<?php

defined('ABSPATH') || exit;

class BundlePress_Bundle_Display
{
    private static $is_ajax_adding = false;

    public function __construct()
    {
        // Primary hook for custom product types
        add_action('woocommerce_bundlepress_add_to_cart', [$this, 'render_bundle_ui'], 15);

        add_action('woocommerce_single_product_summary', [$this, 'maybe_inject_bundle_root'], 25);

        // Remove standard elements for bundle products
        add_action('woocommerce_single_product_summary', [$this, 'remove_default_elements'], 1);

        add_filter('woocommerce_add_to_cart_validation', [$this, 'validate_bundle_add_to_cart'], 10, 3);
        add_action('woocommerce_add_to_cart', [$this, 'handle_bundle_add_to_cart'], 10, 3);
        
        // Support metadata from Store API (passing via query params)
        add_filter('woocommerce_add_cart_item_data', [$this, 'handle_store_api_metadata'], 10, 3);
        add_filter('woocommerce_store_api_add_to_cart_data', [$this, 'handle_store_api_direct'], 10, 2);

        // AJAX handler for bundle add to cart
        add_action('wp_ajax_bundlepress_add_bundle_to_cart', [$this, 'ajax_add_bundle_to_cart']);
        add_action('wp_ajax_nopriv_bundlepress_add_bundle_to_cart', [$this, 'ajax_add_bundle_to_cart']);

        // Apply dynamic pricing in cart
        add_action('woocommerce_before_calculate_totals', [$this, 'apply_bundle_discounts'], 10, 1);

        // Show bundle info in cart
        add_filter('woocommerce_get_item_data', [$this, 'show_bundle_info_in_cart'], 10, 2);

        // Persist bundle meta to order items
        add_action('woocommerce_checkout_create_order_line_item', [$this, 'persist_bundle_meta_to_order'], 10, 4);

        // Handle Free Shipping for bundles
        add_filter('woocommerce_shipping_free_shipping_is_available', [$this, 'handle_free_shipping_available'], 10, 3);
        add_filter('woocommerce_package_rates', [$this, 'apply_bundle_free_shipping'], 10, 2);

        // Cart quantity & removal sync
        add_action('woocommerce_cart_item_removed', [$this, 'sync_cart_item_removal'], 10, 2);
        add_action('woocommerce_after_cart_item_quantity_update', [$this, 'sync_cart_item_quantity'], 10, 4);
        add_filter('woocommerce_cart_item_quantity', [$this, 'lock_child_item_quantity'], 10, 3);
    }

    public function persist_bundle_meta_to_order($item, $cart_item_key, $values, $order)
    {
        $keys = [
            '_bundlepress_bundle',
            '_bundlepress_parent',
            '_bundlepress_type',
            '_bundlepress_discount',
            '_bundlepress_bundle_title',
            '_bundlepress_discount_info',
            '_bxgy_offer_item',
            '_bxgy_free_gift'
        ];

        foreach ($keys as $key) {
            if (isset($values[$key])) {
                $val = $values[$key];
                
                // For child items, persistence needs the numeric bundle ID in _bundlepress_parent
                if ($key === '_bundlepress_parent' && isset($values['_bundlepress_bundle_id'])) {
                    $val = $values['_bundlepress_bundle_id'];
                }

                $item->add_meta_data($key, $val);

                // Add human-readable meta for order view
                if ($key === '_bundlepress_bundle_title') {
                    $item->add_meta_data(__('Bundle', 'bundlepress'), $val, true);
                }
                if ($key === '_bundlepress_discount_info' && is_array($val)) {
                    $display_val = ($val['type'] === 'percentage') ? $val['value'] . '%' : get_woocommerce_currency_symbol() . $val['value'];
                    $item->add_meta_data(__('Bundle Discount', 'bundlepress'), $display_val, true);
                }
            }
        }
    }

    public function show_bundle_info_in_cart($item_data, $cart_item)
    {
        // 1. Show Bundle Title
        if (!empty($cart_item['_bundlepress_bundle_title'])) {
            $item_data[] = [
                'key'     => __('Bundle', 'bundlepress'),
                'value'   => $cart_item['_bundlepress_bundle_title'],
                'display' => $cart_item['_bundlepress_bundle_title'],
            ];
        }

        // 2. Show Savings / Discount Info
        $product = $cart_item['data'];
        $reg = (float) $product->get_regular_price();
        $cur = (float) $product->get_price();

        if ($cur < $reg && $reg > 0) {
            $savings = ($reg - $cur) * $cart_item['quantity'];
            $percent = round((($reg - $cur) / $reg) * 100);

            if ($savings > 0) {
                $item_data[] = [
                    'key'     => __('You Save', 'bundlepress'),
                    'value'   => wc_price($savings) . " ($percent%)",
                    'display' => wc_price($savings) . " ($percent%)",
                ];
            }
        }

        return $item_data;
    }

    public function get_bundle_id_for_item($cart_item)
    {
        if (isset($cart_item['_bundlepress_bundle'])) {
            return absint($cart_item['_bundlepress_bundle']);
        }

        if (isset($cart_item['_bundlepress_parent'])) {
            $parent_key = $cart_item['_bundlepress_parent'];
            
            // In Store API context, WC()->cart might not be initialized yet in some filters, 
            // but for totals calculation it is.
            $cart = (function_exists('WC') && WC()->cart) ? WC()->cart->get_cart() : [];
            
            if (isset($cart[$parent_key])) {
                if (isset($cart[$parent_key]['_bundlepress_bundle'])) {
                    return absint($cart[$parent_key]['_bundlepress_bundle']);
                }
                if (isset($cart[$parent_key]['_bundle_id'])) {
                    return absint($cart[$parent_key]['_bundle_id']);
                }
            }
        }

        return 0;
    }

    public function ajax_add_bundle_to_cart()
    {
        ob_start();

        try {
            $bundle_id = isset($_POST['bundle_id']) ? absint($_POST['bundle_id']) : 0;
            $quantity = isset($_POST['quantity']) ? absint($_POST['quantity']) : 1;
            $items = isset($_POST['items']) ? wc_clean(wp_unslash($_POST['items'])) : [];

            if (!$bundle_id) {
                throw new Exception('Invalid bundle ID');
            }

            $bundle = BundlePress_DB::get_bundle_data($bundle_id);
            $cart_item_key = null;

            if ($bundle && $bundle['product_id']) {
                $product_id = $bundle['product_id'];
                // Add the bundle product itself to the cart
                $cart_item_key = WC()->cart->add_to_cart($product_id, $quantity, 0, [], [
                    '_bundlepress_bundle' => $bundle_id,
                    '_bundle_id'          => $bundle_id,
                    '_bundlepress_type'   => $bundle['type']
                ]);

                if (!$cart_item_key) {
                    $error_message = 'Failed to add bundle to cart';
                    if (function_exists('wc_get_notices') && wc_notice_count('error') > 0) {
                        $errors = wc_get_notices('error');
                        $error_message = strip_tags($errors[0]['notice'] ?? 'Failed to add bundle to cart');
                        wc_clear_notices();
                    }
                    throw new Exception($error_message);
                }
            }
            // Add each item in the bundle to the cart as a child product
            if (!empty($items)) {
                foreach ($items as $item) {
                    $item_product_id = isset($item['product_id']) ? absint($item['product_id']) : 0;
                    $item_qty = isset($item['quantity']) ? absint($item['quantity']) : 1;

                    if ($item_product_id) {
                        $cart_item_data = [];
                        $b_type = $bundle ? $bundle['type'] : 'fixed';

                        if ($cart_item_key) {
                            $cart_item_data['_bundlepress_parent'] = $cart_item_key;
                            $cart_item_data['_bundlepress_bundle_id'] = $bundle_id;
                        } else {
                            $cart_item_data['_bundlepress_bundle'] = $bundle_id;
                            $cart_item_data['_bundle_id'] = $bundle_id;
                            $cart_item_data['_bundlepress_type'] = $b_type;
                        }

                        WC()->cart->add_to_cart(
                            $item_product_id,
                            $item_qty,
                            0,
                            [],
                            $cart_item_data
                        );
                    }
                }
            }

            // Add offer items (free gift / BXGY reward items)
            $offer_items = isset($_POST['offer_items']) ? wc_clean(wp_unslash($_POST['offer_items'])) : [];
            if (!empty($offer_items)) {
                foreach ($offer_items as $offer_item) {
                    $offer_product_id = isset($offer_item['product_id']) ? absint($offer_item['product_id']) : 0;
                    $offer_qty = isset($offer_item['quantity']) ? absint($offer_item['quantity']) : 1;
                    $is_free = isset($offer_item['is_free']) && $offer_item['is_free'] === '1';

                    if (!$offer_product_id)
                        continue;

                    $offer_cart_data = [
                        '_bundlepress_bundle' => $bundle_id,
                        '_bundle_id' => $bundle_id,
                        '_bundlepress_type' => $bundle ? $bundle['type'] : 'bxgy',
                        '_bxgy_offer_item' => true,
                        '_bxgy_free_gift' => $is_free,
                    ];
                    if ($cart_item_key) {
                        $offer_cart_data['_bundlepress_parent'] = $cart_item_key;
                    }

                    WC()->cart->add_to_cart($offer_product_id, $offer_qty, 0, [], $offer_cart_data);
                }
            }

            self::$is_ajax_adding = false;
            wp_send_json_success(array_merge([
                'message'  => 'Bundle added to cart successfully',
                'cart_url' => wc_get_cart_url(),
            ], WC_AJAX::get_refreshed_fragments()));

        } catch (Exception $e) {
            self::$is_ajax_adding = false;
            wp_send_json_error([
                'message' => $e->getMessage()
            ]);
        }
    }

    public function handle_store_api_metadata($cart_item_data, $product_id, $variation_id)
    {
        // Use $_GET for query params and $_POST for body (though Store API encodes in JSON usually)
        $bundle_id = isset($_GET['bundle_id']) ? absint($_GET['bundle_id']) : (isset($_REQUEST['bundle_id']) ? absint($_REQUEST['bundle_id']) : 0);
        
        if ($bundle_id) {
            $cart_item_data['_bundlepress_bundle'] = $bundle_id;
            $cart_item_data['_bundle_id'] = $bundle_id;
            
            $bundle = BundlePress_DB::get_bundle_data($bundle_id);
            if ($bundle) {
                $cart_item_data['_bundlepress_bundle_title'] = $bundle['name'];
            }
        }
        
        $bundle_parent = isset($_GET['bundle_parent']) ? sanitize_text_field($_GET['bundle_parent']) : (isset($_REQUEST['bundle_parent']) ? sanitize_text_field($_REQUEST['bundle_parent']) : '');
        if ($bundle_parent) {
            $cart_item_data['_bundlepress_parent'] = $bundle_parent;
        }
        
        $bundle_type = isset($_GET['bundle_type']) ? sanitize_text_field($_GET['bundle_type']) : (isset($_REQUEST['bundle_type']) ? sanitize_text_field($_REQUEST['bundle_type']) : '');
        if ($bundle_type) {
            $cart_item_data['_bundlepress_type'] = $bundle_type;
        }

        // BXGY Metadata
        $is_offer = !empty($_GET['is_offer']) || !empty($_REQUEST['is_offer']);
        if ($is_offer) {
            $cart_item_data['_bxgy_offer_item'] = true;
        }

        $is_free = !empty($_GET['is_free']) || !empty($_REQUEST['is_free']);
        if ($is_free) {
            $cart_item_data['_bxgy_free_gift'] = true;
        }

        return $cart_item_data;
    }

    public function handle_store_api_direct($data, $request)
    {
        $params = $request->get_params();
        if (isset($params['bundle_id'])) {
            $data['_bundlepress_bundle'] = absint($params['bundle_id']);
            $data['_bundle_id'] = absint($params['bundle_id']);

            $bundle = BundlePress_DB::get_bundle_data($params['bundle_id']);
            if ($bundle) {
                $data['_bundlepress_bundle_title'] = $bundle['name'];
            }
        }
        if (isset($params['bundle_parent']) && $params['bundle_parent']) {
            $data['_bundlepress_parent'] = sanitize_text_field($params['bundle_parent']);
        }
        if (isset($params['bundle_type'])) {
            $data['_bundlepress_type'] = sanitize_text_field($params['bundle_type']);
        }
        if (!empty($params['is_offer'])) {
            $data['_bxgy_offer_item'] = true;
        }
        if (!empty($params['is_free'])) {
            $data['_bxgy_free_gift'] = true;
        }
        return $data;
    }

    public function remove_default_elements()
    {
        global $product;
        if (!$product) return;

        $product_id = $product->get_id();
        $is_bundle = ($product->get_type() === 'bundlepress');

        // Fallback check
        if (!$is_bundle) {
            global $wpdb;
            $is_bundle = (bool) $wpdb->get_var($wpdb->prepare(
                "SELECT 1 FROM {$wpdb->prefix}bundlepress_bundles WHERE product_id = %d LIMIT 1",
                $product_id
            ));
        }

        if ($is_bundle) {
            $bundle = BundlePress_DB::get_bundle_data($product_id);
            $type = $bundle ? $bundle['type'] : '';

            // For bundle types, we replace the standard price/add-to-cart area
            remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_price', 10);
            remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30);
            remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_excerpt', 20);
            
            // Themes often hardcode or use different priorities; CSS is more reliable as a catch-all
            echo '<style>
                .single-product div.product p.price, 
                .single-product div.product span.price,
                .single-product div.product .woocommerce-product-details__short-description,
                .single-product div.product form.cart { 
                    display: none !important; 
                }
            </style>';
        }
    }

    public function maybe_inject_bundle_root()
    {
        global $product;
        if (!$product) {
            echo '<!-- BundlePress DEBUG: No global product found -->';
            return;
        }

        $product_id = $product->get_id();
        $is_bundle = ($product->get_type() === 'bundlepress');

        // Fallback: Check custom table if type check fails
        if (!$is_bundle) {
            global $wpdb;
            $bundle_exists = $wpdb->get_var($wpdb->prepare(
                "SELECT 1 FROM {$wpdb->prefix}bundlepress_bundles WHERE product_id = %d LIMIT 1",
                $product_id
            ));
            if ($bundle_exists) {
                $is_bundle = true;
            }
        }

        if ($is_bundle || did_action('bundlepress_render_on_product')) {
            // Only inject if it hasn't been injected yet via the specific action
            if (!did_action('woocommerce_bundlepress_add_to_cart')) {
                $this->render_bundle_ui();
            } else {
                echo '<!-- BundlePress DEBUG: Already injected via woocommerce_bundlepress_add_to_cart -->';
            }
        } else {
            echo '<!-- BundlePress DEBUG: Not a bundle product (ID: ' . esc_html($product_id) . ', Type: ' . esc_html($product->get_type()) . ') -->';
        }
    }

    public function render_bundle_ui()
    {
        global $product;
        if (!$product) {
            return;
        }

        $id = $product->get_id();
        
        // Inject our root element for React
        echo '<!-- BundlePress Root Injection -->';
        echo '<div id="bundlepress-bundle-root" data-product-id="' . esc_attr($id) . '" style="margin: 20px 0; min-height: 100px;"></div>';
    }

    public function validate_bundle_add_to_cart($passed, $product_id, $quantity)
    {
        $product = wc_get_product($product_id);
        if ($product && $product->get_type() === 'bundlepress') {
            $bundle = BundlePress_DB::get_bundle_data($product_id);
            $type = $bundle ? $bundle['type'] : '';

            if ($type === 'fixed') {
                return $passed;
            }
            // Check both native 'items' (from our AJAX) and 'bundlepress_items' (standard form)
            if (empty($_POST['items']) && empty($_POST['bundlepress_items'])) {
                wc_add_notice('Please select items for your bundle.', 'error');
                return false;
            }
        }
        return $passed;
    }

    public function handle_bundle_add_to_cart($cart_item_key, $product_id, $quantity)
    {
        if (self::$is_ajax_adding) {
            return; // Already handled by the AJAX method
        }

        $product = wc_get_product($product_id);
        if ($product && $product->get_type() === 'bundlepress' && !empty($_POST['bundlepress_items'])) {
            // Update the parent item with bundle meta
            $cart = WC()->cart->get_cart();
            if (isset($cart[$cart_item_key])) {
                $bundle = BundlePress_DB::get_bundle_data($product_id);
                $cart[$cart_item_key]['_bundlepress_bundle'] = $bundle ? $bundle['id'] : $product_id;
                $cart[$cart_item_key]['_bundle_id'] = $bundle ? $bundle['id'] : $product_id;
                $cart[$cart_item_key]['_bundlepress_type'] = $bundle ? $bundle['type'] : 'fixed';
                WC()->cart->set_cart_contents($cart);
            }

            $bundle_items = wc_clean(wp_unslash($_POST['bundlepress_items']));
            foreach ($bundle_items as $item_id => $item_qty) {
                WC()->cart->add_to_cart($item_id, $item_qty, 0, [], [
                    '_bundlepress_parent' => $cart_item_key,
                    '_bundlepress_bundle_id' => $product_id
                ]);
            }
        }
    }

    /**
     * Overrides the price of bundle-related items in the cart.
     */
    public function apply_bundle_discounts($cart)
    {
        if (is_admin() && !defined('DOING_AJAX')) {
            return;
        }

        foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
            $bundle_id = $this->get_bundle_id_for_item($cart_item);
            if (!$bundle_id) {
                continue;
            }

            $bundle = BundlePress_DB::get_bundle_data($bundle_id);
            if (!$bundle)
                continue;

            $type = $bundle['type'];
            $product = $cart_item['data'];
            $regular_price = (float) $product->get_regular_price();
            $new_price = $regular_price;

            switch ($type) {
                case 'volume':
                    $new_price = BundlePress_Volume_Handler::get_price($product->get_id(), $bundle_id, $cart_item, $cart);
                    break;
                case 'mixmatch':
                    $new_price = BundlePress_MixMatch_Handler::get_price($product->get_id(), $bundle_id, $cart_item, $cart);
                    break;
                case 'fbt':
                    $new_price = BundlePress_FBT_Handler::get_price($product->get_id(), $bundle_id, $cart_item, $cart);
                    break;
                case 'bxgy':
                    $new_price = BundlePress_BXGY_Handler::get_price($product->get_id(), $bundle_id, $cart_item, $cart);
                    break;
                default:
                    $new_price = BundlePress_Fixed_Handler::get_price($product->get_id(), $bundle_id, $cart_item, $cart);
                    break;
            }

            if ($bundle_id) {
                $product->set_price($new_price);
                
                // Store the calculated discount for metadata visibility
                $discount = $regular_price - $new_price;
                if ($discount > 0) {
                    $cart->cart_contents[$cart_item_key]['_bundlepress_discount'] = $discount;
                    
                    // Update discount info for display
                    $cart->cart_contents[$cart_item_key]['_bundlepress_discount_info'] = [
                        'type'  => 'fixed_per_item',
                        'value' => $discount
                    ];
                }
            }
        }
    }

    /**
     * Force "Free Shipping" to be available if a bundle in cart offers it.
     */
    public function handle_free_shipping_available($is_available, $package, $shipping_method)
    {
        if ($is_available) {
            return $is_available;
        }
        return $this->has_free_shipping_bundle();
    }

    /**
     * Zero out shipping costs if a free shipping bundle is in the cart.
     */
    public function apply_bundle_free_shipping($rates, $package)
    {
        if ($this->has_free_shipping_bundle()) {
            foreach ($rates as $rate_id => $rate) {
                $rates[$rate_id]->cost = 0;
                $rates[$rate_id]->set_taxes([]); // also remove taxes from shipping
            }
        }
        return $rates;
    }

    /**
     * Help determine if any item in the cart is part of a free shipping bundle.
     */
    private function has_free_shipping_bundle()
    {
        if (!function_exists('WC') || !WC()->cart) {
            return false;
        }

        foreach (WC()->cart->get_cart() as $cart_item) {
            $bundle_id = $this->get_bundle_id_for_item($cart_item);
            if (!$bundle_id)
                continue;

            $bundle = BundlePress_DB::get_bundle_data($bundle_id);
            if (!$bundle || $bundle['type'] !== 'bxgy')
                continue;

            $settings = $bundle['settings'];
            $offer_type = $settings['offer_type'] ?? $settings['bxgy_offer_type'] ?? 'free_gift';

            if ($offer_type === 'free_shipping') {
                return true;
            }
        }

        return false;
    }

    public function sync_cart_item_removal($cart_item_key, $cart)
    {
        $removed_item = $cart->removed_cart_contents[$cart_item_key] ?? null;
        if (!$removed_item) return;

        // Parent deleted? Delete all children.
        $is_parent = (isset($removed_item['_bundlepress_bundle']) || isset($removed_item['_bundle_id'])) && !isset($removed_item['_bundlepress_parent']);
        if ($is_parent) {
            foreach ($cart->get_cart() as $key => $item) {
                if (isset($item['_bundlepress_parent']) && $item['_bundlepress_parent'] === $cart_item_key) {
                    $cart->remove_cart_item($key);
                }
            }
        }
        
        // Child deleted? Remove parent. The parent removal will recursively clear other children.
        if (isset($removed_item['_bundlepress_parent'])) {
            $parent_key = $removed_item['_bundlepress_parent'];
            if (isset($cart->get_cart()[$parent_key])) {
                $cart->remove_cart_item($parent_key);
            }
        }
    }

    public function sync_cart_item_quantity($cart_item_key, $quantity, $old_quantity, $cart)
    {
        if ($old_quantity <= 0) return;

        $item = $cart->get_cart()[$cart_item_key] ?? null;
        if (!$item) return;

        $is_parent = (isset($item['_bundlepress_bundle']) || isset($item['_bundle_id'])) && !isset($item['_bundlepress_parent']);
        if ($is_parent) {
            foreach ($cart->get_cart() as $child_key => $child_item) {
                if (isset($child_item['_bundlepress_parent']) && $child_item['_bundlepress_parent'] === $cart_item_key) {
                    $base_qty = $child_item['quantity'] / $old_quantity;
                    $new_qty = $base_qty * $quantity;
                    $cart->set_quantity($child_key, $new_qty, false);
                }
            }
        }
    }

    public function lock_child_item_quantity($product_quantity, $cart_item_key, $cart_item)
    {
        if (isset($cart_item['_bundlepress_parent'])) {
            // Cannot edit quantity: just render the string value in cart
            return sprintf('<span class="bp-child-qty" style="font-weight:600; padding:0 10px;">%s</span>', $cart_item['quantity']);
        }
        return $product_quantity;
    }
}
