<?php

/**
 * The file that defines the plugin woocommerce cart class
 *
 * @link       https://wpconfiguratorbuilder.com
 * @since      1.0.0
 *
 * @package    wcb-configurator-builder
 * @subpackage wcb-configurator-builder/includes/woocommerce
 */

if ( ! defined('ABSPATH') ) {
	die();
}

/**
 * The plugin woocommerce cart class.
 *
 * @since      1.0.0
 * @package    wcb-configurator-builder
 * @subpackage wcb-configurator-builder/includes/woocommerce
 * @author     WPCB <support@wpconfiguratorbuilder.com>
 */

class WPCB_Cart {

	public function __construct() {
		
		add_filter( 'woocommerce_loop_add_to_cart_link', array( $this, 'wpcb_filter_add_to_cart_link' ), 20, 3 );
		add_filter( 'woocommerce_add_to_cart_fragments', array( $this, 'wpcb_add_to_cart_fragments' ) );
		add_filter( 'woocommerce_add_cart_item_data', array( $this, 'wpcb_save_product_data' ), 20, 3 );
		add_filter( 'woocommerce_get_item_data', array( $this, 'wpcb_render_data_on_cart_checkout' ), 20, 2 );
		add_filter( 'woocommerce_cart_item_name', array( $this, 'wpcb_modify_cart_item_name' ), 20, 3 );
		add_filter( 'woocommerce_cart_item_permalink', array( $this, 'wpcb_modify_cart_item_link' ), 20, 3 );
		add_filter( 'woocommerce_cart_item_thumbnail', array( $this, 'wpcb_set_product_thumbnail' ), 20, 3 );
		add_filter( 'woocommerce_store_api_cart_item_images', array( $this, 'wpcb_set_cart_block_images' ), 20, 3 );
		add_filter( 'woocommerce_cart_shipping_packages', array( $this, 'wpcb_set_custom_shipping_dimensions' ), 20 );
		add_filter( 'woocommerce_cart_get_taxes', array( $this, 'wpcb_set_cart_tax_totals' ), 20, 2 );

		add_filter( 'woocommerce_add_cart_item', array( $this, 'wpcb_get_configuration_cart_item' ), 10, 2 );
		add_filter( 'woocommerce_add_to_cart_redirect', array( $this, 'wpcb_add_to_cart_redirect_to_page' ), 10, 2 );
		add_filter( 'woocommerce_cart_redirect_after_error', array( $this, 'wpcb_add_to_cart_redirect_to_page' ), 10, 2 );

		add_filter( 'woocommerce_order_again_cart_item_data', array( $this, 'wpcb_order_again_cart_item_data' ), 20, 3 );

		add_action( 'woocommerce_add_to_cart', array( $this, 'wpcb_add_configuration_to_cart' ), 10, 6 );
		add_action( 'woocommerce_before_calculate_totals', array( $this, 'wpcb_set_price_for_cart_item' ), 99 );
		add_action( 'woocommerce_remove_cart_item', array( $this, 'wpcb_remove_bundle_product_items' ), 10, 2 );
		
		add_filter( 'woocommerce_cart_item_price', array( $this, 'wpcb_cart_item_price_display' ), 10, 3 );
	}

	/**
	 * Redirect back to shortcode page after add to cart
	 *
	 * @since    1.0.0
	 */
	public function wpcb_add_to_cart_redirect_to_page( $redirect_url, $product ) {
		if ( isset( $_REQUEST['wpcb_redirect_uri'] ) ) {
			$redirect_url = esc_url( sanitize_url( wp_unslash( $_REQUEST['wpcb_redirect_uri'] ) ) );
		}
		return $redirect_url;
	}

	/**
	 * Remove loop add to cart links for configurable products.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_filter_add_to_cart_link( $add_to_cart_link, $product, $args = array() ) {
		$wpcb_configuration_id = wpcb_product_has_configurator( $product->get_id() );
		if ( ! $wpcb_configuration_id ) {
			return $add_to_cart_link;
		}

		if ( strpos( $add_to_cart_link, 'wp-block-button' ) ) {
			$html_template = '<div data-wc-interactive class="wp-block-button wc-block-components-product-button align-center"><a href="%s" class="%s">%s</a></div>';
		} else {
			$html_template = '<a href="%s" class="%s">%s</a>';
		}

		$add_to_cart_link = sprintf(
			$html_template,
			get_permalink( $product->get_id() ),
			esc_attr( isset( $args['class'] ) ? $args['class'] : 'button' ),
			esc_html( $product->add_to_cart_text() )
		);

		return $add_to_cart_link;
	}

	/**
	 * Add fragments for notices.
	 *
	 * @since 1.0.0
	 * 
	 * @param array $fragments WooCommerce AJAX fragments
	 * @return array $fragments Modified WooCommerce AJAX fragments
	 */
	public function wpcb_add_to_cart_fragments( $fragments ) {
		$all_notices  = WC()->session->get( 'wc_notices', array() );
		$notice_types = apply_filters( 'wpcb_notice_types', array( 'error', 'success', 'notice' ) );

		ob_start();
		foreach ( $notice_types as $notice_type ) {
			if ( wc_notice_count( $notice_type ) > 0 ) {
				wc_get_template(
					"notices/{$notice_type}.php",
					array(
						'notices' => array_filter( $all_notices[ $notice_type ] ),
					)
				);

				if ( 'error' === $notice_type ) {
					break;
				}
			}
		}
		$fragments['notices_html'] = ob_get_clean();

		wc_clear_notices();

		return $fragments;
	}

	/**
	 * Modify product item name when in cart.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_modify_cart_item_name( $name, $cart_item, $cart_item_key ) {
		if ( isset( $cart_item['wpcb_name'] ) ) {
			if ( str_contains( $name, '</a>' ) ) {
				$name = str_replace( $cart_item['data']->get_name(), esc_attr( $cart_item['wpcb_name'] ), $name );
			} else {
				$name = esc_attr( $cart_item['wpcb_name'] );
			}
		}
		return $name;
	}

	/**
	 * Modify product item link when in cart.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_modify_cart_item_link( $permalink, $cart_item, $cart_item_key ) {
		if ( isset( $cart_item['wpcb_filename'] ) && $cart_item['wpcb_filename'] ) {
			if ( isset( $cart_item['wpcb_url'] ) && $cart_item['wpcb_url'] ) {
				$permalink = esc_url( $cart_item['wpcb_url'] );
			} else {
				$product_id = isset( $cart_item['variation_id'] ) && $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'];
				$permalink = get_permalink( $product_id );
			}

			$permalink = add_query_arg( array(
				'wpcb_configuration' => $cart_item['wpcb_filename'],
				'cart_key' => $cart_item_key,
				'cart_qty' => $cart_item['quantity'],
			), $permalink );
		}

		return $permalink;
	}

	/**
	 * Save configurator data to cart item.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_save_product_data( $cart_item_data, $product_id, $variation_id ) {

		// Addon product. Don't include data.
		if ( isset( $cart_item_data['wpcb_addon_product'] ) ) {
			return $cart_item_data;
		}

		// Edits cart item. Remove original and replace with new contents.
		$cart_item_key = isset( $_POST['cart_item_key'] ) ? sanitize_text_field( wp_unslash( $_POST['cart_item_key'] ) ) : '';
		if ( $cart_item_key ) {
			$in_cart = WC()->cart->find_product_in_cart( $cart_item_key );

			if ( $in_cart ) {
				WC()->cart->remove_cart_item( $cart_item_key );
			}
		}

		// Get filtered POST data.
		$configuration_json = array();
		$config_name = '';

		if ( isset( $_POST['wpcb_configuration_data'] ) ) {
			$json = base64_decode( wp_unslash( $_POST['wpcb_configuration_data'] ) );
			$configuration_json = json_decode( $json, true );

			if ( function_exists( 'wpcb_save_configuration_file' ) ) {
				$config_name = wpcb_save_configuration_file( $configuration_json );
			}
		} elseif ( isset( $_POST['wpcb_configuration_file'] ) && function_exists( 'wpcb_get_configuration_temp_dir_path' ) ) {
			$config_name = sanitize_text_field( wp_unslash( $_POST['wpcb_configuration_file'] ) );
			$save_path  = wpcb_get_configuration_temp_dir_path();

			if ( file_exists( trailingslashit($save_path) . $config_name . '.json')) {
				$json = file_get_contents(trailingslashit($save_path) . $config_name . '.json');
				$configuration_json = json_decode( $json, true );
			}
		}

		// Set config file
		if ( $config_name ) {
			$cart_item_data['wpcb_filename'] = $config_name;
		}

		// Save page link.
		if ( isset( $configuration_json['url'] ) ) {
			$cart_item_data['wpcb_url'] = $configuration_json['url'];
			$cart_item_data['wpcb_name'] = $configuration_json['name'];
		}

		// Set custom image
		if ( isset( $configuration_json['renders'] ) && is_array( $configuration_json['renders'] ) && count( $configuration_json['renders'] ) > 0 ) {
			$imagedata = $configuration_json['renders'][0];

			if ( wpcb_get_option( 'wpcb_checkout_show_image' ) || wpcb_get_option( 'wpcb_checkout_order_show_image' ) || wpcb_get_option( 'wpcb_checkout_email_show_image' ) ) {
				if ( $config_name ) {
					$image_name = $config_name;
				} else {
					$image_name = wpcb_generate_configuration_name();
				}
				$imagedata = wpcb_store_configuration_image( $image_name, $imagedata );
			}

			$cart_item_data['wpcb_product_image'] = $imagedata;
		}

		// Set options array.
		$wpcb_item_skus = array();
		$product_selections = isset( $configuration_json['selection'] ) ? filter_var_array( $configuration_json['selection'] ) : array();
		$configurator_id = isset( $configuration_json['configurator_id'] ) ? sanitize_key( $configuration_json['configurator_id'] ) : 0;
		if ( is_array( $product_selections ) && count( $product_selections ) > 0 ) {
			$cart_item_data['wpcb_configurator_id'] = $configurator_id;
			$cart_item_data['wpcb_product_selections'] = $product_selections;

			$product_item_keys = array();
			$product_item_total = 0;
			$exclude_linked_ids = wpcb_get_option('wpcb_checkout_exclude_linked_products') ?: false;

			$length_key = '';
			$width_key = '';
			$height_key = '';
			if ( 'yes' == get_post_meta( $configurator_id, '_change_dimensions', true ) ) {
				$length_key = get_post_meta( $configurator_id, '_configurator_length', true ) ?: '';
				$width_key = get_post_meta( $configurator_id, '_configurator_width', true ) ?: '';
				$height_key = get_post_meta( $configurator_id, '_configurator_height', true ) ?: '';
			}

			/**
			 * Clean up linked products items selection
			 */

			foreach ( $product_selections as $selection_key => $selection ) {
				if ( isset( $selection['values'] ) && is_array( $selection['values'] ) && count( $selection['values'] ) > 0 ) {
					foreach ( $selection['values'] as $item ) {
						if ( isset( $item['values'] ) && is_array( $item['values'] ) && count( $item['values'] ) > 0 ) {
							foreach ( $item['values'] as $sub_item ) {
								if ( $exclude_linked_ids && isset( $sub_item['product_id'] ) && is_numeric( $sub_item['product_id'] ) ) {
									$product_item_keys[] = $selection_key;
								}

								if ( isset( $sub_item['sku'] ) && '' !== $sub_item['sku'] ) {
									$wpcb_item_skus[ $item['id'] ] = $sub_item['sku'];
								}
							}
						} else {
							if ( $exclude_linked_ids && isset( $item['product_id'] ) && is_numeric( $item['product_id'] ) ) {
								$product_item_keys[] = $selection_key;
							}

							if ( isset( $item['sku'] ) && '' !== $item['sku'] ) {
								$wpcb_item_skus[ $selection['id'] ] = $item['sku'];
							} 
							else if ( isset( $item['input_type'] ) && '' !== $item['value'] ) {
								$wpcb_item_skus[ $selection['id'] ] = $item['value'];
							}
						}
					}
				}

				// Collect custom dimensions
				if ( '' != $length_key && $length_key == $selection['id'] ) {
					$cart_item_data['wpcb_product_length'] = $selection['value'];
				}
				if ( '' != $width_key && $width_key == $selection['id'] ) {
					$cart_item_data['wpcb_product_width'] = $selection['value'];
				}
				if ( '' != $height_key && $height_key == $selection['id'] ) {
					$cart_item_data['wpcb_product_height'] = $selection['value'];
				}
			}

			foreach ( $product_item_keys as $product_selection_key ){
				unset( $product_selections[ $product_selection_key ] );
			}

			$cart_item_data['wpcb_product_options'] = $product_selections;
		}

		// Set custom SKU format
		$sku_format = get_post_meta( $configurator_id, '_configuration_sku_format', true );
		if ( '' !== $sku_format && count( $wpcb_item_skus ) > 0 ) {
			foreach ( $wpcb_item_skus as $id => $sku ) {
				$sku_format = str_replace( '{' . $id . '}', $sku, $sku_format );
			}
			$cart_item_data['wpcb_product_sku'] = $sku_format;
		}

		// Set custom totals
		if ( isset( $configuration_json['totals']['total_price'] ) ) {
			// Recalculate pricings and set final price
			$wpcb_product_id = $variation_id ? $variation_id : $product_id;
			$configurator_totals = wpcb_get_configurator_cart_totals( $configurator_id, $wpcb_product_id, $product_selections, $configuration_json['totals'] );
			$cart_item_data['wpcb_product_totals'] = $configurator_totals;

			// Set correct price for cart to prevent duplicate taxes.
			$include_tax = get_option( 'woocommerce_prices_include_tax' );
			$tax_display = get_option( 'woocommerce_tax_display_shop' );
			if ( ( 'no' === $include_tax && 'incl' === $tax_display ) || ( 'yes' === $include_tax && 'excl' === $tax_display ) ) { 
				$cart_item_data['wpcb_product_price'] = $configurator_totals['subtotal_price'];
				$cart_item_data['wpcb_product_sale'] = $configurator_totals['subtotal_sale'];
			} else {
				$cart_item_data['wpcb_product_price'] = $configurator_totals['total_price'];
				$cart_item_data['wpcb_product_sale'] = $configurator_totals['sale_price'];
			}

			// Set tax
			if ( isset( $configurator_totals['total_tax'] ) && $configurator_totals['total_tax'] ) {
				$cart_item_data['wpcb_product_tax'] = $configurator_totals['total_tax'];
			}

			// Set weight
			if ( isset( $configurator_totals['total_weight'] ) && $configurator_totals['total_weight'] ) {
				$cart_item_data['wpcb_product_weight'] = $configurator_totals['total_weight'];
			}
		}

		return $cart_item_data;
	}

	/**
	 * Modify configurator taxes.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_set_cart_tax_totals( $taxes, $cart ) {
		// $custom_tax_rate_id = 1; // get with WC_Tax if needed
		// $custom_total = 0;
		// foreach ( $cart->get_cart() as $cart_item ) {
		// 	if ( isset( $cart_item['wpcb_product_totals'] ) ) {
		// 		$custom_total += $cart_item['wpcb_product_totals']['total_tax'] * $cart_item['quantity'];
		// 	}
		// }
		// if ( $custom_total > 0 ) {
		// 	$taxes[ $custom_tax_rate_id ] = $custom_total;
		// }
		return $taxes;
	}

	/**
	 * Modify configurator shipping meta.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_set_custom_shipping_dimensions($packages) {
		foreach ($packages as &$package) {
			foreach ($package['contents'] as &$item) {
				if (isset($item['wpcb_product_length'])) {
					if (method_exists( $item['data'], 'set_length') ) {
						$item['data']->set_length( $item['wpcb_product_length'] );
					}
				}
				if (isset($item['wpcb_product_width'])) {
					if (method_exists( $item['data'], 'set_width') ) {
						$item['data']->set_width( $item['wpcb_product_width'] );
					}
				}
				if (isset($item['wpcb_product_height'])) {
					if (method_exists( $item['data'], 'set_height') ) {
						$item['data']->set_height( $item['wpcb_product_height'] );
					}
				}
				if (isset($item['wpcb_product_weight'])) {
					if (method_exists( $item['data'], 'set_weight') ) {
						$item['data']->set_length( $item['wpcb_product_weight'] );
					}
				}
			}
		}
		return $packages;
	}

	/**
	 * Modify configurator cart item meta.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_get_configuration_cart_item( $cart_item_data, $cart_item_key ) {
		if ( ! isset( $cart_item_data['wpcb_product_selections'] ) ) {
			return $cart_item_data;
		}

		$bundle_product_lines = wpcb_get_option('wpcb_checkout_bundle_product_lines') ?: false;
		if ( $bundle_product_lines ) {
			$bundle_hash = md5( $cart_item_key );
			$cart_item_data['wpcb_bundle_key'] = $bundle_hash;
		}

		return $cart_item_data;
	}

	/**
	 * Save configurator items to cart.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_add_configuration_to_cart( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
		if ( ! isset( $cart_item_data['wpcb_product_selections'] ) ) {
			return;
		}

		$exclude_linked_ids   = wpcb_get_option('wpcb_checkout_exclude_linked_products') ?: false;
		$exclude_base_product = wpcb_get_option('wpcb_checkout_exclude_base_product') ?: false;
		$include_product_qty  = wpcb_get_option('wpcb_checkout_include_product_qty') ?: false;
		$bundle_product_lines = wpcb_get_option('wpcb_checkout_bundle_product_lines') ?: false;
		if ( $bundle_product_lines ) {
			$bundle_hash = md5( $cart_item_key );
			$cart_item_data['wpcb_bundle_key'] = $bundle_hash;
		}

		if ( $exclude_base_product ) {
			WC()->cart->remove_cart_item( $cart_item_key );
		}

		global $wpcb_price_rates;
		if ( ! $wpcb_price_rates ) {
			wpcb_define_price_rates();
		}

		$product_selections = $cart_item_data['wpcb_product_selections'];
		if ( $exclude_linked_ids && is_array( $product_selections ) ) {
			if ( ! $include_product_qty ) {
				$quantity = 1; // Multiply by 1
			}

			foreach ( $product_selections as $selection ) {
				if ( isset( $selection['values'] ) && is_array( $selection['values'] ) && count( $selection['values'] ) > 0 ) {
					foreach ( $selection['values'] as $item ) {
						if ( isset( $item['product_id'] ) && is_numeric( $item['product_id'] ) ) {
							$option_product_id    = $item['product_id'];
							$option_variation_id  = isset( $item['variation_id'] ) ? $item['variation_id'] : 0;
							$option_product_qty   = $quantity;
							$option_product_price = $item['price'];
							$option_product_sale  = $item['sale'] ? $item['sale'] : $item['price'];

							if ( 'no' === $wpcb_price_rates['include_tax'] && 'incl' === $wpcb_price_rates['tax_display'] ){ 
								$option_product_price = wpcb_get_price_excluding_tax( $option_product_price, $item['tax_percent'], true );
								$option_product_sale = wpcb_get_price_excluding_tax( $option_product_sale, $item['tax_percent'], true );
							} else if ( 'yes' === $wpcb_price_rates['include_tax'] && 'excl' === $wpcb_price_rates['tax_display'] ) {
								$option_product_price = wpcb_get_price_including_tax( $option_product_price, $item['tax_percent'], true );
								$option_product_sale = wpcb_get_price_including_tax( $option_product_sale, $item['tax_percent'], true );
							} else {
								$option_product_price = floatval( $option_product_price );
								$option_product_sale = floatval( $option_product_sale );
							}

							if ( intval( $item['value'] ) > 1 ) {
								$option_product_qty   = $item['value'] * $quantity;
								$option_product_price = $option_product_price / $option_product_qty;
								$option_product_sale  = $option_product_sale / $option_product_qty;
							}

							$option_cart_data = array(
								'wpcb_addon_product' => true,
								'wpcb_product_price' => $option_product_price,
							);
							if ( $option_product_sale < $option_product_price ) {
								$option_cart_data['wpcb_product_sale'] = $option_product_sale;
							}

							if ( $bundle_product_lines ) {
								$option_cart_data['wpcb_bundle_key'] = $bundle_hash;
							}
		
							remove_action( 'woocommerce_add_to_cart', array( $this, 'wpcb_add_configuration_to_cart' ), 10, 6 );

							WC()->cart->add_to_cart( $option_product_id, $option_product_qty, $option_variation_id, array(), $option_cart_data );

							add_action( 'woocommerce_add_to_cart', array( $this, 'wpcb_add_configuration_to_cart' ), 10, 6 );
						}
					}
				}
			}
		}
	}

	/**
	 * Add custom items to cart meta so it is visible in the cart.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_render_data_on_cart_checkout( $cart_data, $cart_item = null ) {
		$custom_items = array();

		if ( ! empty( $cart_data ) ) {
			$custom_items = $cart_data;
		}

		$forbidden_labels = array();
		if ( wpcb_get_option( 'wpcb_checkout_forbidden_option_labels' ) ) {
			$forbidden_labels = array_map( 'trim', explode( ',', wpcb_get_option( 'wpcb_checkout_forbidden_option_labels' ) ) );
		}

		$show_cart_skus   = wpcb_get_option('wpcb_cart_show_option_skus') ?: false;
		$show_cart_prices = wpcb_get_option('wpcb_cart_show_option_prices') ?: false;
		if ( isset( $cart_item['wpcb_product_options'] ) && is_array( $cart_item['wpcb_product_options'] ) ) {
			foreach ( $cart_item['wpcb_product_options'] as $meta_option ) :
				if ( ! isset( $meta_option['label'] ) || '' === $meta_option['label'] ) {
					continue;
				}

				if ( in_array( $meta_option['label'], $forbidden_labels ) ) {
					continue;
				}

				if ( ! isset( $meta_option['values'] ) || ! is_array( $meta_option['values'] ) ) {
					continue;
				}

				if ( isset( $meta_option['format'] ) && '' !== $meta_option['format'] ) {
					$format_value = $meta_option['value'];

					if ( $show_cart_prices && $meta_option['cost'] > 0 ) {
						if ( isset( $meta_option['sale_cost'] ) ) {
							$format_value .= ' (' . wpcb_get_price_html( $meta_option['sale_cost'] ) . ')';
						} else {
							$format_value .= ' (' . wpcb_get_price_html( $meta_option['cost'] ) . ')';
						}
					}

					$custom_items[] = array(
						'name'  => $meta_option['label'],
						'value' => $format_value,
					);
				}
				else if ( count( $meta_option['values'] ) > 1 ) {
					$subvalues   = '';
					$value_count = count( $meta_option['values'] );
					$option_cost = 0;

					foreach ( $meta_option['values'] as $option_index => $option_value ) {
						if ( isset( $option_value['values'] ) && count( $option_value['values'] ) > 0 ) {
							if ( count( $option_value['values'] ) > 1 ) {
								$subvalues .= '<br><span class="subitem">' . $option_value['label'] . ': ';
								$subval_count = count( $option_value['values'] );

								foreach ( $option_value['values'] as $subkey => $subval ) {
									if ( isset( $subval['product_id'] ) && is_numeric( $subval['product_id'] ) ) {
										$subvalues .= $subval['label'] . ': ' . $subval['value'];
									} 
									else if ( isset( $subval['input_type'] ) && 'file' === $subval['input_type'] ) {
										$subvalues .= $subval['label'];
									}
									else {
										$subvalues .= $subval['value'];
									}

									if ( $subkey + 1 < $subval_count ) {
										$subvalues .= ', ';
									}
								}

							} else {

								if ( isset( $option_value['values'][0]['product_id'] ) && is_numeric( $option_value['values'][0]['product_id'] ) ) {
									$subvalues .= '<br><span class="subitem">' . $option_value['values'][0]['label'] . ': ' . $option_value['values'][0]['value'] . '</span>';
								} 
								else if ( 'file' === $option_value['values'][0]['input_type'] ) {
									$subvalues .= '<br><span class="subitem">' . $option_value['label'] . ': ' . $option_value['values'][0]['label'] . '</span>';
								} 
								else {
									$subvalues .= '<br><span class="subitem">' . $option_value['label'] . ': ' . $option_value['values'][0]['value'] . '</span>';
								}

								if ( $option_value['cost'] > 0 ) {
									if ( isset( $option_value['sale_cost'] ) ) {
										$option_cost += $option_value['sale_cost'];
									} else {
										$option_cost += $option_value['cost'];
									}
								}

								if ( $option_index + 1 < $value_count ) {
									$subvalues .= ', ';
								}
							}

						} else {
							if ( isset( $option_value['product_id'] ) && is_numeric( $option_value['product_id'] ) ) {
								$subvalues .= $option_value['label'] . ': ' . $option_value['value'];
							} 
							else if ( 'file' === $option_value['input_type'] ) {
								$subvalues .= $option_value['label'];
							}
							else {
								$subvalues .= $option_value['value'];
							}

							if ( $option_index + 1 < $value_count ) {
								$subvalues .= ', ';
							}
						}
					}

					if ( $meta_option['cost'] > 0 ) {
						if ( isset( $meta_option['sale_cost'] ) ) {
							$option_cost = $meta_option['sale_cost'];
						} else {
							$option_cost = $meta_option['cost'];
						}
					}

					if ( $show_cart_prices && $option_cost > 0 ) {
						$subvalues .= ' (' . wpcb_get_price_html( $option_cost ) . ')';
					}

					$custom_items[] = array(
						'name'  => $meta_option['label'],
						'value' => $subvalues,
					);
					
				} else if ( count( $meta_option['values'] ) > 0 ) {
					
					$select_val = '';
					foreach ( $meta_option['values'] as $meta_index => $meta_value ) {
						if ( isset( $meta_value['product_id'] ) && is_numeric( $meta_value['product_id'] ) ) {
							$option_val = $meta_value['label'] . ': ' . $meta_value['value'];
						} 
						else if ( isset( $meta_value['input_type'] ) && 'file' === $meta_value['input_type'] ) {
							$option_val = $meta_value['label'];
						}
						else {
							$option_val = $meta_value['value'];
						}

						if ( isset( $meta_value['sku'] ) && '' !== $meta_value['sku'] && $show_cart_skus ) {
							$option_val .= sprintf( ' (%s)', $meta_value['sku'] );
						}

						$select_val .= $option_val;
						if ( sizeof( $meta_option['values'] ) > $meta_index + 1) {
							$select_val .= ', ';
						}
					}

					if ( $show_cart_prices && $meta_option['cost'] > 0 ) {
						if ( isset( $meta_option['sale_cost'] ) ) {
							$select_val .= ' (' . wpcb_get_price_html( $meta_option['sale_cost'] ) . ')';
						} else {
							$select_val .= ' (' . wpcb_get_price_html( $meta_option['cost'] ) . ')';
						}
					}

					$custom_items[] = array(
						'name'  => $meta_option['label'],
						'value' => $select_val,
					);
				}
			endforeach;
		}

		return $custom_items;
	}

	/**
	 * Override base product price with calculated configurator price.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_set_price_for_cart_item( $cart_object ) {
		if ( is_admin() && !defined('DOING_AJAX')) {
			return;
		}

		if ( ! WC()->session->__isset( 'reload_checkout' ) ) {
			$include_tax = get_option( 'woocommerce_prices_include_tax' );
			$tax_display = get_option( 'woocommerce_tax_display_shop' );
			$wpcb_dynamic_pricing = wpcb_get_option( 'wpcb_cart_enable_dynamic_pricing' );

			foreach ( $cart_object->cart_contents as $key => $value ) {
				if ( isset( $value['wpcb_product_totals'] ) && isset( $value['wpcb_product_options'] ) ) {
					$sale = false;

					if ( $wpcb_dynamic_pricing ) {
						$product_id = $value['variation_id'] ? $value['variation_id'] : $value['product_id'];

						$configurator_totals = wpcb_get_configurator_cart_totals( 
							$value['wpcb_configurator_id'],
							$product_id,
							$value['wpcb_product_options'],
							$value['wpcb_product_totals'],
							$value['quantity']
						);
					} else {
						$configurator_totals = $value['wpcb_product_totals'];
					}

					// Set correct price for cart to prevent duplicate taxes.
					if ( ( 'no' === $include_tax && 'incl' === $tax_display ) || ( 'yes' === $include_tax && 'excl' === $tax_display ) ) { 
						$price = $configurator_totals['subtotal_price'];
						$sale = $configurator_totals['subtotal_sale'];
					} else {
						$price = $configurator_totals['total_price'];
						$sale = $configurator_totals['sale_price'];
					}

					if ( $sale && $sale < $price ) {
						$value['data']->set_price( $sale );
						$value['data']->set_regular_price( $price );
					} else {
						$value['data']->set_price( $price );
					}

					if ( isset( $value['wpcb_product_weight'] ) && '' !== $value['wpcb_product_weight'] ) {
						$value['data']->set_weight( $value['wpcb_product_weight'] );
					}
					if ( isset( $value['wpcb_product_length'] ) && '' !== $value['wpcb_product_length'] ) {
						$value['data']->set_length( $value['wpcb_product_length'] );
					}
					if ( isset( $value['wpcb_product_width'] ) && '' !== $value['wpcb_product_width'] ) {
						$value['data']->set_width( $value['wpcb_product_width'] );
					}
					if ( isset( $value['wpcb_product_height'] ) && '' !== $value['wpcb_product_height'] ) {
						$value['data']->set_height( $value['wpcb_product_height'] );
					}

					if ( isset( $value['wpcb_product_sku'] ) && '' !== $value['wpcb_product_sku'] ) {
						// Clone to prevent other references from being modified.
						$product = $value['data'];
						$new_product = clone $product;
						$new_product->set_sku( $value['wpcb_product_sku'] );
						$value['data'] = $new_product;
					}
				}

				if ( isset( $value['wpcb_product_price'] ) && isset( $value['wpcb_addon_product'] ) ) {
					$price = $value['wpcb_product_price'];
					$sale = isset( $value['wpcb_product_sale'] ) ? $value['wpcb_product_sale'] : false;

					if ( $sale && $sale < $price ) {
						$value['data']->set_price( $sale );
						$value['data']->set_regular_price( $price );
					} else {
						$value['data']->set_price( $price );
					}
				}
			}
		}
	}

	/**
	 * Show correct price when updating via AJAX
	 *
	 * @since    1.0.0
	 */
	public function wpcb_cart_item_price_display( $price_html, $cart_item, $cart_item_key ) {
		if ( isset( $cart_item['wpcb_product_price'] ) && isset( $cart_item['data'] ) ) {
			$tax_display = get_option( 'woocommerce_tax_display_shop' );
			$sale = false;
			$configurator_totals = false;

			if ( isset( $cart_item['wpcb_product_totals'] ) ) {
				$configurator_totals = $cart_item['wpcb_product_totals'];

				$price = $configurator_totals['total_price'];
				$sale = $configurator_totals['sale_price'];
			} else {
				$price = $cart_item['wpcb_product_price'];
				$sale = isset( $cart_item['wpcb_product_sale'] ) ? $cart_item['wpcb_product_sale'] : false;
			}

			if ( $sale && $sale < $price ) {
				if ( 'incl' === $tax_display ) {
					$price_html = '<del>' . wc_price( wc_get_price_including_tax( $cart_item['data'], array( 'price' => $price ) ) ) . '</del> <ins>' . wc_price( wc_get_price_including_tax( $cart_item['data'], array( 'price' => $sale ) ) ) . '</ins>';
				} else {
					$price_html = '<del>' . wc_price( wc_get_price_excluding_tax( $cart_item['data'], array( 'price' => $price ) ) ) . '</del> <ins>' . wc_price( wc_get_price_excluding_tax( $cart_item['data'], array( 'price' => $sale ) ) ) . '</ins>';
				}
			} else {
				if ( 'incl' === $tax_display ) {
					$price_html = wc_price( wc_get_price_including_tax( $cart_item['data'], array( 'price' => $price ) ) );
				} else {
					$price_html = wc_price( wc_get_price_excluding_tax( $cart_item['data'], array( 'price' => $price ) ) );
				}
			}
		}

		// If not set, let WooCommerce handle default
		return $price_html;
	}

	/**
	 * Include WPCB cart item meta when ordering again
	 *
	 * @since    1.0.0
	 */
	public function wpcb_order_again_cart_item_data($cart_item_meta, $product, $order) {
		if ( $product->get_meta( '_wpcb_cart_meta' ) ) {
			$meta = $product->get_meta( '_wpcb_cart_meta' );

			foreach ( $meta as $key => $value ) {
				$cart_item_meta[$key] = $value;
			}
		}

		return $cart_item_meta;
	}

	/**
	 * Override base product thumbnail with generated configurator image.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_set_product_thumbnail( $product_image, $cart_item, $cart_item_key ) {
		if ( is_admin() ) {
			// Elementor fix.
			return $product_image;
		}

		if ( isset( $cart_item['wpcb_product_image'] ) && '' !== $cart_item['wpcb_product_image'] ) {
			$product_image = '<img class="lazy" src="' . esc_attr( $cart_item['wpcb_product_image'] ) . '" alt="' . esc_attr( get_the_title( $cart_item['product_id'] ) ) . '" />';
		}

		return $product_image;
	}

	/**
	 * Override base product thumbnail with generated configurator image.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_set_cart_block_images( $product_images, $cart_item, $cart_item_key ) {
		if ( is_admin() ) {
			// Elementor fix.
			return $product_images;
		}

		if ( isset( $cart_item['wpcb_product_image'] ) && '' !== $cart_item['wpcb_product_image'] ) {
			if ( isset( $cart_item['wpcb_filename'] ) && '' !== $cart_item['wpcb_filename'] ) {
				$image_name = $cart_item['wpcb_filename'];
			} else {
				$image_name = wpcb_generate_configuration_name();
			}
			$image_url = wpcb_store_configuration_image( $image_name, $cart_item['wpcb_product_image'], true );
			$image_name = isset( $cart_item['wpcb_name'] ) ? $cart_item['wpcb_name'] : $cart_item['data']->get_title();

			$product_images = [
       			(object)[
					'id' => 0,
					'src' => esc_url( $image_url ),
					'thumbnail' => esc_url( $image_url ),
					'name' => esc_attr( $image_name ),
					'alt' => esc_attr( $image_name ),
				]
			];
		}

		return $product_images;
	}

	/**
	 * Override base product thumbnail with generated configurator image.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_set_block_thumbnail( $product_image, $cart_item ) {
		if ( is_admin() ) {
			// Elementor fix.
			return $product_image;
		}

		if ( isset( $cart_item['wpcb_product_image'] ) && '' !== $cart_item['wpcb_product_image'] ) {
			$product_image = '<img class="lazy" src="' . esc_attr( $cart_item['wpcb_product_image'] ) . '" alt="' . esc_attr( get_the_title( $cart_item['product_id'] ) ) . '" />';
		}

		return $product_image;
	}

	/**
	 * Delete other linked products on bundle product remove.
	 *
	 * @since    1.0.0
	 */
	public function wpcb_remove_bundle_product_items( $cart_item_key, $cart ) {
		if ( ! isset( $cart->cart_contents[$cart_item_key]['wpcb_bundle_key'] ) ) {
			return;
		}

		remove_action( 'woocommerce_remove_cart_item', array( $this, 'wpcb_remove_bundle_product_items' ), 10, 2 );
		
		// Get the key of the bundle product removed
		$removed_bundle_key = $cart->cart_contents[$cart_item_key]['wpcb_bundle_key'];

		// Loop through the cart items
		foreach ( $cart->get_cart() as $item_key => $item ) {
			if ( ! array_key_exists( 'wpcb_bundle_key', $item ) ) {
				continue;
			}
			if ( $item_key === $cart_item_key ) {
				continue;
			}
			if ( $removed_bundle_key !== $item['wpcb_bundle_key'] ) {
				continue;
			}
			// Remove the product from the cart
			$cart->remove_cart_item( $item_key );
		}

		add_action( 'woocommerce_remove_cart_item', array( $this, 'wpcb_remove_bundle_product_items' ), 10, 2 );
	}
}
