<?php

namespace Discountify\Core\Frontend;

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

use Discountify\Core\Frontend\Calculator;
use Discountify\Utils\Singleton;
use Discountify\Core\Frontend\Coupon as DiscountifyCoupon;
/**
 *  Apply hooks
 *
 * @since 1.0.0
 */
class Frontend extends Calculator {

	use Singleton;

	private $discount_data      = array();
	private $cached_coupon_data = null;
	private $last_cart_hash     = null;
	private static $bogo_processing = false;

	/**
	 * Initialize all modules.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function init() {
		add_filter( 'woocommerce_cart_item_price', array( $this, 'change_product_price_display' ), 10, 3 );
		add_action( 'woocommerce_before_calculate_totals', array( $this, 'add_coupon_automatically' ), 99 );

		// Add cart item data filter with highest priority to ensure it runs after all other plugins
		add_filter( 'woocommerce_get_item_data', array( $this, 'display_cart_item_meta_data' ), 999, 2 );

		// Add order item meta when item is added to order
		add_action( 'woocommerce_checkout_create_order_line_item', array( $this, 'add_order_item_meta' ), 10, 3 );

		// Display discount offer on order/thank-you page and admin
		add_filter( 'woocommerce_order_item_get_formatted_meta_data', array( $this, 'format_order_item_discount_meta' ), 10, 1 );
		add_filter( 'woocommerce_order_item_display_meta_key', array( $this, 'format_order_item_meta_key' ), 10, 3 );

		// Add inline CSS for discount display in mini-cart
		add_action( 'wp_head', array( $this, 'add_discount_display_styles' ) );

		add_action( 'woocommerce_cart_calculate_fees', array( $this, 'add_discount_on_cart_total' ) );
		add_action( 'woocommerce_cart_calculate_fees', array( $this, 'apply_buy_x_get_y_fee' ), 20 );
		add_filter( 'woocommerce_package_rates', array( $this, 'shipping_discount' ), 100, 2 );
		add_filter( 'woocommerce_get_shop_coupon_data', array( $this, 'validate_discount_coupon' ), 10, 3 );
		add_filter( 'woocommerce_cart_totals_coupon_html', array( $this, 'add_coupon_html' ), 10, 3 );
		add_action( 'woocommerce_before_shop_loop_item_title', array( $this, 'show_discount_badge_on_thumbnail' ), 11 );
		add_action( 'woocommerce_product_thumbnails', array( $this, 'show_discount_badge_on_single_product' ), 5 );
		add_action( 'wp_ajax_discountify_get_variation_discount', array( $this, 'ajax_get_variation_discount' ) );
		add_action( 'wp_ajax_nopriv_discountify_get_variation_discount', array( $this, 'ajax_get_variation_discount' ) );
		add_action( 'wp_footer', array( $this, 'show_cart_adjustment_message_block_cart' ) );

		// BOGO: Auto-add/remove/update free products in cart.
		add_action( 'woocommerce_add_to_cart', array( $this, 'bogo_auto_add_free_product' ), 20, 6 );
		add_action( 'woocommerce_cart_item_removed', array( $this, 'bogo_handle_removed_product' ), 10, 2 );
		add_action( 'woocommerce_after_cart_item_quantity_update', array( $this, 'bogo_handle_quantity_update' ), 20, 4 );
		add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'bogo_validate_free_products' ), 20 );

		// BOGO: Show FREE in Total column on checkout, thank-you page, and order details.
		add_filter( 'woocommerce_order_item_name', array( $this, 'bogo_order_item_name' ), 10, 2 );
		add_filter( 'woocommerce_order_formatted_line_subtotal', array( $this, 'bogo_order_line_subtotal' ), 10, 3 );
		// Hide _discountify_bogo_free meta from admin order display.
		add_filter( 'woocommerce_hidden_order_itemmeta', array( $this, 'bogo_hide_order_itemmeta' ) );
		// Admin order: show FREE in total column for BOGO free items.
		add_action( 'woocommerce_admin_order_item_headers', array( $this, 'bogo_admin_order_styles' ) );

		// Extend WC Store API so block cart shows BOGO free item data.
		add_action( 'woocommerce_store_api_checkout_update_order_from_request', array( $this, 'bogo_store_api_order_meta' ), 10, 2 );
		// Register Store API item data for WC blocks cart.
		if ( function_exists( 'woocommerce_store_api_register_endpoint_data' ) &&
			class_exists( '\Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema' ) ) {
			woocommerce_store_api_register_endpoint_data(
				array(
					'endpoint'        => \Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema::IDENTIFIER,
					'namespace'       => 'discountify_bogo',
					'data_callback'   => array( $this, 'bogo_store_api_cart_item_data' ),
					'schema_callback' => array( $this, 'bogo_store_api_cart_item_schema' ),
				)
			);
		}
	}


	/**
	 * Shipping discount
	 *
	 * @param [type] $rates
	 */
	public function shipping_discount( $rates, $package ) {
		if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
			return $rates;
		}

		// Check for Free Shipping discount rules first
		$free_shipping_applied = $this->apply_free_shipping_rules( $rates );
		if ( $free_shipping_applied ) {
			return $free_shipping_applied;
		}

		// Fallback to settings-based shipping discount
		extract( \Discountify\Utils\Helper::get_settings() );
		$is_free_ship = ! empty( $shipping_discount ) && $shipping_discount === 'yes' ? true : false;

		if ( ! $is_free_ship ) {
			return $rates;
		}

		$total = $shipping_discount_in === 'cart_total' ? WC()->cart->get_subtotal() : WC()->cart->get_cart_contents_count();

		$discount = $this->cart_condition_check( $shipping_cart, $total );
		if ( ! empty( $discount ) ) {
			foreach ( $rates as $rate_key => $rate ) {
				if ( 'free_shipping' !== $rate->method_id ) {
					$rates[ $rate_key ]->cost = (float) $discount;
					break;
				}
			}
		}

		return $rates;
	}

	/**
	 * Apply Free Shipping discount rules
	 *
	 * @param array $rates Shipping rates
	 * @return array|false Modified rates or false if no rule applies
	 */
	public function apply_free_shipping_rules( $rates ) {
		// Get all enabled free_shipping rules
		$meta_query = array(
			array(
				'key'   => 'rules_type',
				'value' => 'free_shipping',
			),
			array(
				'key'   => 'enable_rules',
				'value' => 'yes',
			),
		);

		$free_shipping_rules = \Discountify\Utils\Helper::get_all_rules( -1, $meta_query );

		if ( empty( $free_shipping_rules ) ) {
			return false;
		}

		$cart = WC()->cart;
		if ( ! $cart || $cart->is_empty() ) {
			return false;
		}

		foreach ( $free_shipping_rules as $rule ) {
			// Check if rule is valid (date range)
			if ( ! $this->is_rule_valid( $rule ) ) {
				continue;
			}

			// Check user role/customer restrictions
			if ( ! $this->check_user_restrictions( $rule ) ) {
				continue;
			}

			$based_on = ! empty( $rule['free_shipping_based_on'] ) ? $rule['free_shipping_based_on'] : 'product';

			$qualifies = false;

			switch ( $based_on ) {
				case 'product':
					$qualifies = $this->check_free_shipping_by_product( $rule, $cart );
					break;
				case 'category':
					$qualifies = $this->check_free_shipping_by_category( $rule, $cart );
					break;
				case 'cart_amount':
					$qualifies = $this->check_free_shipping_by_cart_amount( $rule, $cart );
					break;
			}

			if ( $qualifies ) {
				// Apply free shipping - set all shipping costs to 0
				foreach ( $rates as $rate_key => $rate ) {
					if ( 'free_shipping' !== $rate->method_id ) {
						$rates[ $rate_key ]->cost  = 0;
						$rates[ $rate_key ]->label = esc_html__( 'Free Shipping', 'discountify' );
					}
				}
				return $rates;
			}
		}

		return false;
	}

	/**
	 * Check if rule is valid based on date range
	 *
	 * @param array $rule
	 * @return bool
	 */
	private function is_rule_valid( $rule ) {
		if ( empty( $rule['discount_valid'] ) ) {
			return true; // No date restriction
		}

		$date_range = explode( ' - ', $rule['discount_valid'] );
		if ( count( $date_range ) !== 2 ) {
			return true;
		}

		$start_date = strtotime( trim( $date_range[0] ) );
		$end_date   = strtotime( trim( $date_range[1] ) );
		$today      = strtotime( wp_date( 'Y-m-d' ) );

		return ( $today >= $start_date && $today <= $end_date );
	}

	/**
	 * Check user role/customer restrictions
	 *
	 * @param array $rule
	 * @return bool
	 */
	private function check_user_restrictions( $rule ) {
		if ( empty( $rule['enable_user_discount'] ) || $rule['enable_user_discount'] !== 'yes' ) {
			return true; // No user restriction
		}

		$current_user = wp_get_current_user();
		$condition    = ! empty( $rule['user_discount_condition'] ) ? $rule['user_discount_condition'] : 'user_roles';

		if ( $condition === 'specific_customers' ) {
			$allowed_customers = ! empty( $rule['specific_customers'] ) ? $rule['specific_customers'] : array();
			return in_array( $current_user->ID, $allowed_customers );
		} else {
			$allowed_roles = ! empty( $rule['disc_user_roles'] ) ? $rule['disc_user_roles'] : array();
			if ( empty( $allowed_roles ) ) {
				return true;
			}
			return ! empty( array_intersect( $current_user->roles, $allowed_roles ) );
		}
	}

	/**
	 * Check if cart qualifies for free shipping by product
	 *
	 * @param array   $rule
	 * @param WC_Cart $cart
	 * @return bool
	 */
	private function check_free_shipping_by_product( $rule, $cart ) {
		$allowed_products = ! empty( $rule['free_shipping_products'] ) ? $rule['free_shipping_products'] : array();

		if ( empty( $allowed_products ) ) {
			return false;
		}

		foreach ( $cart->get_cart() as $cart_item ) {
			$product_id = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
			$parent_id  = $cart_item['product_id'];

			if ( in_array( $product_id, $allowed_products ) || in_array( $parent_id, $allowed_products ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Check if cart qualifies for free shipping by category
	 *
	 * @param array   $rule
	 * @param WC_Cart $cart
	 * @return bool
	 */
	private function check_free_shipping_by_category( $rule, $cart ) {
		$allowed_categories = ! empty( $rule['free_shipping_categories'] ) ? $rule['free_shipping_categories'] : array();

		if ( empty( $allowed_categories ) ) {
			return false;
		}

		foreach ( $cart->get_cart() as $cart_item ) {
			$product_id = $cart_item['product_id'];
			$product    = wc_get_product( $product_id );

			if ( ! $product ) {
				continue;
			}

			$product_categories = $product->get_category_ids();

			if ( ! empty( array_intersect( $product_categories, $allowed_categories ) ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Check if cart qualifies for free shipping by cart amount
	 *
	 * @param array   $rule
	 * @param WC_Cart $cart
	 * @return bool
	 */
	private function check_free_shipping_by_cart_amount( $rule, $cart ) {
		$min_amount = ! empty( $rule['free_shipping_min_amount'] ) ? (float) $rule['free_shipping_min_amount'] : 0;

		if ( $min_amount <= 0 ) {
			return false;
		}

		$cart_total = $cart->get_subtotal();

		return $cart_total >= $min_amount;
	}

	/**
	 * check cart rules for shipping/cart
	 *
	 * @param [type] $cart_total
	 * @param [type] $total
	 */
	public function cart_condition_check( $cart_total, $total ) {
		$discount = null;
		foreach ( $cart_total as $key => $item ) {
			if ( ! empty( $item ) ) {
				$max     = (int) $key + 1;
				$get_min = (float) $cart_total[ $key ]['total'];
				$get_max = ! empty( $cart_total[ $max ]['total'] ) ? (float) $cart_total[ $max ]['total'] : 9999;

				if ( ( $total >= (float) $get_min ) && ( $total < $get_max ) ) {
					$discount = $cart_total[ $key ]['discount'];
				}
			}
		}

		return $discount;
	}

	/**
	 * Add discount on cart total
	 *
	 * @param [type] $cart
	 */
	public function add_discount_on_cart_total( $cart ) {
		if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
			return;
		}

		$cart_discount = $this->get_cart_adjustment_discount();

		if ( ! $cart_discount ) {
			return;
		}

		$discount_number = (float) $cart_discount['discount_number'];
		$offer_type      = $cart_discount['offer_type'];
		$discount_label  = $cart_discount['discount_label'];
		$rule            = $cart_discount['rule'];

		// Calculate discount amount based on qualifying items only
		if ( $offer_type === 'percentage' ) {
			// Get subtotal of qualifying items only
			$qualifying_subtotal = $this->get_qualifying_cart_total( $rule, $cart );
			$discount_amount     = ( $qualifying_subtotal * $discount_number ) / 100;
		} else {
			$discount_amount = $discount_number;
		}

		if ( $discount_amount > 0 ) {
			$cart->add_fee( $discount_label, -$discount_amount );
		}
	}

	/**
	 * Get cart adjustment discount from rules
	 *
	 * @return array|false
	 */
	public function get_cart_adjustment_discount() {
		// Get all enabled cart_adjustment rules
		$meta_query = array(
			array(
				'key'   => 'rules_type',
				'value' => 'cart_adjustment',
			),
			array(
				'key'   => 'enable_rules',
				'value' => 'yes',
			),
		);

		$cart_adjustment_rules = \Discountify\Utils\Helper::get_all_rules( -1, $meta_query );

		if ( empty( $cart_adjustment_rules ) ) {
			return false;
		}

		$cart = WC()->cart;
		if ( ! $cart || $cart->is_empty() ) {
			return false;
		}

		foreach ( $cart_adjustment_rules as $rule ) {

			// Check if rule is valid (date range)
			if ( ! $this->is_rule_valid( $rule ) ) {
				continue;
			}

			// Check user role/customer restrictions
			if ( ! $this->check_user_restrictions( $rule ) ) {
				continue;
			}

			// Check if cart contains qualifying products/categories
			if ( ! $this->check_cart_has_qualifying_items( $rule, $cart ) ) {
				continue;
			}

			$based_on = ! empty( $rule['cart_discount_on'] ) ? $rule['cart_discount_on'] : 'cart_total';
			$total    = $based_on === 'cart_total' ? $this->get_qualifying_cart_total( $rule, $cart ) : $this->get_qualifying_cart_qty( $rule, $cart );

			// multi_discounts is saved directly as array of tiers (not nested under rule type key)
			$multi_discounts = ! empty( $rule['multi_discounts'] ) ? $rule['multi_discounts'] : array();

			if ( empty( $multi_discounts ) || ! is_array( $multi_discounts ) ) {
				continue;
			}

			// Find matching discount tier
			$discount_data = $this->get_cart_adjustment_tier( $multi_discounts, $total );

			if ( $discount_data ) {
				return array(
					'rule'            => $rule,
					'discount_number' => $discount_data['discount_number'],
					'offer_type'      => $discount_data['offer_type'],
					'discount_label'  => ! empty( $rule['discount_label'] ) ? $rule['discount_label'] : $rule['discount_name'],
				);
			}
		}

		return false;
	}

	/**
	 * Get matching cart adjustment tier based on total
	 *
	 * @param array $multi_discounts
	 * @param float $total
	 * @return array|false
	 */
	private function get_cart_adjustment_tier( $multi_discounts, $total ) {
		$matched_discount = false;
		$best_min         = null;

		foreach ( $multi_discounts as $key => $tier ) {
			if ( ! isset( $tier['min'] ) || $tier['min'] === '' ) {
				continue;
			}

			$min            = (float) $tier['min'];
			$condition_type = ! empty( $tier['condition_type'] ) ? trim( html_entity_decode( $tier['condition_type'] ) ) : '>=';

			// Check if total matches the condition
			$condition_met = false;
			if ( $condition_type === '>' ) {
				$condition_met = $total > $min;
			} elseif ( $condition_type === '>=' ) {
				$condition_met = $total >= $min;
			} elseif ( $condition_type === '<' ) {
				$condition_met = $total < $min;
			} elseif ( $condition_type === '<=' ) {
				$condition_met = $total <= $min;
			} else {
				// Default to >= for backwards compatibility
				$condition_met = $total >= $min;
			}

			if ( $condition_met ) {
				// For >= and > conditions, we want the highest min that still qualifies
				// For < and <= conditions, we want the lowest min that still qualifies
				$is_better_match = false;

				if ( $best_min === null ) {
					$is_better_match = true;
				} elseif ( in_array( $condition_type, array( '>=', '>' ), true ) ) {
					// For "greater than" conditions, prefer higher minimum values
					$is_better_match = $min > $best_min;
				} else {
					// For "less than" conditions, prefer lower minimum values
					$is_better_match = $min < $best_min;
				}

				if ( $is_better_match ) {
					$best_min         = $min;
					$matched_discount = array(
						'discount_number' => ! empty( $tier['discount_number'] ) ? $tier['discount_number'] : 0,
						'offer_type'      => ! empty( $tier['offer_type'] ) ? $tier['offer_type'] : 'fixed',
					);
				}
			}
		}

		return $matched_discount;
	}

	/**
	 * Check if cart has qualifying items based on product/category filter
	 *
	 * @param array   $rule
	 * @param WC_Cart $cart
	 * @return bool
	 */
	private function check_cart_has_qualifying_items( $rule, $cart ) {
		$discount_in        = ! empty( $rule['discount_in'] ) ? $rule['discount_in'] : 'product';
		$filter_by_products = ! empty( $rule['filter_by_products'] ) ? $rule['filter_by_products'] : array();
		$filter_by_category = ! empty( $rule['filter_by_category'] ) ? $rule['filter_by_category'] : array();

		// If no filters are set, apply to all
		if ( $discount_in === 'product' && empty( $filter_by_products ) ) {
			return true;
		}
		if ( $discount_in === 'category' && empty( $filter_by_category ) ) {
			return true;
		}

		foreach ( $cart->get_cart() as $cart_item ) {
			$product_id = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
			$parent_id  = $cart_item['product_id'];

			if ( $discount_in === 'product' ) {
				$match1 = \Discountify\Utils\Helper::discount_product( $product_id, $filter_by_products );
				$match2 = \Discountify\Utils\Helper::discount_product( $parent_id, $filter_by_products );
				if ( $match1 || $match2 ) {
					return true;
				}
			} elseif ( $discount_in === 'category' ) {
				$cat_match = \Discountify\Utils\Helper::discount_category( $parent_id, $filter_by_category );
				if ( $cat_match ) {
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * Get cart total for qualifying items only
	 *
	 * @param array   $rule
	 * @param WC_Cart $cart
	 * @return float
	 */
	private function get_qualifying_cart_total( $rule, $cart ) {
		$discount_in        = ! empty( $rule['discount_in'] ) ? $rule['discount_in'] : 'product';
		$filter_by_products = ! empty( $rule['filter_by_products'] ) ? $rule['filter_by_products'] : array();
		$filter_by_category = ! empty( $rule['filter_by_category'] ) ? $rule['filter_by_category'] : array();

		// If no filters, return full subtotal
		if ( $discount_in === 'product' && empty( $filter_by_products ) ) {
			return $cart->get_subtotal();
		}
		if ( $discount_in === 'category' && empty( $filter_by_category ) ) {
			return $cart->get_subtotal();
		}

		$qualifying_total = 0;

		foreach ( $cart->get_cart() as $cart_item ) {
			$product_id    = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
			$parent_id     = $cart_item['product_id'];
			$is_qualifying = false;

			if ( $discount_in === 'product' ) {
				if ( \Discountify\Utils\Helper::discount_product( $product_id, $filter_by_products ) ||
					\Discountify\Utils\Helper::discount_product( $parent_id, $filter_by_products ) ) {
					$is_qualifying = true;
				}
			} elseif ( $discount_in === 'category' ) {
				if ( \Discountify\Utils\Helper::discount_category( $parent_id, $filter_by_category ) ) {
					$is_qualifying = true;
				}
			}

			if ( $is_qualifying ) {
				$qualifying_total += $cart_item['line_subtotal'];
			}
		}

		return $qualifying_total;
	}

	/**
	 * Get cart quantity for qualifying items only
	 *
	 * @param array   $rule
	 * @param WC_Cart $cart
	 * @return int
	 */
	private function get_qualifying_cart_qty( $rule, $cart ) {
		$discount_in        = ! empty( $rule['discount_in'] ) ? $rule['discount_in'] : 'product';
		$filter_by_products = ! empty( $rule['filter_by_products'] ) ? $rule['filter_by_products'] : array();
		$filter_by_category = ! empty( $rule['filter_by_category'] ) ? $rule['filter_by_category'] : array();

		// If no filters, return full cart count
		if ( $discount_in === 'product' && empty( $filter_by_products ) ) {
			return $cart->get_cart_contents_count();
		}
		if ( $discount_in === 'category' && empty( $filter_by_category ) ) {
			return $cart->get_cart_contents_count();
		}

		$qualifying_qty = 0;

		foreach ( $cart->get_cart() as $cart_item ) {
			$product_id    = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
			$parent_id     = $cart_item['product_id'];
			$is_qualifying = false;

			if ( $discount_in === 'product' ) {
				if ( \Discountify\Utils\Helper::discount_product( $product_id, $filter_by_products ) ||
					\Discountify\Utils\Helper::discount_product( $parent_id, $filter_by_products ) ) {
					$is_qualifying = true;
				}
			} elseif ( $discount_in === 'category' ) {
				if ( \Discountify\Utils\Helper::discount_category( $parent_id, $filter_by_category ) ) {
					$is_qualifying = true;
				}
			}

			if ( $is_qualifying ) {
				$qualifying_qty += $cart_item['quantity'];
			}
		}

		return $qualifying_qty;
	}

	/**
	 * Display updated price
	 * Show discount tag , discount message
	 **/
	public function custom_dynamic_sale_price_html( $price_html, $product ) {
		if ( ! $product ) {
			return $price_html;
		}

		// Prevent duplicate tags
		if ( strpos( $price_html, 'discountify-product-discount' ) !== false ) {
			return $price_html;
		}

		$result = $this->get_rules_type( $product->get_id() );

		// If no discount found and product is variable, check its variations
		if ( $result['success'] === false && $product->is_type( 'variable' ) ) {
			$variation_ids = $product->get_children();
			foreach ( $variation_ids as $variation_id ) {
				$result = $this->get_rules_type( $variation_id );
				if ( $result['success'] === true ) {
					break;
				}
			}
		}

		if ( $result['success'] === false ) {
			return $price_html;
		}

		$discount_text = '';
		if ( ! empty( $result['data']['discount_label'] ) ) {
			$discount_text = $result['data']['discount_label'];
			$discount_text = str_replace( '{{product_name}}', get_the_title( $product->get_id() ), $discount_text );
		} else {
			$discount_text = Message::instance()->discount_label( $result['data'] );
		}

		if ( empty( $discount_text ) ) {
			return $price_html;
		}

		$message = ' <span class="discountify-product-discount"><span class="discountify-product-discount-label-value">' . esc_html( $discount_text ) . '</span></span>';

		return $price_html . $message;
	}

	/**
	 * Show discount badge on product thumbnail in shop loop
	 */
	public function show_discount_badge_on_thumbnail() {
		global $product;

		if ( ! $product ) {
			return;
		}

		$result = $this->get_rules_type( $product->get_id() );

		// If no discount found and product is variable, check its variations
		if ( $result['success'] === false && $product->is_type( 'variable' ) ) {
			$variation_ids = $product->get_children();
			foreach ( $variation_ids as $variation_id ) {
				$result = $this->get_rules_type( $variation_id );
				if ( $result['success'] === true ) {
					break;
				}
			}
		}

		if ( $result['success'] === false ) {
			return;
		}

		$discount_text = '';
		if ( ! empty( $result['data']['discount_label'] ) ) {
			$discount_text = $result['data']['discount_label'];
			$discount_text = str_replace( '{{product_name}}', get_the_title( $product->get_id() ), $discount_text );
		} else {
			$discount_text = Message::instance()->discount_label( $result['data'] );
		}

		if ( empty( $discount_text ) ) {
			return;
		}

		echo '<span class="discountify-thumbnail-badge"><span class="discountify-thumbnail-badge-value">' . esc_html( $discount_text ) . '</span></span>';
	}

	/**
	 * Show discount badge on single product page thumbnail
	 */
	public function show_discount_badge_on_single_product() {
		global $product;

		if ( ! $product || ! is_product() ) {
			return;
		}

		$result = $this->get_rules_type( $product->get_id() );

		// If no discount found and product is variable, check its variations
		if ( $result['success'] === false && $product->is_type( 'variable' ) ) {
			$variation_ids = $product->get_children();
			foreach ( $variation_ids as $variation_id ) {
				$result = $this->get_rules_type( $variation_id );
				if ( $result['success'] === true ) {
					break;
				}
			}
		}

		$discount_text = '';
		if ( $result['success'] === true ) {
			if ( ! empty( $result['data']['discount_label'] ) ) {
				$discount_text = $result['data']['discount_label'];
				$discount_text = str_replace( '{{product_name}}', get_the_title( $product->get_id() ), $discount_text );
			} else {
				$discount_text = Message::instance()->discount_label( $result['data'] );
			}
		}

		// Build variation discount data for JS
		$variation_discounts = array();
		if ( $product->is_type( 'variable' ) ) {
			foreach ( $product->get_children() as $variation_id ) {
				$var_result = $this->get_rules_type( $variation_id );
				if ( $var_result['success'] === true ) {
					$var_text = '';
					if ( ! empty( $var_result['data']['discount_label'] ) ) {
						$var_text = $var_result['data']['discount_label'];
						$var_text = str_replace( '{{product_name}}', get_the_title( $product->get_id() ), $var_text );
					} else {
						$var_text = Message::instance()->discount_label( $var_result['data'] );
					}
					if ( ! empty( $var_text ) ) {
						$variation_discounts[ $variation_id ] = $var_text;
					}
				}
			}
		}

		$badge_class = empty( $discount_text ) ? ' discountify-badge-hidden' : '';
		echo '<span class="discountify-single-badge' . esc_attr( $badge_class ) . '"><span class="discountify-single-badge-value" data-default="' . esc_attr( $discount_text ) . '">' . esc_html( $discount_text ) . '</span></span>';

		if ( $product->is_type( 'variable' ) ) {
			echo '<script>var discountifyVariationDiscounts = ' . wp_json_encode( $variation_discounts ) . ';</script>';
		}
	}

	/**
	 * AJAX handler to get variation discount
	 */
	public function ajax_get_variation_discount() {
		$variation_id = isset( $_POST['variation_id'] ) ? absint( $_POST['variation_id'] ) : 0;

		if ( ! $variation_id ) {
			wp_send_json_error();
		}

		$result = $this->get_rules_type( $variation_id );

		if ( $result['success'] === false ) {
			wp_send_json_success( array( 'discount_text' => '' ) );
		}

		$discount_text = '';
		if ( ! empty( $result['data']['discount_label'] ) ) {
			$discount_text = $result['data']['discount_label'];
		} else {
			$discount_text = Message::instance()->discount_label( $result['data'] );
		}

		wp_send_json_success( array( 'discount_text' => $discount_text ) );
	}

	/**
	 * Show cart item meta
	 *
	 * @param [type] $item_data
	 * @param [type] $cart_item
	 */
	public function display_cart_item_meta_data( $item_data, $cart_item ) {
		// Skip meta display for BOGO free items — the FREE tag is shown separately.
		if ( ! empty( $cart_item['bogo_x_x_free'] ) || ! empty( $cart_item['bogo_x_y_free'] ) ) {
			return $item_data;
		}

		// Use variation_id if it exists, otherwise use product_id
		$product_id = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
		$data       = DiscountifyCoupon::instance()->item_discount_check( $product_id, $cart_item['quantity'], $cart_item );

		if ( ! empty( $data ) && ! empty( $data['message'] ) ) {
			$item_data[] = array(
				'name'  => '',
				'key'   => '',
				'value' => $data['message'],
			);
		}

		return $item_data;
	}


	/**
	 * Add order item meta from cart item meta
	 */
	public function add_order_item_meta( $item, $cart_item_key, $values ) {
		// Skip discount message for BOGO free items — handled via _discountify_bogo_free flag.
		if ( ! empty( $values['bogo_x_x_free'] ) || ! empty( $values['bogo_x_y_free'] ) ) {
			$item->add_meta_data( '_discountify_bogo_free', 'yes', true );
			return;
		}

		// Use variation_id if it exists, otherwise use product_id
		$product_id = ! empty( $values['variation_id'] ) ? $values['variation_id'] : $values['product_id'];
		$data       = DiscountifyCoupon::instance()->item_discount_check( $product_id, $values['quantity'], $values );
		if ( ! empty( $data ) && ! empty( $data['message'] ) ) {
			$item->add_meta_data( 'discountify_offer', $data['message'], true );
		}
	}

	/**
	 * Format discount meta for order/thank-you page display
	 */
	public function format_order_item_discount_meta( $formatted_meta ) {
		$offer_keys = array( 'discountify_offer', 'Discount', 'Offer', 'Bogo' );
		foreach ( $formatted_meta as $meta_id => $meta ) {
			if ( in_array( $meta->key, $offer_keys, true ) ) {
				$meta->display_key   = '<span class="discountify-offer-meta"></span>';
				$meta->display_value = wp_kses_post( $meta->value );
			}
		}
		return $formatted_meta;
	}

	/**
	 * Rename discountify_offer meta key in admin order details
	 */
	public function format_order_item_meta_key( $display_key, $meta, $item = null ) {
		if ( $meta->key === 'discountify_offer' ) {
			return __( 'Offer', 'discountify' );
		}
		return $display_key;
	}

	/**
	 * Add coupon in total
	 *
	 * @param [type] $cart
	 * @return void
	 */
	public function add_coupon_automatically( $cart ) {
		if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
			return;
		}

		if ( self::$bogo_processing ) {
			return;
		}

		self::$bogo_processing = true;


		$needs_free  = array();
		$has_free    = array(); // tracks bogo_x_x_free items (same product) for orphan cleanup
		$has_xy_free = array(); // tracks bogo_x_y_free items (different product) — managed by Pro, skip orphan cleanup

		foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
			$pid      = (int) $cart_item['product_id'];
			$vid      = isset( $cart_item['variation_id'] ) ? (int) $cart_item['variation_id'] : 0;
			$item_key = $pid . '_' . $vid;

			if ( ! empty( $cart_item['bogo_x_x_free'] ) || ! empty( $cart_item['bogo_x_y_free'] ) ) {
				$cart_item['data']->set_price( 0 );
				if ( ! empty( $cart_item['bogo_x_y_free'] ) ) {
					// XY free items are a different gift product — managed by Pro plugin, don't orphan-clean them.
					$has_xy_free[ $item_key ] = $cart_item_key;
				} else {
					$has_free[ $item_key ] = $cart_item_key;
				}
			} else {
				// Use variation_id if it exists, otherwise use product_id
				$product_id = $vid ? $vid : $pid;
				$quantity   = $cart_item['quantity'];
				$price      = $cart_item['data']->get_price();


				// Check for BOGO free rule – auto-add free item if needed.
				$bogo_free = $this->get_bogo_free_data( $product_id, $quantity );

				if ( $bogo_free ) {
					$needs_free[ $item_key ] = array(
						'product_id'   => $pid,
						'variation_id' => $vid,
						'variation'    => isset( $cart_item['variation'] ) ? $cart_item['variation'] : array(),
						'free_qty'     => $bogo_free['free_qty'],
					);
				}

				$result = DiscountifyCoupon::instance()->get_coupon_discount( $product_id, $quantity, $price );
				if ( ! empty( $result ) && $result['rules_type'] !== '' ) {
					$cart->applied_coupons = array_diff( $cart->applied_coupons, array( $result['rules_type'] ) );
					$allowed_coupons       = array( 'bogo', 'discount', 'total_spend' );
					if ( ( in_array( $result['rules_type'], $allowed_coupons ) ) &&
					! in_array( $result['bogo_discount_type'], array( 'buy_x_get_y', 'category_bogo' ), true ) ) {
						$cart->applied_coupons[] = $result['rules_type'];
					}
				}
			}
		}


		// Add missing BOGO free products directly into cart contents.
		foreach ( $needs_free as $item_key => $data ) {
			if ( isset( $has_free[ $item_key ] ) ) {
				// Update quantity of existing free item if it changed.
				if ( isset( $cart->cart_contents[ $has_free[ $item_key ] ] ) ) {
					$cart->cart_contents[ $has_free[ $item_key ] ]['quantity'] = $data['free_qty'];
				}
				continue;
			}

			$free_product = wc_get_product( $data['variation_id'] ? $data['variation_id'] : $data['product_id'] );
			if ( ! $free_product ) {
				continue;
			}

			$cart_item_data  = array( 'bogo_x_x_free' => $data['free_qty'] );
			$free_cart_key   = $cart->generate_cart_id( $data['product_id'], $data['variation_id'], $data['variation'], $cart_item_data );


			$cart->cart_contents[ $free_cart_key ] = apply_filters(
				'woocommerce_add_cart_item',
				array_merge(
					$cart_item_data,
					array(
						'key'          => $free_cart_key,
						'product_id'   => $data['product_id'],
						'variation_id' => $data['variation_id'],
						'variation'    => $data['variation'],
						'quantity'     => $data['free_qty'],
						'data'         => $free_product,
						'data_hash'    => wc_get_cart_item_data_hash( $free_product ),
					)
				),
				$free_cart_key
			);

			$cart->cart_contents[ $free_cart_key ]['data']->set_price( 0 );
		}

		// Remove orphaned free items (paid product was removed).
		foreach ( $has_free as $item_key => $cart_key ) {
			if ( ! isset( $needs_free[ $item_key ] ) ) {
				unset( $cart->cart_contents[ $cart_key ] );
			}
		}

		self::$bogo_processing = false;
	}

	/**
	 * Show coupon html
	 *
	 * @param [type] $coupon_html
	 * @param [type] $coupon
	 * @param [type] $discount_amount_html
	 */
	public function add_coupon_html( $coupon_html, $coupon, $discount_amount_html ) {
		$amt       = '';
		$currency  = '';
		$last_part = esc_html__( 'OFF', 'discountify' );

		// Get the discount label from the coupon code
		$coupon_code    = $coupon->get_code();
		$discount_label = '';

		// Handle cart_adjustment coupon
		if ( $coupon_code === 'cart_adjustment' ) {
			$cart_discount = $this->get_cart_adjustment_discount();
			if ( $cart_discount ) {
				$discount_label = $cart_discount['discount_label'];
				$currency       = $cart_discount['offer_type'] === 'percentage' ? '%' : get_woocommerce_currency_symbol();

				if ( ! empty( $discount_label ) ) {
					$amt = "<p><em><strong class='coupon_discount_html'>" . esc_html( $discount_label ) . '</strong></em></p>';
				} else {
					$amt = "<p><em><strong class='coupon_discount_html'>{$cart_discount['discount_number']}{$currency} {$last_part}</strong></em></p>";
				}
				return $coupon_html . $amt;
			}
		}

		// Check if this is a discountify coupon and get the discount_label
		if ( in_array( $coupon_code, array( 'bogo', 'discount', 'total_spend' ) ) ) {
			global $woocommerce;
			foreach ( $woocommerce->cart->get_cart() as $cart_item ) {
				// Use variation_id if it exists, otherwise use product_id
				$product_id = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
				$result     = $this->get_rules_type( $product_id );
				if ( $result['success'] && ! empty( $result['data']['discount_label'] ) ) {
					$discount_label = $result['data']['discount_label'];
					break;
				}
			}
		}

		// If discount_label exists, show only the label. Otherwise, show the discount amount
		if ( ! empty( $discount_label ) ) {
			// Show only the discount label, no need to show amount again
			return $coupon_html;
		} else {
			// Show the discount amount as before
			if ( $coupon->get_discount_type() === 'fixed_product' ) {
				$currency = get_woocommerce_currency_symbol();
			}
			if ( $coupon->get_discount_type() === 'percent' ) {
				$currency = '%';
			}

			if ( ! empty( $coupon->get_amount() ) ) {
				$amt = "<p><em><strong class='coupon_discount_html'>{$coupon->get_amount()}{$currency} {$last_part}</strong></em></p>";
			}
			return $coupon_html . $amt;
		}
	}

	/**
	 * Apply coupon html
	 *
	 * @param [type] $false
	 * @param [type] $data
	 * @param [type] $coupon
	 */
	public function validate_discount_coupon( $false, $data, $coupon ) {
		// possible types are: 'fixed_cart', 'percent', 'fixed_product' or 'percent_product.
		switch ( $data ) {
			case 'bogo':
			case 'discount':
			case 'total_spend':
				$coupon = $this->apply_discount_data();
				return $coupon;
			case 'cart_adjustment':
				$coupon = $this->apply_cart_adjustment_coupon();
				return $coupon;
			default:
				return $false;
		}
	}

	/**
	 * Apply cart adjustment coupon data
	 *
	 * @return array
	 */
	public function apply_cart_adjustment_coupon() {
		$cart_discount = $this->get_cart_adjustment_discount();

		if ( ! $cart_discount ) {
			return array();
		}

		$discount_type = $cart_discount['offer_type'] === 'percentage' ? 'percent' : 'fixed_cart';

		return \Discountify\Utils\Helper::discount_coupon(
			array(
				'amount'                     => $cart_discount['discount_number'],
				'product_ids'                => array(),
				'product_categories'         => array(),
				'exclude_product_categories' => array(),
				'discount_type'              => $discount_type,
			)
		);
	}

	public function apply_discount_data() {
		global $woocommerce;

		// Generate a hash of current cart to detect changes
		$cart_contents = $woocommerce->cart->get_cart();
		$cart_hash     = md5(
			json_encode(
				array_map(
					function ( $item ) {
						return array(
							'product_id'   => $item['product_id'],
							'variation_id' => $item['variation_id'] ?? 0,
							'quantity'     => $item['quantity'],
							'price'        => $item['data']->get_price(),
						);
					},
					$cart_contents
				)
			)
		);

		// Return cached data if cart hasn't changed
		if ( $this->last_cart_hash === $cart_hash && $this->cached_coupon_data !== null ) {
			return $this->cached_coupon_data;
		}

		$coupon                = array();
		$total_discount_amount = 0;
		$has_fixed_discount    = false;

		foreach ( $cart_contents as $cart_item ) {
			// Use variation_id if it exists, otherwise use product_id
			$product_id = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
			$price      = $cart_item['data']->get_price();
			$result     = DiscountifyCoupon::instance()->get_coupon_discount( $product_id, $cart_item['quantity'], $price );
			if ( ! empty( $result ) && ! empty( $result['coupon'] ) ) {
				$coupon = $result['coupon'];
				// Accumulate discount amounts for fixed discounts
				if ( isset( $coupon['discount_type'] ) && $coupon['discount_type'] === 'fixed_product' ) {
					$total_discount_amount += (float) $coupon['amount'] * $cart_item['quantity'];
					$has_fixed_discount     = true;
				}
			}
		}

		// If we accumulated fixed discounts, convert to fixed_cart and use total amount
		if ( $has_fixed_discount && ! empty( $coupon ) ) {
			$coupon['amount']        = $total_discount_amount;
			$coupon['discount_type'] = 'fixed_cart'; // Apply total discount to cart
		}

		// Cache the result
		$this->last_cart_hash     = $cart_hash;
		$this->cached_coupon_data = $coupon;

		return $coupon;
	}

	public function change_product_price_display( $old_display, $cart_item, $cart_item_key ) {
		$product = $cart_item['data'];
		if ( $this->get_rules_type( $product->get_id() )['success'] === true ) {
			return $product->get_price_html();
		}

		return $old_display;
	}

	/**
	 * Add inline CSS styles for discount display in cart and mini-cart
	 */
	public function add_discount_display_styles() {
		$settings = \Discountify\Utils\Helper::get_settings();

		$text_color    = esc_attr( $settings['label_text_color'] );
		$bg_color      = esc_attr( $settings['label_bg_color'] );
		$border_color  = esc_attr( $settings['label_border_color'] );
		$border_width  = intval( $settings['label_border_width'] );
		$border_radius = intval( $settings['label_border_radius'] );
		$box_shadow    = esc_attr( $settings['label_box_shadow'] );

		?>
		<style type="text/css">
			/* Hide legacy discount tag after price */
			.discountify-product-discount {
				display: none !important;
			}
			/* Discountify thumbnail badge styles for shop loop */
			.discountify-thumbnail-badge {
				position: absolute;
				top: 20px;
				left: 10px;
				z-index: 1;
				display: inline-block;
				max-width: calc(100% - 20px);
				background: <?php echo esc_attr( $bg_color ); ?>;
				color: <?php echo esc_attr( $text_color ); ?> !important;
				font-size: 11px;
				font-weight: 600;
				padding: 0.5em 0.6em;
				border-radius: <?php echo esc_attr( $border_radius ); ?>px;
				text-transform: uppercase;
				letter-spacing: 0.3px;
				white-space: normal;
				line-height: 1.3;
				overflow: hidden;
				text-overflow: ellipsis;
				display: -webkit-box;
				-webkit-line-clamp: 2;
				-webkit-box-orient: vertical;
			}
				<?php if ( ! empty( $box_shadow ) ) : ?>
				box-shadow: <?php echo esc_attr( $box_shadow ); ?>;
				<?php endif; ?>
				<?php if ( $border_width > 0 ) : ?>
				border: <?php echo esc_attr( $border_width ); ?>px solid <?php echo esc_attr( $border_color ); ?>;
				<?php endif; ?>
			}
			/* Discountify single product badge */
			.discountify-single-badge {
				position: absolute;
				top: 10px;
				left: 20px;
				z-index: 9;
				display: inline-block;
				margin-top: 8px;
				background: <?php echo esc_attr( $bg_color ); ?>;
				color: <?php echo esc_attr( $text_color ); ?> !important;
				font-size: 13px;
				font-weight: 500;
				padding: 0.4em 0.8em;
				border-radius: <?php echo esc_attr( $border_radius ); ?>px;
				text-transform: uppercase;
				letter-spacing: 0.3px;
				white-space: nowrap;
				line-height: 1.4;
				<?php if ( ! empty( $box_shadow ) ) : ?>
				box-shadow: <?php echo esc_attr( $box_shadow ); ?>;
				<?php endif; ?>
				<?php if ( $border_width > 0 ) : ?>
				border: <?php echo esc_attr( $border_width ); ?>px solid <?php echo esc_attr( $border_color ); ?>;
				<?php endif; ?>
			}
			.discountify-single-badge-value {
				display: inline-block;
				color: inherit !important;
			}
			.discountify-badge-hidden {
				display: none !important;
			}
			.woocommerce div.product div.images {
				position: relative;
			}
			/* Discountify cart discount display styles */
			.discountify-cart-meta {
				display: block;
				font-size: 13px;
				color: #28a745;
				margin-bottom: 2px;
			}
			.discountify-cart-meta small {
				display: block;
				line-height: 1.5;
				font-size: inherit;
			}
			/* Ensure discount info is visible in WooCommerce cart item data */
			.woocommerce-cart-form__cart-item .product-name .discountify-cart-meta,
			.mini_cart_item .discountify-cart-meta,
			.cart_item .discountify-cart-meta {
				display: block !important;
				visibility: visible !important;
			}
			/* Hide empty key label and colon for discountify cart item data */
			dl.variation dt.variation- {
				display: none !important;
			}
			dl.variation dd.variation- {
				padding: 0;
				margin: 0;
			}
			/* Hide empty key colon on cart page */
			dl.variation dt.variation- {
				display: none;
			}
			/* Hide the label/colon for discountify order offer meta */
			.wc-item-meta-label:has(.discountify-offer-meta) {
				display: none !important;
			}
			/* BOGO Free tag styles for side-cart, mini-cart, and checkout */
			.discountify-bogo-free-tag {
				display: inline-block;
				background: #28a745;
				color: #fff !important;
				font-size: 10px;
				font-weight: 700;
				padding: 2px 8px;
				border-radius: 3px;
				margin-left: 6px;
				text-transform: uppercase;
				vertical-align: middle;
				letter-spacing: 0.5px;
				line-height: 1.4;
			}
			.discountify-bogo-free-price {
				color: #28a745 !important;
				font-weight: 700;
				font-size: 14px;
			}
		</style>
		<script>
		document.addEventListener('DOMContentLoaded', function() {
			/* Shop loop: position badge after sale tag */
			document.querySelectorAll('.discountify-thumbnail-badge').forEach(function(badge) {
				var product = badge.closest('li.product');
				if (!product) return;
				var saleTag = product.querySelector('.ast-onsale-card');
				if (saleTag) {
					badge.style.left = (saleTag.offsetLeft + saleTag.offsetWidth + 5) + 'px';
				}
			});

			/* Shop loop: position discount badge after sale tag */
			function positionShopBadges() {
				document.querySelectorAll('.discountify-thumbnail-badge').forEach(function(badge) {
					var parent = badge.parentElement;
					if (!parent) return;
					var saleTag = parent.querySelector('.onsale') || parent.querySelector('.ast-onsale-card');
					if (saleTag) {
						badge.style.left = (saleTag.offsetLeft + saleTag.offsetWidth + 5) + 'px';
					}
				});
			}
			positionShopBadges();
			window.addEventListener('load', positionShopBadges);

			/* Single product: position badge after sale tag */
			function positionSingleBadge() {
				var singleBadge = document.querySelector('.discountify-single-badge');
				if (!singleBadge) return;
				var container = singleBadge.closest('.woocommerce-product-gallery')
					|| singleBadge.closest('.images')
					|| singleBadge.parentElement;
				if (!container) return;
				var saleTag = container.querySelector('.ast-onsale-card')
					|| container.querySelector('.onsale')
					|| container.parentElement.querySelector('.ast-onsale-card')
					|| container.parentElement.querySelector('.onsale');
				if (saleTag) {
					singleBadge.style.left = (saleTag.offsetLeft + saleTag.offsetWidth + 5) + 'px';
				}
			}
			positionSingleBadge();
			window.addEventListener('load', positionSingleBadge);

			/* Single product: update badge and price label on variation change */
			if (typeof jQuery !== 'undefined') {
				jQuery('.variations_form').on('found_variation', function(event, variation) {
					var badge = document.querySelector('.discountify-single-badge');
					if (badge) {
						var valueEl = badge.querySelector('.discountify-single-badge-value');
						if (typeof discountifyVariationDiscounts !== 'undefined' && discountifyVariationDiscounts[variation.variation_id]) {
							valueEl.textContent = discountifyVariationDiscounts[variation.variation_id];
							badge.classList.remove('discountify-badge-hidden');
						} else {
							valueEl.textContent = '';
							badge.classList.add('discountify-badge-hidden');
						}
					}

					/* Show discount label after price */
					var priceWrap = document.querySelector('.summary .price');
					if (priceWrap) {
						var existing = priceWrap.querySelector('.discountify-price-label');
						if (existing) existing.remove();
						if (typeof discountifyVariationDiscounts !== 'undefined' && discountifyVariationDiscounts[variation.variation_id]) {
							var label = document.createElement('span');
							label.className = 'discountify-thumbnail-badge discountify-price-label';
							label.style.position = 'relative';
							label.style.top = 'auto';
							label.style.left = 'auto';
							label.style.marginLeft = '8px';
							label.style.marginTop = '0px';
							label.style.verticalAlign = 'middle';
							label.innerHTML = '<span class="discountify-thumbnail-badge-value">' + discountifyVariationDiscounts[variation.variation_id].replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</span>';
							priceWrap.appendChild(label);
						}
					}
				}).on('reset_data', function() {
					var badge = document.querySelector('.discountify-single-badge');
					if (badge) {
						var valueEl = badge.querySelector('.discountify-single-badge-value');
						var defaultText = valueEl.getAttribute('data-default');
						if (defaultText) {
							valueEl.textContent = defaultText;
							badge.classList.remove('discountify-badge-hidden');
						} else {
							badge.classList.add('discountify-badge-hidden');
						}
					}

					/* Remove discount label from price */
					var existing = document.querySelector('.summary .price .discountify-price-label');
					if (existing) existing.remove();
				});
			}
		});
		</script>
		<?php
	}
	/**
	 * Show cart adjustment discount message before block cart items
	 */
	public function show_cart_adjustment_message_block_cart() {
		if ( ! function_exists( 'is_cart' ) && ! function_exists( 'is_checkout' ) ) {
			return;
		}
		if ( ! is_cart() && ! is_checkout() ) {
			return;
		}

		?>
		<script>
		(function() {
			var msgClass = 'discountify-cart-adjustment-message';

			function updateMessage() {
				var cartItems = document.querySelector('.wc-block-cart-items.wp-block-woocommerce-cart-line-items-block');
				if (!cartItems) return;

				var existing = cartItems.parentNode.querySelector('.' + msgClass);
				var cartStore = window.wc && window.wc.wcBlocksData && window.wc.wcBlocksData.cartStore;
				if (!cartStore) return;

				var store = wp.data.select(cartStore);
				var cartData = store.getCartData();
				var fees = cartData.fees || [];

				// Find discount fee (negative amount)
				var discountFee = null;
				for (var i = 0; i < fees.length; i++) {
					if (parseInt(fees[i].totals.total) < 0) {
						discountFee = fees[i];
						break;
					}
				}

				if (!discountFee) {
					if (existing) existing.remove();
					return;
				}

				var totals = cartData.totals || {};
				var minorUnit = totals.currency_minor_unit || 2;
				var symbol = totals.currency_symbol || '$';
				var prefix = totals.currency_prefix || '';
				var suffix = totals.currency_suffix || '';
				var amount = Math.abs(parseInt(discountFee.totals.total)) / Math.pow(10, minorUnit);
				var message = discountFee.name || '';
					
				if (existing) {
					existing.textContent = message;
				} else {
					var div = document.createElement('div');
					div.className = 'woocommerce-info ' + msgClass;
					div.textContent = message;
					cartItems.parentNode.insertBefore(div, cartItems);
				}
			}

			// Mark BOGO free items in block cart and checkout (show FREE badge, hide qty controls).
			function markBogoFreeItems() {
				var cartStore = window.wc && window.wc.wcBlocksData && window.wc.wcBlocksData.cartStore;
				if (!cartStore) return;

				var store = wp.data.select(cartStore);
				var cartData = store.getCartData();
				var items = cartData.items || [];

				// Block cart rows
				var rows = document.querySelectorAll('.wc-block-cart-items__row');
				rows.forEach(function(row, index) {
					if (!items[index]) return;

					var ext = items[index].extensions && items[index].extensions.discountify_bogo;
					if (ext && ext.is_bogo_free && !row.classList.contains('discountify-bogo-done')) {
						row.classList.add('discountify-bogo-done');

						// Replace total price with FREE.
						var totalPrice = row.querySelector('.wc-block-cart-item__total');
						if (totalPrice) {
							totalPrice.innerHTML = '<span class="discountify-bogo-free-price"><?php echo esc_js( __( 'FREE', 'discountify' ) ); ?></span>';
						}

						// Hide quantity controls and remove button.
						var qtyWrap = row.querySelector('.wc-block-cart-item__quantity');
						if (qtyWrap) {
							var qtyInput = qtyWrap.querySelector('.wc-block-components-quantity-selector');
							if (qtyInput) qtyInput.style.display = 'none';
							var removeBtn = qtyWrap.querySelector('.wc-block-cart-item__remove-link');
							if (removeBtn) removeBtn.style.display = 'none';
						}
					}
				});

				// Block checkout order summary rows
				var checkoutRows = document.querySelectorAll('.wc-block-components-order-summary-item');
				checkoutRows.forEach(function(row, index) {
					if (!items[index]) return;

					var ext = items[index].extensions && items[index].extensions.discountify_bogo;
					if (ext && ext.is_bogo_free && !row.classList.contains('discountify-bogo-done')) {
						row.classList.add('discountify-bogo-done');

						// Replace total price with FREE
						var totalPrice = row.querySelector('.wc-block-components-order-summary-item__total-price');
						if (totalPrice) {
							totalPrice.innerHTML = '<span class="discountify-bogo-free-price"><?php echo esc_js( __( 'FREE', 'discountify' ) ); ?></span>';
						}

						// Hide individual price line (strikethrough + sale price) and save badge
						var priceRow = row.querySelector('.wc-block-components-order-summary-item__individual-prices');
						if (priceRow) priceRow.style.display = 'none';
						var saleBadge = row.querySelector('.wc-block-components-sale-badge');
						if (saleBadge) saleBadge.style.display = 'none';
					}
				});
			}

			// Subscribe to cart store changes + observe DOM for late-rendered checkout elements.
			function init() {
				if (!window.wc || !window.wc.wcBlocksData || !window.wp || !wp.data) {
					setTimeout(init, 200);
					return;
				}

				var cartStore = window.wc.wcBlocksData.cartStore;
				wp.data.subscribe(function() {
					requestAnimationFrame(function() {
						updateMessage();
						markBogoFreeItems();
					});
				});
				updateMessage();
				markBogoFreeItems();

				// MutationObserver: checkout order summary renders after page load.
				var observer = new MutationObserver(function() {
					markBogoFreeItems();
				});
				observer.observe(document.body, { childList: true, subtree: true });

				// Stop observing after 10s to avoid performance impact.
				setTimeout(function() { observer.disconnect(); }, 10000);
			}

			if (document.readyState === 'complete') {
				init();
			} else {
				window.addEventListener('load', init);
			}
		})();
		</script>
		<?php
	}

	/**
	 * Get the BOGO free rule data for a product if applicable.
	 *
	 * @param int $product_id
	 * @param int $quantity
	 * @return array|false
	 */
	private function get_bogo_free_data( $product_id, $quantity ) {
		$result = $this->get_rules_type( $product_id );


		if ( ! $result['success'] ) {
			return false;
		}


		if ( $result['data']['rules_type'] !== 'bogo' ) {
			return false;
		}

		$xx_types = array( 'buy_x_get_x', 'bogo_free', 'buy_n_get_one' );
		if ( ! in_array( $result['data']['bogo_discount_type'], $xx_types, true ) ) {
			return false;
		}

		$product = wc_get_product( $product_id );
		if ( ! $product ) {
			return false;
		}

		$bogo_data = $this->multi_discount_type( $result['data'], $quantity, $product->get_price() );


		if ( empty( $bogo_data['offer_type'] ) || $bogo_data['offer_type'] !== 'free' ) {
			return false;
		}

		$free_qty = ! empty( $bogo_data['free_quantity'] ) ? (int) $bogo_data['free_quantity'] : 1;


		return array(
			'free_qty'  => $free_qty,
			'bogo_data' => $bogo_data,
		);
	}

	/**
	 * Find existing BOGO free cart item for a product.
	 *
	 * @param int $product_id
	 * @param int $variation_id
	 * @return string|false Cart item key or false.
	 */
	private function find_bogo_free_cart_item( $product_id, $variation_id = 0 ) {
		foreach ( WC()->cart->get_cart() as $key => $item ) {
			if ( ! empty( $item['bogo_x_x_free'] ) &&
				(int) $item['product_id'] === (int) $product_id &&
				( ! $variation_id || (int) $item['variation_id'] === (int) $variation_id ) ) {
				return $key;
			}
		}
		return false;
	}

	/**
	 * Auto-add free product when a BOGO-qualifying product is added to cart.
	 * Note: The main logic is in add_coupon_automatically(); this ensures
	 * the free item appears immediately when the Store API returns the cart.
	 */
	public function bogo_auto_add_free_product( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
		if ( self::$bogo_processing ) {
			return;
		}

		if ( ! empty( $cart_item_data['bogo_x_x_free'] ) ) {
			return;
		}

		$check_id  = $variation_id ? $variation_id : $product_id;
		$bogo_free = $this->get_bogo_free_data( $check_id, $quantity );

		if ( ! $bogo_free ) {
			return;
		}

		$free_qty    = $bogo_free['free_qty'];
		$existing_key = $this->find_bogo_free_cart_item( $product_id, $variation_id );

		if ( $existing_key ) {
			return;
		}

		// Directly inject into cart_contents to avoid WC validation/stock blocks.
		$free_product = wc_get_product( $variation_id ? $variation_id : $product_id );
		if ( ! $free_product ) {
			return;
		}

		$cart           = WC()->cart;
		$free_item_data = array( 'bogo_x_x_free' => $free_qty );
		$free_cart_key  = $cart->generate_cart_id( $product_id, $variation_id, is_array( $variation ) ? $variation : array(), $free_item_data );

		$cart->cart_contents[ $free_cart_key ] = apply_filters(
			'woocommerce_add_cart_item',
			array_merge(
				$free_item_data,
				array(
					'key'          => $free_cart_key,
					'product_id'   => $product_id,
					'variation_id' => $variation_id ? $variation_id : 0,
					'variation'    => is_array( $variation ) ? $variation : array(),
					'quantity'     => $free_qty,
					'data'         => $free_product,
					'data_hash'    => wc_get_cart_item_data_hash( $free_product ),
				)
			),
			$free_cart_key
		);
	}

	/**
	 * Remove free product when the qualifying paid product is removed.
	 */
	public function bogo_handle_removed_product( $cart_item_key, $cart ) {
		if ( self::$bogo_processing ) {
			return;
		}

		$removed_item = isset( $cart->removed_cart_contents[ $cart_item_key ] ) ? $cart->removed_cart_contents[ $cart_item_key ] : null;
		if ( ! $removed_item || ! empty( $removed_item['bogo_x_x_free'] ) ) {
			return;
		}

		$product_id   = (int) $removed_item['product_id'];
		$variation_id = isset( $removed_item['variation_id'] ) ? (int) $removed_item['variation_id'] : 0;

		// Check if another paid item for the same product still exists.
		foreach ( $cart->get_cart() as $key => $item ) {
			if ( empty( $item['bogo_x_x_free'] ) &&
				(int) $item['product_id'] === $product_id &&
				( ! $variation_id || (int) $item['variation_id'] === $variation_id ) ) {
				return;
			}
		}

		// Remove associated free product directly from cart contents.
		foreach ( $cart->cart_contents as $key => $item ) {
			if ( ! empty( $item['bogo_x_x_free'] ) &&
				(int) $item['product_id'] === $product_id &&
				( ! $variation_id || (int) ( $item['variation_id'] ?? 0 ) === $variation_id ) ) {
				unset( $cart->cart_contents[ $key ] );
			}
		}
	}

	/**
	 * Update free product quantity when paid product quantity changes.
	 * The actual update is handled by add_coupon_automatically() during recalculation;
	 * this provides an immediate cart-contents update for responsiveness.
	 */
	public function bogo_handle_quantity_update( $cart_item_key, $quantity, $old_quantity, $cart ) {
		if ( self::$bogo_processing ) {
			return;
		}

		$cart_item = $cart->get_cart_item( $cart_item_key );
		if ( ! $cart_item || ! empty( $cart_item['bogo_x_x_free'] ) ) {
			return;
		}

		$product_id   = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
		$variation_id = isset( $cart_item['variation_id'] ) ? (int) $cart_item['variation_id'] : 0;
		$bogo_free    = $this->get_bogo_free_data( $product_id, $quantity );

		$free_key = $this->find_bogo_free_cart_item( $cart_item['product_id'], $variation_id );

		if ( ! $bogo_free ) {
			if ( $free_key ) {
				unset( $cart->cart_contents[ $free_key ] );
			}
			return;
		}

		if ( $free_key && isset( $cart->cart_contents[ $free_key ] ) ) {
			$cart->cart_contents[ $free_key ]['quantity'] = $bogo_free['free_qty'];
		}
	}

	/**
	 * Validate free products when cart is loaded from session (page reload / WC blocks).
	 * Ensures orphaned free items are removed and missing free items are added.
	 * The heavy lifting is done by add_coupon_automatically() during calculate_totals();
	 * this method handles early cleanup so the cart state is correct before rendering.
	 */
	public function bogo_validate_free_products( $cart ) {
		if ( self::$bogo_processing ) {
			return;
		}

		self::$bogo_processing = true;

		$paid_items    = array();
		$existing_free = array();

		foreach ( $cart->get_cart() as $key => $item ) {
			$product_id   = (int) $item['product_id'];
			$variation_id = isset( $item['variation_id'] ) ? (int) $item['variation_id'] : 0;
			$item_key     = $product_id . '_' . $variation_id;

			if ( ! empty( $item['bogo_x_x_free'] ) ) {
				$existing_free[ $item_key ] = $key;
			} else {
				$check_id  = $variation_id ? $variation_id : $product_id;
				$bogo_free = $this->get_bogo_free_data( $check_id, $item['quantity'] );
				if ( $bogo_free ) {
					$paid_items[ $item_key ] = array(
						'product_id'   => $product_id,
						'variation_id' => $variation_id,
						'variation'    => isset( $item['variation'] ) ? $item['variation'] : array(),
						'free_qty'     => $bogo_free['free_qty'],
					);
				}
			}
		}

		// Remove orphaned free items.
		foreach ( $existing_free as $item_key => $cart_key ) {
			if ( ! isset( $paid_items[ $item_key ] ) ) {
				unset( $cart->cart_contents[ $cart_key ] );
			} else {
				$cart->cart_contents[ $cart_key ]['quantity'] = $paid_items[ $item_key ]['free_qty'];
			}
		}

		// Add missing free items directly into cart contents.
		foreach ( $paid_items as $item_key => $data ) {
			if ( ! isset( $existing_free[ $item_key ] ) ) {
				$free_product = wc_get_product( $data['variation_id'] ? $data['variation_id'] : $data['product_id'] );
				if ( ! $free_product ) {
					continue;
				}

				$cart_item_data = array( 'bogo_x_x_free' => $data['free_qty'] );
				$free_cart_key  = $cart->generate_cart_id( $data['product_id'], $data['variation_id'], $data['variation'], $cart_item_data );

				$cart->cart_contents[ $free_cart_key ] = apply_filters(
					'woocommerce_add_cart_item',
					array_merge(
						$cart_item_data,
						array(
							'key'          => $free_cart_key,
							'product_id'   => $data['product_id'],
							'variation_id' => $data['variation_id'],
							'variation'    => $data['variation'],
							'quantity'     => $data['free_qty'],
							'data'         => $free_product,
							'data_hash'    => wc_get_cart_item_data_hash( $free_product ),
						)
					),
					$free_cart_key
				);
			}
		}

		self::$bogo_processing = false;
	}

	/**
	 * Store API cart item data callback for WC blocks.
	 *
	 * @param array $cart_item
	 * @return array
	 */
	public function bogo_store_api_cart_item_data( $cart_item ) {
		$is_free = ! empty( $cart_item['bogo_x_x_free'] ) || ! empty( $cart_item['bogo_x_y_free'] );
		$qty     = ! empty( $cart_item['bogo_x_x_free'] ) ? (int) $cart_item['bogo_x_x_free']
			: ( ! empty( $cart_item['bogo_x_y_free'] ) ? (int) $cart_item['bogo_x_y_free'] : 0 );
		return array(
			'is_bogo_free' => $is_free,
			'free_label'   => $is_free
				? esc_html__( 'Free', 'discountify' ) . ' ' . $qty . ' ' . esc_html__( 'Item', 'discountify' )
				: '',
		);
	}

	/**
	 * Store API cart item schema callback for WC blocks.
	 *
	 * @return array
	 */
	public function bogo_store_api_cart_item_schema() {
		return array(
			'is_bogo_free' => array(
				'description' => esc_html__( 'Whether this item is a BOGO free item.', 'discountify' ),
				'type'        => 'boolean',
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
			'free_label'   => array(
				'description' => esc_html__( 'BOGO free label text.', 'discountify' ),
				'type'        => 'string',
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
		);
	}

	/**
	 * Save BOGO meta when order is created via Store API (blocks checkout).
	 *
	 * @param \WC_Order                                                         $order
	 * @param \Automattic\WooCommerce\StoreApi\Routes\V1\CheckoutOrder $request
	 */
	public function bogo_store_api_order_meta( $order, $request ) {
		// Collect product IDs that are paid (not free) to avoid tagging them.
		$paid_product_keys = array();
		foreach ( WC()->cart->get_cart() as $cart_item ) {
			if ( empty( $cart_item['bogo_x_x_free'] ) && empty( $cart_item['bogo_x_y_free'] ) ) {
				$paid_product_keys[ $cart_item['product_id'] . '_' . ( $cart_item['variation_id'] ?? 0 ) ] = true;
			}
		}

		foreach ( WC()->cart->get_cart() as $cart_item ) {
			if ( ! empty( $cart_item['bogo_x_x_free'] ) || ! empty( $cart_item['bogo_x_y_free'] ) ) {
				$free_qty_remaining = (int) $cart_item['quantity'];
				foreach ( $order->get_items() as $item ) {
					if ( $free_qty_remaining <= 0 ) {
						break;
					}
					if ( $item->get_product_id() === $cart_item['product_id'] &&
						( empty( $cart_item['variation_id'] ) || $item->get_variation_id() === (int) $cart_item['variation_id'] ) &&
						! $item->get_meta( '_discountify_bogo_free' ) &&
						(float) $item->get_subtotal() == 0 ) {
						$item->add_meta_data( '_discountify_bogo_free', 'yes', true );
						$item->save();
						$free_qty_remaining -= $item->get_quantity();
					}
				}
			}
		}
	}

	/**
	 * Do not append badge to order item name — FREE is shown only in the Total column.
	 */
	public function bogo_order_item_name( $name, $item ) {
		return $name;
	}

	/**
	 * Replace line subtotal with FREE for BOGO free order items (line total = 0).
	 */
	public function bogo_order_line_subtotal( $subtotal, $item, $order ) {
		if ( $item instanceof \WC_Order_Item_Product && (float) $item->get_total() == 0 && $item->get_meta( '_discountify_bogo_free' ) === 'yes' ) {
			return '<span class="discountify-bogo-free-price">' . esc_html__( 'FREE', 'discountify' ) . '</span>';
		}
		return $subtotal;
	}

	/**
	 * Hide internal BOGO meta from admin order item display.
	 */
	public function bogo_hide_order_itemmeta( $hidden_meta ) {
		$hidden_meta[] = '_discountify_bogo_free';
		return $hidden_meta;
	}

	/**
	 * Inject inline CSS/JS in admin order page to show FREE for BOGO items.
	 */
	public function bogo_admin_order_styles( $order ) {
		?>
		<style>.discountify-bogo-free-price { color: #28a745 !important; font-weight: 700; }</style>
		<script>
		jQuery(function($){
			$('#order_line_items .item').each(function(){
				var $row = $(this);
				var total = parseFloat($row.find('.line_cost .woocommerce-Price-amount').first().text().replace(/[^\d.,]/g,'').replace(',','.'));
				if (total === 0 || isNaN(total)) {
					var $cost = $row.find('.line_cost');
					if ($cost.length) {
						$cost.find('.view').html('<span class="discountify-bogo-free-price">FREE</span>');
					}
					var $total = $row.find('.line_total');
					if ($total.length) {
						$total.find('.view').html('<span class="discountify-bogo-free-price">FREE</span>');
					}
				}
			});
		});
		</script>
		<?php
	}

	/**
	 * Apply buy_x_get_y (and category_bogo) discounts as a cart fee.
	 * When product X is in cart, product Y (also in cart) gets free/percentage/fixed discount.
	 */
	public function apply_buy_x_get_y_fee( $cart ) {
		if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
			return;
		}

		if ( $cart->is_empty() ) {
			return;
		}

		// Query all buy_x_get_y / category_bogo rules directly so that other rules
		// matching the same product (e.g. a flat % discount) don't shadow them.
		$all_rules = (array) \Discountify\Utils\Helper::get_all_rules();
		$xy_rules  = array();
		foreach ( $all_rules as $rule ) {
			if ( 'yes' !== ( $rule['enable_rules'] ?? '' ) ) {
				continue;
			}
			if ( ( $rule['rules_type'] ?? '' ) !== 'bogo' ) {
				continue;
			}
			if ( ! in_array( $rule['bogo_discount_type'] ?? '', array( 'buy_x_get_y', 'category_bogo' ), true ) ) {
				continue;
			}
			if ( ! $this->discount_period( $rule ) ) {
				continue;
			}
			if ( ! $this->role_base_discount( $rule ) ) {
				continue;
			}
			$xy_rules[] = $rule;
		}

		if ( empty( $xy_rules ) ) {
			return;
		}

		$total_discount  = 0;
		$discount_label  = esc_html__( 'Offer', 'discountify' );
		$cart_items      = $cart->get_cart();
		$discounted_keys = array();

		foreach ( $xy_rules as $rule ) {
			// Find the first cart item that qualifies as the X trigger for this rule.
			$x_item     = null;
			$x_item_key = null;

			foreach ( $cart_items as $ckey => $cart_item ) {
				if ( ! empty( $cart_item['bogo_x_x_free'] ) || ! empty( $cart_item['bogo_x_y_free'] ) ) {
					continue;
				}

				$product_id = ! empty( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : $cart_item['product_id'];
				$parent_id  = (int) $cart_item['product_id'];
				$discount_in = $rule['discount_in'] ?? '';

				$is_x = false;
				if ( 'all' === $discount_in ) {
					$is_x = true;
				} elseif ( 'product' === $discount_in ) {
					$is_x = \Discountify\Utils\Helper::discount_product( $product_id, $rule['filter_by_products'] ?? array() )
						|| \Discountify\Utils\Helper::discount_product( $parent_id, $rule['filter_by_products'] ?? array() );
				} elseif ( 'category' === $discount_in ) {
					$is_x = \Discountify\Utils\Helper::discount_category( $parent_id, $rule['filter_by_category'] ?? array() );
				}

				if ( $is_x ) {
					$x_item     = $cart_item;
					$x_item_key = $ckey;
					break;
				}
			}

			if ( null === $x_item ) {
				continue;
			}

			$x_product_id = ! empty( $x_item['variation_id'] ) ? $x_item['variation_id'] : $x_item['product_id'];
			$x_product    = wc_get_product( $x_product_id );
			if ( ! $x_product ) {
				continue;
			}

			$bogo_data = $this->multi_discount_type( $rule, $x_item['quantity'], $x_product->get_price() );

			if ( empty( $bogo_data['offer_type'] ) ) {
				continue;
			}

			$y_products = $this->get_bogo_products( $rule['bogo_discount_in'] ?? 'product', $bogo_data );

			if ( empty( $y_products ) ) {
				continue;
			}

			$offer_type      = $bogo_data['offer_type'];
			$discount_number = isset( $bogo_data['discount_number'] ) && $bogo_data['discount_number'] !== '' ? (float) $bogo_data['discount_number'] : 0;
			$free_qty        = isset( $bogo_data['free_quantity'] ) && $bogo_data['free_quantity'] !== '' ? (int) $bogo_data['free_quantity'] : 0;
			$all_y           = in_array( 'all', (array) $y_products, true );
			$y_product_ids   = $all_y ? array() : array_map( 'intval', (array) $y_products );

			if ( ! empty( $rule['discount_label'] ) ) {
				$discount_label = $rule['discount_label'];
			}

			foreach ( $cart_items as $y_key => $y_item ) {
				if ( ! empty( $y_item['bogo_x_x_free'] ) || ! empty( $y_item['bogo_x_y_free'] ) ) {
					continue;
				}

				if ( isset( $discounted_keys[ $y_key ] ) ) {
					continue;
				}

				$y_pid      = (int) $y_item['product_id'];
				$y_vid      = isset( $y_item['variation_id'] ) ? (int) $y_item['variation_id'] : 0;
				$y_check_id = $y_vid ?: $y_pid;

				if ( ! $all_y && ! in_array( $y_pid, $y_product_ids, true ) && ! in_array( $y_check_id, $y_product_ids, true ) ) {
					continue;
				}

				// Don't discount X when X and Y are the same cart item.
				$x_pid = (int) $x_item['product_id'];
				$x_vid = isset( $x_item['variation_id'] ) ? (int) $x_item['variation_id'] : 0;
				if ( $y_pid === $x_pid && $y_vid === $x_vid && $y_key === $x_item_key ) {
					continue;
				}

				$y_price = (float) $y_item['data']->get_price();
				$y_qty   = (int) $y_item['quantity'];

				switch ( $offer_type ) {
					case 'free':
						$applicable_qty  = $free_qty > 0 ? min( $free_qty, $y_qty ) : $y_qty;
						$total_discount += $y_price * $applicable_qty;
						break;
					case 'percentage':
						$total_discount += $y_price * $y_qty * ( $discount_number / 100 );
						break;
					case 'fixed':
						$applicable_qty  = $free_qty > 0 ? min( $free_qty, $y_qty ) : $y_qty;
						$total_discount += min( $discount_number * $applicable_qty, $y_price * $y_qty );
						break;
				}

				$discounted_keys[ $y_key ] = true;
			}
		}

		if ( $total_discount > 0 ) {
			$cart->add_fee( $discount_label, -$total_discount );
		}
	}

} // End Frontend class