<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class Dspilot_Pricing_Discount {

    private $plugin_options = array();
    public $discounts = array();

    public function __construct() {
       $this->plugin_options = Dspilot_Plugin::get_plugin_options();
       $this->discounts = Dspilot_Plugin::get_discounts('pricing_discounts');
       
        // constructor / init
        if(!is_admin()){
            
            add_filter( 'woocommerce_get_price_html', [ $this, 'filter_price_html' ], 999, 2 );
            add_filter( 'woocommerce_product_get_price', [ $this, 'filter_product_price' ], 999, 2 );
            add_filter( 'woocommerce_product_get_regular_price', [ $this, 'filter_product_regular_price' ], 999, 2 );
            add_filter( 'woocommerce_product_get_sale_price', [ $this, 'filter_product_sale_price' ], 10, 2 );



            //add_filter( 'woocommerce_product_variation_get_price', [ $this, 'filter_product_price' ], 999, 2 );
            // add_filter( 'woocommerce_product_variation_get_regular_price', [ $this, 'filter_product_regular_price' ], 999, 2 );
            // add_filter( 'woocommerce_product_variation_get_sale_price', [ $this, 'filter_product_sale_price' ], 999, 2 );

            // variation prices arrays (3 args!)
            //add_filter( 'woocommerce_variation_prices_price', [ $this, 'filter_variation_prices_price' ], 10, 3 );
            // add_filter( 'woocommerce_variation_prices_regular_price', [ $this, 'filter_variation_prices_regular_price' ], 10, 3 );
            // add_filter( 'woocommerce_variation_prices_sale_price', [ $this, 'filter_variation_prices_sale_price' ], 10, 3 );

            // cart
            add_action( 'woocommerce_before_calculate_totals', [ $this, 'apply_discount_in_cart' ], 20, 1 );
            add_action( 'woocommerce_before_calculate_totals', [$this, 'bogo_cleanup_orphans'], 5 );


            add_action( 'woocommerce_after_cart_item_quantity_update', [ $this, 'reset_applied_discounts_after_qty' ], 10, 3 );
            add_action( 'woocommerce_add_to_cart', [ $this, 'reset_applied_discounts_add_to_cart' ], 10, 6 );
            add_action( 'woocommerce_cart_item_removed', [ $this, 'reset_applied_discounts_removed' ], 10, 2 );
            add_action( 'woocommerce_checkout_update_order_review', [ $this, 'reset_applied_discounts_checkout' ], 10, 1 );



            
            // Ensure BOGO prices stick
            add_action( 'woocommerce_before_calculate_totals', [ $this, 'apply_bogo_prices' ], 99999, 1 );
            add_filter( 'woocommerce_get_cart_item_from_session', [ $this, 'restore_bogo_prices_from_session' ], 20, 3 );
            
            // Override price filters
            add_filter( 'woocommerce_product_get_price', [ $this, 'enforce_bogo_product_price' ], 10000, 2 );
            add_filter( 'woocommerce_product_get_sale_price', [ $this, 'enforce_bogo_product_price' ], 10000, 2 );
            add_filter( 'woocommerce_product_get_regular_price', [ $this, 'enforce_bogo_product_price' ], 10000, 2 );
            add_action( 'woocommerce_before_calculate_totals', [ $this, 'sanitize_cart_items' ], 1 );
            
            // Clean session to prevent warnings
            add_action( 'wp_loaded', [ $this, 'cleanup_session_garbage' ], 10 );

        }
    }


    public function reset_applied_discounts_after_qty( $cart_item_key, $buy_qty, $old_quantity ) {
        $this->clear_transients();
    }

    public function reset_applied_discounts_add_to_cart( $cart_item_key, $product_id, $buy_qty, $variation_id, $variation, $cart_item_data ) {
        $this->clear_transients();
    }

    public function reset_applied_discounts_removed( $cart_item_key, $cart ) {
        $this->clear_transients();
    }

    public function reset_applied_discounts_checkout( $post_data ) {
        $this->clear_transients();
    }

    private function clear_transients() {
        if ( ! WC()->cart ) return;
        $cart = WC()->cart->get_cart();
        foreach ( $cart as $cart_item ) {
            if ( isset( $cart_item['product_id'] ) ) {
                wc_delete_product_transients( $cart_item['product_id'] );
            }
        }
    }

    public function filter_price_html( $price_html, $product ) {
        if ( is_admin() && ! wp_doing_ajax() ) return $price_html;
        if ( ! $product instanceof WC_Product ) return $price_html;
        if ( ! $this->is_targeted_product( $product ) ) return $price_html;

        $regular_price = (float) $product->get_regular_price();
        $sale_price    = (float) $product->get_sale_price();
        $price         = (float) $product->get_price();


        if ( $regular_price > 0 ) {

            // If product has no sale price → show discounted price as sale
            if ( empty( $sale_price ) ) {
                $discounted_price = $this->calculate_discounted_price_from_base( $regular_price, $product );
                $price_html = wc_format_sale_price( wc_price( $regular_price ), wc_price( $discounted_price ) );
            }
            // If already has sale price → just show sale vs discounted
            else {
                $discounted_price = $discounted_price = $this->calculate_discounted_price_from_base( $sale_price, $product );
                $price_html = wc_format_sale_price( wc_price( $regular_price ), wc_price( $discounted_price ) );
            }
        }

        // check if product type is varable

        if($product->is_type('variable')) {
            $prices = $product->get_variation_prices( true );
            if ( empty( $prices['price'] ) ) {
                return $price_html;
            }
            $min_price = current( $prices['price'] );
            $max_price = end( $prices['price'] );
            $regular_min_price = current( $prices['regular_price'] );
            $regular_max_price = end( $prices['regular_price'] );

            $discounted_min_price = $this->calculate_discounted_price_from_base( $min_price, $product );
            $discounted_max_price = $this->calculate_discounted_price_from_base( $max_price, $product );


            $old_price_html = sprintf( '<del>%s - %s</del>', wc_price( $regular_min_price ), wc_price( $regular_max_price ) );

            if(array_intersect([$regular_min_price, $regular_max_price], [$discounted_min_price, $discounted_max_price])) {
                // if min or max price is same as discounted price, don't show old price
                $old_price_html = '';
            }

            if ( $min_price !== $max_price ) {
             
                $price_html = sprintf( '%s %s - %s', $old_price_html, wc_price( $discounted_min_price ), wc_price( $discounted_max_price ) );
            } else {
                
                $price_html = $old_price_html . wc_price( $discounted_min_price );
            }
        }

        return $price_html;
    }


    private function is_targeted_product( WC_Product $product ) {
        $discounted_product_ids = (array) $this->get_discounted_products();
        if ( empty( $discounted_product_ids ) ) {
            return false;
        }

        $ids = [ $product->get_id() ];
        if ( $product->is_type( 'variation' ) ) {
            $ids[] = $product->get_parent_id();
        }

        return (bool) array_intersect( $ids, $discounted_product_ids );
    }

    public function calculate_discounted_price_from_base( $base_price, $product = null, $buy_qty = null ) {
        $price = floatval( $base_price );
        if ( $price <= 0 ) {
            return $price;
        }

        
        
        foreach ( $this->discounts as $discount ) {

            if( empty( $discount ) || ! isset( $discount['mode']) ) {
                continue;
            }
            
            $discount_mode = $discount['mode'] ?? 'simple'; // default to simple if not set

            if ($discount_mode == 'simple' && empty( $discount['amount'] ) ) {
                continue;
            }


            $quantity_count_based = $discount['quantity_based'] ?? 'single_product';

            if($discount_mode == 'simple') {
                // Simple discount mode
                if ( $discount['type'] === 'percentage' ) {
                    $price -= ( $price * ( floatval( $discount['amount'] ) / 100 ) );
                } elseif ( $discount['type'] === 'fixed' ) {
                    $price = max( 0, $price - floatval( $discount['amount'] ) );
                }
            }
            
            else {
                // $price = apply_filters( 'dspilot_pricing_discount_calculate_price', $price, $discount, $product, $buy_qty );
                
                if ( $discount_mode == 'bulk' ) {
                    $price = apply_filters( 'dspilot_pricing_discount_calculate_bulk_price', $price, $discount, $product, $buy_qty );
                }
                else if ( $discount_mode === 'bundle' ) {

                    if ( ! empty( $discount['bundle_amounts'] ) && is_array( $discount['bundle_amounts'] ) ) {

                        if($buy_qty === null || $buy_qty <= 0 ) {
                            // get quantity from cart if not provided
                            $cart = WC()->cart;
                            $buy_qty = 0;
                            foreach ( $cart->get_cart() as $cart_item ) {
                                if ( $cart_item['product_id'] === $product->get_id() || ( $product->is_type( 'variation' ) && $cart_item['variation_id'] === $product->get_id() ) ) {
                                    $buy_qty += $cart_item['quantity'];
                                }
                            }
                        }

                        // Choose the single best matching rule: highest quantity <= cart quantity
                        $applicable = array_filter( $discount['bundle_amounts'], function( $r ) use ( $buy_qty ) {
                            return isset( $r['quantity'], $r['amount'], $r['type'] ) && $buy_qty >= intval( $r['quantity'] );
                        });

                        if ( empty( $applicable ) ) continue;

                        usort( $applicable, function( $a, $b ) {
                            return intval( $b['quantity'] ) <=> intval( $a['quantity'] );
                        });

                        $rule         = $applicable[0]; // best match only
                        $bundle_size  = intval( $rule['quantity'] );
                        $bundle_count = (int) floor( $buy_qty / $bundle_size );
                        $eligible_qty = $bundle_count * $bundle_size;
                        $leftover_qty = max( 0, $buy_qty - $eligible_qty );

                        $original = (float) $price; // base per-item price before applying this rule

                        // Apply exactly one rule
                        if ( $rule['type'] === 'percentage_discount_per_item' ) {
                            // Per-item percentage off
                            $price = $original * ( 1 - (float) $rule['amount'] / 100 );

                        } elseif ( $rule['type'] === 'fixed_discount_per_item' ) {
                            // Per-item fixed off
                            $price = max( 0, $original - (float) $rule['amount'] );

                        } elseif ( $rule['type'] === 'percentage_discount_per_bundle' ) {
                            // Percentage off the bundle total; average across the whole line
                            $bundle_total        = $bundle_size * $original;
                            $discounted_bundle   = $bundle_total * ( 1 - (float) $rule['amount'] / 100 );
                            $new_total           = $bundle_count * $discounted_bundle + $leftover_qty * $original;
                            $price               = $new_total / $buy_qty;

                        } elseif ( $rule['type'] === 'fixed_discount_per_bundle' ) {
                            // Fixed off per bundle; average across the whole line
                            $total_before = $buy_qty * $original;
                            $new_total    = max( 0, $total_before - $bundle_count * (float) $rule['amount'] );
                            $price        = $new_total / $buy_qty;

                        } elseif ( $rule['type'] === 'fixed_price_per_bundle' ) {
                            // Fixed price for each full bundle; leftover stays at original
                            $new_total = $bundle_count * (float) $rule['amount'] + $leftover_qty * $original;
                            $price     = $new_total / $buy_qty;

                        } elseif ( $rule['type'] === 'fixed_price_per_item' ) {
                            // Apply fixed price only to eligible bundle qty, leftover at original price
                            $bundle_size  = intval( $rule['quantity'] );
                            $bundle_count = (int) floor( $buy_qty / $bundle_size );
                            $eligible_qty = $bundle_count * $bundle_size;
                            $leftover_qty = max( 0, $buy_qty - $eligible_qty );

                            $total = ($eligible_qty * (float) $rule['amount']) + ($leftover_qty * $original);
                            $price = $total / $buy_qty; // per-item average price
                        }
                    }
                }
            }
        }

            return round( (float) $price, wc_get_price_decimals() );
        }

    /** regular price filter (uses stored regular_price) */
    public function filter_product_regular_price( $price, $product ) {
        if ( is_admin() && ! wp_doing_ajax() ) return $price;
        if ( ! $product instanceof WC_Product ) return $price;
        if ( ! $this->is_targeted_product( $product ) ) return $price;

        $data = $product->get_data();
        $regular = isset( $data['regular_price'] ) ? $data['regular_price'] : '';
        $sale = isset( $data['sale_price'] ) ? $data['sale_price'] : '';

        
        if ( $regular === '' || $regular === null ) return $price;

        if( $sale !== '' && $sale !== null ) {
            // if sale price is set, return the regular price
            return $this->calculate_discounted_price_from_base( $regular, $product );
        }
        
        return $price; // no sale price, return unchanged
    }

    /** sale price filter (uses stored sale_price) */
    public function filter_product_sale_price( $price, $product ) {
        if ( is_admin() && ! wp_doing_ajax() ) return $price;
        if ( ! $product instanceof WC_Product ) return $price;
        if ( ! $this->is_targeted_product( $product ) ) return $price;

        $data = $product->get_data();
        $sale = isset( $data['sale_price'] ) ? $data['sale_price'] : '';

        if ( $sale === '' || $sale === null ) {
            // nothing to discount (no sale defined) — return unchanged
            return $price;
        }

        return $this->calculate_discounted_price_from_base( $sale, $product );
    }

    /** get_price filter — show discounted sale if exists otherwise discounted regular */
    public function filter_product_price( $price, $product ) {
        if ( is_admin() && ! wp_doing_ajax() ) return $price;
        if ( ! $product instanceof WC_Product ) return $price;
        if ( ! $this->is_targeted_product( $product ) ) return $price;

        $data = $product->get_data();
        $sale = isset( $data['sale_price'] ) ? $data['sale_price'] : '';
        $regular = isset( $data['regular_price'] ) ? $data['regular_price'] : '';

        $base = ( $sale !== '' && $sale !== null ) ? $sale : $regular;
        if ( $base === '' || $base === null ) return $price;

        $discounted_price = $this->calculate_discounted_price_from_base( $base, $product );

        return $discounted_price;
    }

    /** variation array filters (3 args) */
    public function filter_variation_prices_price( $price, $variation, $product ) {
        $variation_obj = is_object( $variation ) ? $variation : wc_get_product( $variation );
        if ( ! $variation_obj instanceof WC_Product ) return $price;
        return $this->filter_product_price( $price, $variation_obj );
    }
    
    public function filter_variation_prices_regular_price( $price, $variation, $product ) {
        $variation_obj = is_object( $variation ) ? $variation : wc_get_product( $variation );
        if ( ! $variation_obj instanceof WC_Product ) return $price;
        return $this->filter_product_regular_price( $price, $variation_obj );
    }
    public function filter_variation_prices_sale_price( $price, $variation, $product ) {
        $variation_obj = is_object( $variation ) ? $variation : wc_get_product( $variation );
        if ( ! $variation_obj instanceof WC_Product ) return $price;
        return $this->filter_product_sale_price( $price, $variation_obj );
    }

    /** cart adjustments */
    public function apply_discount_in_cart( $cart ) {
        if ( is_admin() && ! wp_doing_ajax() ) return;
        if ( did_action( 'woocommerce_before_calculate_totals' ) > 1 ) return;

        $discounted_product_ids = (array) $this->get_discounted_products();
        if ( empty( $discounted_product_ids ) ) return;

        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            if ( empty( $cart_item['data'] ) || ! $cart_item['data'] instanceof WC_Product ) continue;
            $product = $cart_item['data'];
            if ( ! $this->is_targeted_product( $product ) ) continue;

            
            $data    = $product->get_data();
            $product_id = $product->get_id();
            $sale    = isset( $data['sale_price'] ) ? $data['sale_price'] : '';
            $regular = isset( $data['regular_price'] ) ? $data['regular_price'] : '';
            $base = ( $sale !== '' && $sale !== null ) ? $sale : $regular;
            if ( $base === '' || $base === null ) continue;

            $new_price = $this->calculate_discounted_price_from_base( $base, $product );
            if ( $new_price !== (float) $product->get_price() ) {
                $product->set_price( $new_price );
                $cart->cart_contents[ $cart_item_key ]['data'] = $product;
            }

            // set bogo discount
            $this->set_bogo_discount($cart, $product, $base);
        }
    }

    public function evaluate_product_filter_conditions($conditions, $product_id = null) {

        if (empty($conditions) || !is_array($conditions)) {
            return true;
        }

        $condition_result = [];
        $x = 0;

        foreach ($conditions as $condition) {

            $x++;
            $type = $condition['condition'] ?? '';
            $compare = $condition['condition_compare'] ?? 'equal_to';

            if (in_array($type, ['variations'])) {
                $value = $condition['variation_ids'] ?? [];
            } elseif (in_array($type, ['categories'])) {
                $value = $condition['category_ids'] ?? [];
            } elseif (in_array($type, ['brands'])) {
                $value = $condition['brand_ids'] ?? [];
            } elseif (in_array($type, ['attributes'])) {
                $value = $condition['attribute_ids'] ?? [];
            } elseif (in_array($type, ['regular_price', 'stock_quantity'])) {
                $value = $condition['number'];
            } elseif (in_array($type, ['product_meta'])) {
                $value = $condition['meta_value'] ?? '';
            } elseif (in_array($type, ['is_featured', 'is_onsale', 'is_trending'])) {
                $value = $product_id;
            } else {
                $value = $condition['text'] ?? '';
            }

            $value = is_array($value) ? $value : (is_numeric($value) ? floatval($value) : sanitize_text_field($value));
        
            $target = null;

            switch ($type) {
                case 'products':
                    $target = $product_id;
                    break;
                case 'variations':
                    $target = Dspilot_Helper::get_product_variations($product_id, 'ids');
                    break;
                case 'categories':
                    $target = Dspilot_Helper::get_taxonomy_ids_by_product_id($product_id, 'product_cat');
                    break;
                case 'brands':
                    $target = Dspilot_Helper::get_taxonomy_ids_by_product_id($product_id, 'product_brand');
                    break;
                case 'regular_price':
                    $target = Dspilot_Helper::get_product_price($product_id, true);
                    if(is_array($target)) {
                        $target = $target['min'] ?? 0;
                    }
                    break;
                case 'stock_quantity':
                    $target = Dspilot_Helper::get_product_stock_quantity($product_id);
                    break;
                case 'meta':
                    $target = Dspilot_Helper::get_product_meta_value($product_id, $condition['meta_key'] ?? '');
                    break;
                case 'is_featured':
                    $target = Dspilot_Helper::get_all_product_ids([], true);
                    break;
                case 'is_onsale':
                    $target = Dspilot_Helper::get_all_product_ids([], false, true);
                    break;
                case 'is_trending':
                    $target = Dspilot_Helper::get_trending_product_ids();
                    break;
                default:
                    do_action('dspilot_custom_product_filter_condition_fallback', $type, $compare, $value);
                    break;
            }

            // If any one condition is false, return false immediately
            if (! Dspilot_Helper::evaluate_condition_compare($target, $compare, $value)) {
                return false;
            }
            
        }
        return true;
    }

    /**
     * Get discounted products based on the plugin options and conditions
     *
     * @return array
     */
    public function get_discounted_products() {
        $discount = $this->discounts;

        // // Remove discounts not related to pricing
        // foreach ($discount as $key => $value) {
        //     if (!empty($value['discount_apply_type']) && $value['discount_apply_type'] !== 'pricing') {
        //         unset($this->discounts[$key]);
        //     }
        // }

        // if (empty($this->discounts)) {
        //     return [];
        // }

        $filtered_products = [];

        foreach ($this->discounts as $discount) {

                    
            // ✅ Conditions fallback
            $condition_groups = ! empty( $discount['condition_groups'] ) ? $discount['condition_groups'] : [];

            if ( $this->evaluate_discount_condition_groups( $condition_groups ) == false ) {
                //continue;
            }

            
            if (empty($discount['products'])) {
                //continue;
            }

            $products = $discount['products'];

            if(in_array('all_products', $products)) {
                // all products
                $products = Dspilot_Helper::get_all_product_ids();
            }

            if(!empty($discount['products_filter']) && is_array($discount['products_filter'])) {
                foreach ($products as $product_id) {
                    $result = $this->evaluate_product_filter_conditions($discount['products_filter'], $product_id);

                    if ($result) {
                        $filtered_products[] = $product_id;
                    }
                }
            }else {
                $filtered_products = array_merge($filtered_products, $products);
            }

            
        }

        return $filtered_products;
    }


    /**
     * Set BOGO discount for same product (works with variable products).
     *
     * Replace your existing method with this. Assumes $this->discounts exists.
     *
     * @param WC_Cart $cart
     * @param WC_Product $product   // current product object (can be variation)
     * @param float $base_price    // unit base price
     */
    function set_bogo_discount( $cart, $product, $base_price ) {
        
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
            return;
        }

        if ( ! $cart || ! method_exists( $cart, 'get_cart' ) ) {
            return;
        }

        // RE-ENTRY GUARD
        static $running = false;
        if ( $running ) {
            return;
        }
        $running = true;

        $discounts = $this->discounts;

        // product ids
        $current_id   = (int) $product->get_id();
        $is_variation = $product->is_type( 'variation' );
        $parent_id    = $is_variation ? (int) $product->get_parent_id() : $current_id;

        $price = floatval( $base_price );
        if ( $price <= 0 ) {
            $running = false;
            return;
        }

        // --- 1) count paid qty for this product (count all variations under same parent)
        $paid_qty = 0;
        $rep_variation_id = 0;     // representative variation to use when adding free item
        $rep_variation     = array();
        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            // skip already-added free items (we don't count them as paid)
            if ( ! empty( $cart_item['dspilot_bogo_free'] ) ) {
                continue;
            }

            // cart stores product_id = parent id and variation_id (0 or variation id)
            if ( isset( $cart_item['product_id'] ) && (int) $cart_item['product_id'] === $parent_id ) {
                $paid_qty += (int) $cart_item['quantity'];

                // capture one variation's info to reuse when adding free item (if needed)
                if ( $rep_variation_id === 0 && ! empty( $cart_item['variation_id'] ) ) {
                    $rep_variation_id = (int) $cart_item['variation_id'];
                    $rep_variation = isset( $cart_item['variation'] ) ? (array) $cart_item['variation'] : array();
                }
            }
        }

        // nothing bought -> nothing to do
        if ( $paid_qty <= 0 ) {
            $running = false;
            return;
        }

        // --- 2) parse discounts and find matching BOGO rule
        $needed_free = 0;
        $discount_unit_price = $price; // final unit price for discounted/free items (could be 0)
        $discounted_product_id = $parent_id; // where to add free item (may be variation id or parent id)

        if ( ! empty( $discounts ) && is_array( $discounts ) ) {
            foreach ( $discounts as $discount ) {

                if ( ! $this->check_discount_validity( $discount, $product ) ) {
                    continue;
                }

                if ( empty( $discount ) || empty( $discount['mode'] ) ) {
                    continue;
                }

                $discount_mode = $discount['mode'];

                if ( $discount_mode !== 'buy_x_get_x' && $discount_mode !== 'buy_x_get_y' ) {
                    continue;
                }

                // choose the right bogo rule array from config
                $bogo_rules = array();
                if ( $discount_mode === 'buy_x_get_x' ) {
                    $bogo_rules = ! empty( $discount['bogo_discounts_x_x'] ) && is_array( $discount['bogo_discounts_x_x'] ) ? $discount['bogo_discounts_x_x'] : array();
                } else {
                    $bogo_rules = ! empty( $discount['bogo_discounts_x_y'] ) && is_array( $discount['bogo_discounts_x_y'] ) ? $discount['bogo_discounts_x_y'] : array();
                }

                // if buy_x_get_y and a specific Y product is set, use that id (may be variation id or parent)
                if ( $discount_mode === 'buy_x_get_y' && ! empty( $discount['bogo_y_product'] ) ) {
                    $discounted_product_id = (int) $discount['bogo_y_product'];
                } else {
                    $discounted_product_id = $parent_id;
                }

                // iterate rules to find a matching one based on paid_qty range
                if ( ! empty( $bogo_rules ) ) {
                    foreach ( $bogo_rules as $rule ) {
                        $min_q = isset( $rule['minimum_quantity'] ) ? intval( $rule['minimum_quantity'] ) : 0;
                        $max_q = isset( $rule['maximum_quantity'] ) ? intval( $rule['maximum_quantity'] ) : 0; // 0 = no upper limit
                        $d_qty = isset( $rule['discount_quantity'] ) ? intval( $rule['discount_quantity'] ) : 0;

                        if ( $min_q <= 0 || $d_qty <= 0 ) {
                            continue;
                        }

                        if ( $paid_qty >= $min_q && ( $max_q === 0 || $paid_qty <= $max_q ) ) {
                            // how many sets of the trigger do we have?
                            $sets = floor( $paid_qty / $min_q );
                            $needed_free = $sets * $d_qty;

                            // compute unit price for the discounted/free items according to rule
                            $amount = isset( $rule['amount'] ) ? floatval( $rule['amount'] ) : 0;
                            $type   = isset( $rule['type'] ) ? $rule['type'] : 'fixed';

                            if ( $type === 'percentage' && $amount > 0 ) {
                                $discount_unit_price = max( 0, $price - ( $price * ( $amount / 100 ) ) );
                            } elseif ( $type === 'fixed' && $amount > 0 ) {
                                $discount_unit_price = max( 0, $price - $amount );
                            } elseif ( $amount > 0 ) {
                                // absolute price set
                                $discount_unit_price = $amount;
                            } else {
                                // if no amount provided, assume FREE
                                $discount_unit_price = 0;
                            }

                            // we found a matching rule — stop searching further rules/discounts
                            break 2;
                        }
                    }
                }
            }
        }

        // nothing to grant
        if ( $needed_free <= 0 ) {
            // also remove any existing free lines for this parent/variation (cleanup)
            foreach ( $cart->cart_contents as $k => $ci ) {
                if ( ! empty( $ci['dspilot_bogo_free'] ) ) {
                    $trigger_id = isset( $ci['dspilot_bogo_parent_id'] ) ? (int) $ci['dspilot_bogo_parent_id'] : 0;
                    if ( $trigger_id === $current_id || ( $parent_id && $trigger_id === $parent_id ) ) {
                        $cart->remove_cart_item( $k );
                    }
                }
            }

            $running = false;
            return;
        }


        // --- 3) Prepare add_to_cart parameters for discounted_product_id (handle variation)
        $add_parent_id = $parent_id;
        $add_variation_id = 0;
        $add_variation = array();

        $maybe_prod = wc_get_product( $discounted_product_id );
        if ( $maybe_prod ) {
            if ( $maybe_prod->is_type( 'variation' ) ) {
                $add_variation_id = (int) $discounted_product_id;
                $add_parent_id = (int) $maybe_prod->get_parent_id();
                // variation attributes (attribute_pa_x => value). Good to reuse.
                $add_variation = (array) $maybe_prod->get_variation_attributes();
            } else {
                // discounted_product_id refers to parent (simple or variable)
                $add_parent_id = (int) $discounted_product_id;
            }
        } else {
            // fallback: if we captured a representative variation from cart, reuse that
            if ( $rep_variation_id > 0 ) {
                $add_variation_id = $rep_variation_id;
                $add_parent_id = $parent_id;
                $add_variation = $rep_variation;
            } else {
                $add_parent_id = $parent_id;
            }
        }

        // --- 4) Find existing free cart line that matches the same parent + variation (if any)
        $existing_free_key = false;
        foreach ( $cart->cart_contents as $k => $ci ) {

            if ( empty( $ci['dspilot_bogo_free'] ) ) {
                continue;
            }
            // match by variation if this free line has same variation id, otherwise match by product parent id
            $ci_var_id = isset( $ci['variation_id'] ) ? (int) $ci['variation_id'] : 0;
            if ( $add_variation_id > 0 ) {
                if ( $ci_var_id === $add_variation_id ) {
                    $existing_free_key = $k;
                    break;
                }
            } else {
                if ( isset( $ci['product_id'] ) && (int) $ci['product_id'] === $add_parent_id ) {
                    $existing_free_key = $k;
                    break;
                }
            }
        }

        $target_key = false;

        // Add / update / remove free line as needed
        if ( $existing_free_key !== false ) {
            $target_key = $existing_free_key;
            // update quantity only if differs
            $current_qty = isset( $cart->cart_contents[ $target_key ]['quantity'] ) ? (int) $cart->cart_contents[ $target_key ]['quantity'] : 0;
            if ( $current_qty !== (int) $needed_free ) {
                $cart->set_quantity( $target_key, (int) $needed_free, false );
            }
            // Update the stored price meta for the existing item, so subsequent calcs pick it up
            $cart->cart_contents[ $target_key ]['dspilot_bogo_price'] = (float) $discount_unit_price;
            
        } else {
            // add free product line (with meta to identify it and store price).
            $bogo_parent_id = $current_id;
            if ( $add_variation_id > 0 ) {
                $bogo_parent_id = $add_variation_id;
                $target_key = $cart->add_to_cart( $add_parent_id, (int) $needed_free, $add_variation_id, $add_variation, array( 'dspilot_bogo_free' => true, 'dspilot_bogo_parent_id' => $bogo_parent_id, 'dspilot_bogo_price' => (float) $discount_unit_price ) );
            } else {
                $target_key = $cart->add_to_cart( $add_parent_id, (int) $needed_free, 0, array(), array( 'dspilot_bogo_free' => true, 'dspilot_bogo_parent_id' => $bogo_parent_id, 'dspilot_bogo_price' => (float) $discount_unit_price ) );
            }
        }

        // --- 5) Ensure free item unit price set according to rule (Immediate for current cycle)
        if ( $target_key && isset( $cart->cart_contents[ $target_key ] ) ) {
             // Directly update the object in cart_contents
             $cart->cart_contents[ $target_key ]['data']->set_price( (float) $discount_unit_price );
        }

        // done
        $running = false;
    }

    /**
     * Check if discount is valid for specific product
     */
    private function check_discount_validity( $discount, $product ) {
         // 1. Check Condition Groups
         $condition_groups = ! empty( $discount['condition_groups'] ) ? $discount['condition_groups'] : [];
         if ( ! $this->evaluate_discount_condition_groups( $condition_groups ) ) {
             return false;
         }

         // 2. Check Product Eligibility
         if ( empty( $discount['products'] ) ) return false;
         $products_list = $discount['products'];
         
         $product_id = $product->get_id();
         $parent_id = $product->get_parent_id();
         
         $is_in_list = false;
         if ( in_array( 'all_products', $products_list ) ) {
             $is_in_list = true;
         } else {
             if ( in_array( $product_id, $products_list ) ) $is_in_list = true;
             if ( $parent_id && in_array( $parent_id, $products_list ) ) $is_in_list = true;
         }

         // 3. Check Product Filter
         if ( ! empty( $discount['products_filter'] ) && is_array( $discount['products_filter'] ) ) {
             if ( ! $this->evaluate_product_filter_conditions( $discount['products_filter'], $product_id ) ) {
                 return false; 
             }
         } else {
             if ( ! $is_in_list ) return false;
         }

         return true;
    }

    /**
     * Remove orphan BOGO free items when parent products are removed.
     */
    function bogo_cleanup_orphans() {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;

        $cart = WC()->cart;
        if ( ! $cart || ! method_exists( $cart, 'get_cart' ) ) return;

        // count paid quantity by parent product id
        $paid_counts = array();
        foreach ( $cart->get_cart() as $key => $item ) {
            if ( ! empty( $item['dspilot_bogo_free'] ) ) {
                continue;
            }

            $pid = (int) $item['product_id'];
            $pid = !empty($item['variation_id']) ? $item['variation_id'] : $pid; 

            if ( ! isset( $paid_counts[ $pid ] ) ) {
                $paid_counts[ $pid ] = 0;
            }

            $paid_counts[ $pid ] += (int) $item['quantity'];
        }

        // now remove free items whose parent no longer exists
        foreach ( $cart->get_cart() as $key => $item ) {
            if ( empty( $item['dspilot_bogo_free'] ) ) {
                continue;
            }

            $parent_id = (int) $item['dspilot_bogo_parent_id'];

            // if there is no paid quantity for this parent, remove it
            if ( empty( $paid_counts[ $parent_id ] ) ) {
                $cart->remove_cart_item( $key );
            }
        }
    }


    /**
     * Evaluate discount conditions
     * Returns true if all conditions are met, false otherwise
     */
    public function evaluate_discount_condition_groups ( $condition_groups ) {
        if ( empty( $condition_groups ) || ! is_array( $condition_groups ) ) {
            return true;
        }

        foreach ( $condition_groups as $group ) {
            if ( ! empty( $group['conditions'] ) && is_array( $group['conditions'] ) ) {
                if ( ! $this->evaluate_discount_conditions( $group['conditions'] ) ) {
                    return false; // If any group fails, the whole evaluation fails
                }
            }
        }
        return true; // All groups passed
    }
    
    /**
     * Evaluate individual discount conditions
     * Returns true if all conditions are met, false otherwise
     */
    public function evaluate_discount_conditions( $conditions ) {
        if ( empty( $conditions ) || ! is_array( $conditions ) ) {
            return true;
        }

        $cart = WC()->cart; 
        $customer = wp_get_current_user();
        $cart_items = $cart->get_cart();
        $cart_total_weight = $cart->get_cart_contents_weight();
        $cart_subtotal_incl_tax = $cart->get_subtotal() + $cart->get_subtotal_tax();
        $cart_subtotal_excl_tax = $cart->get_subtotal();
        $cart_item_count = $cart->get_cart_contents_count();
        $cart_contents = $cart->get_cart_contents();
        $cart_coupons = $cart->get_applied_coupons();

        $cart_max_width_height = Dspilot_Helper::get_cart_max_width_height();
        $cart_max_height = $cart_max_width_height['max_height'];
        $cart_max_width = $cart_max_width_height['max_width'];

    
        $cart_max_length = Dspilot_Helper::get_cart_max_length();
        $cart_min_stock = Dspilot_Helper::get_min_stock_of_cart_items();
        $cart_product_ids = Dspilot_Helper::get_cart_product_ids();

        $cart_product_variations = Dspilot_Helper::get_cart_product_variation_ids();
        $current_user_id = get_current_user_id();

        $chosen_payment_method_id = WC()->session->get( 'chosen_payment_method' ); 
        $chosen_shipping_method_id = Dspilot_Helper::get_selected_shipping_method(); 


        foreach ( $conditions as $condition ) {
            $type = $condition['condition'] ?? '';
            $compare = $condition['condition_compare'] ?? 'equal_to';

            if(in_array($type, ['user_email', 'user_meta', 'coupons_applied', 'shipping_city', 'shipping_postcode'])){
                $value = $condition['text'];
            }else if(in_array($type, ['last_order_date'])){
                $value = $condition['date'];
            }else if(in_array($type, ['products_in_cart', 'featured_products_in_cart', 'onsale_products_in_cart', 'bought_products', 'bought_featured_products', 'bought_onsale_products'])){
                $value = $condition['product_ids'] ?? [];
            }else if(in_array($type, ['product_categories_in_cart', 'bought_product_categories'])){
                $value = $condition['category_ids'] ?? [];
            }else if(in_array($type, ['product_brands_in_cart', 'bought_product_brands'])){
                $value = $condition['brand_ids'] ?? [];
            }else if(in_array($type, ['product_variations_in_cart', 'quantity_of_variations', 'bought_variations', 'quantity_of_bought_variations', 'amount_of_bought_variations'])){
                $value = $condition['variation_ids'] ?? [];
            }else if(in_array($type, ['shipping_classes_in_cart'])){
                $value = $condition['shipping_classes'] ?? [];
            }else if(in_array($type, ['user_roles'])){
                $value = $condition['user_roles'];
            }else if(in_array($type, ['user_capability'])){
                $value = $condition['user_capabilities'];
            }else if(in_array($type, ['is_user_logged_in'])){
                $value = $condition['bool'];
            }else if(in_array($type, ['payment_method'])){
                $value = $condition['payment_methods'];
            }else if(in_array($type, ['shipping_method'])){
                $value = $condition['shipping_methods'];
            }else if(in_array($type, ['shipping_country'])){
                $value = $condition['shipping_countries'];
            }else if(in_array($type, ['shipping_state'])){
                $value = $condition['shipping_states'];
            }else if(in_array($type, ['shipping_zone'])){
                $value = $condition['shipping_zones'];
            }else{
                $value = $condition['number'];
            }

            $product_ids = $condition['product_ids'] ?? [];
            $variation_ids = $condition['variation_ids'] ?? [];
            $category_ids = $condition['category_ids'] ?? [];
            $brand_ids = $condition['brand_ids'] ?? [];
            $user_roles = $condition['user_roles'] ?? [];
            $shipping_classes = $condition['shipping_classes'] ?? [];
            $user_meta_key = $condition['user_meta_key'] ?? '';

        
            $value = is_array( $value ) ? $value : ( is_numeric( $value ) ? floatval( $value ) : sanitize_text_field( $value ) );
            $target = null;
        $target = apply_filters( 'dspilot_discount_condition_target', $target, $type, $condition );

            if ( null === $target ) {
            switch ( $type ) {
                // ✅ Cart conditions
                case 'cart_total_weight':
                    $target = $cart_total_weight;
                    break;
                case 'number_of_cart_items':
                    $target = count( $cart_items );
                    break;
                case 'subtotal_including_tax':
                    $target = $cart_subtotal_incl_tax;
                    break;

                case 'bought_products':
                    $target = Dspilot_Helper::bought_products();
                    $value =  $product_ids;
                    break;


                default:
                    do_action( 'dspilot_custom_coupon_condition_fallback', $type, $compare, $value );
                    break;
            }
            }

            // check condition
            if ( ! Dspilot_Helper::evaluate_condition_compare( $target, $compare, $value ) ) {
                return false;
            }
        }

        return true;
    }
    

    public function cleanup_session_garbage() {
        if ( ! class_exists( 'WC' ) || ! WC()->session ) return;
        $cart = WC()->session->get( 'cart' );
        if ( is_array( $cart ) ) {
            $changed = false;
            foreach ( $cart as $key => $values ) {
                if ( empty( $values['product_id'] ) || empty( $values['quantity'] ) ) {
                    unset( $cart[ $key ] );
                    $changed = true;
                }
            }
            if ( $changed ) {
                WC()->session->set( 'cart', $cart );
            }
        }
    }

    public function sanitize_cart_items( $cart = null ) {
        $target_cart = $cart ? $cart : WC()->cart;
        if ( ! $target_cart || ! isset( $target_cart->cart_contents ) ) return;
        
        foreach ( $target_cart->cart_contents as $key => $item ) {
            if ( ! isset( $item['product_id'] ) || ! isset( $item['quantity'] ) ) {
                unset( $target_cart->cart_contents[ $key ] );
            }
        }
    }

    public function restore_bogo_prices_from_session( $item, $values, $key ) {
        if ( isset( $values['dspilot_bogo_price'] ) ) {
            $item['data']->set_price( (float) $values['dspilot_bogo_price'] );
            // Restore meta marker for filters
            $item['data']->add_meta_data( 'dspilot_bogo_price_enforced', (float) $values['dspilot_bogo_price'], true );
        }
        return $item;
    }

    public function enforce_bogo_product_price( $price, $product ) {
        $enforced = $product->get_meta( 'dspilot_bogo_price_enforced' );
        if ( $enforced !== '' && $enforced !== false ) {
             return (float) $enforced;
        }
        return $price;
    }

    /**
     * Enforce BOGO prices after all calculations
     */
    public function apply_bogo_prices( $cart ) {
        // Iterate cart contents directly to ensure we catch everything
        if ( ! $cart->cart_contents ) return;
        
        foreach ( $cart->cart_contents as $key => $item ) {
            if ( isset( $item['dspilot_bogo_price'] ) ) {
                $price = (float) $item['dspilot_bogo_price'];
                $product = $item['data'];
                if ( (float) $product->get_price() !== $price ) {
                    $product->set_price( $price );
                }
                // Add marker to bypass other filters
                $product->add_meta_data( 'dspilot_bogo_price_enforced', $price, true );
            }
        }
    }



}

new Dspilot_Pricing_Discount();


// bogo disocunt



/**
 * Make free BOGO cart item non-editable (no qty input) and non-removable.
 */
add_filter( 'woocommerce_cart_item_quantity', 'dspilot_bogo_cart_item_quantity_display', 99, 3 );
function dspilot_bogo_cart_item_quantity_display( $product_quantity, $cart_item_key, $cart_item ) {
    if ( isset( $cart_item['dspilot_bogo_free'] ) && $cart_item['dspilot_bogo_free'] === true ) {
        return (int) $cart_item['quantity']; // plain number, no input
    }
    return $product_quantity;
}

add_filter( 'woocommerce_cart_item_remove_link', 'dspilot_bogo_cart_item_remove_link', 10, 2 );
function dspilot_bogo_cart_item_remove_link( $link, $cart_item_key ) {
    $cart = WC()->cart;
    if ( isset( $cart->cart_contents[ $cart_item_key ] ) &&
         isset( $cart->cart_contents[ $cart_item_key ]['dspilot_bogo_free'] ) &&
         $cart->cart_contents[ $cart_item_key ]['dspilot_bogo_free'] === true ) {
        return ''; // hide remove link
    }
    return $link;
}

add_filter( 'woocommerce_is_cart_item_quantity_editable', function( $editable, $cart_item ) {
    if ( ! empty( $cart_item['dspilot_bogo_free'] ) ) {
        return false; // ❌ free item qty change করা যাবে না
    }
    return $editable;
}, 10, 2 );



add_filter( 'woocommerce_cart_item_remove_link', function( $link, $cart_item_key ) {
    $cart = WC()->cart;
    if ( isset( $cart->cart_contents[ $cart_item_key ]['dspilot_bogo_free'] )
         && $cart->cart_contents[ $cart_item_key ]['dspilot_bogo_free'] ) {
        return ''; // ❌ লিঙ্ক দেখাবে না
    }
    return $link;
}, 10, 2 );


add_filter( 'woocommerce_cart_item_class', function( $class, $cart_item, $cart_item_key ){
    if ( ! empty( $cart_item['dspilot_bogo_free'] ) ) {
        $class .= ' bogo-free';
    }
    return $class;
}, 10, 3 );


add_filter( 'woocommerce_update_cart_validation', function( $passed, $cart_item_key, $values, $buy_qty ) {
    if ( ! empty( $values['dspilot_bogo_free'] ) ) {
        // Block any attempt to update free item
        wc_add_notice( __( 'Free BOGO item quantity cannot be changed.', 'discountpilot-dynamic-pricing' ), 'error' );
        return false;
    }
    return $passed;
}, 10, 4 );
