<?php

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

class AIEO_DMM_Free_Shipping extends AIEO_DMM_Module_Base {

    public function get_id() { return 'free_shipping'; }
    public function get_label() { return __('Free Shipping + COD', 'ai-eshop-optimizer'); }
    public function get_priority() { return 50; }
    public function get_group() { return 'special_pricing_offers'; }

    const OPTION_KEY = 'aieo_dmm_free_shipping';

    public function register_hooks() {
        
        
        
        add_filter('aieo_eligibility_compute', array(__CLASS__, 'add_eligibility_row'), 10, 3);

        add_action('wp_ajax_aieo_dmm_free_shipping_save', array($this, 'ajax_save'));
        add_action('wp_ajax_aieo_dmm_free_shipping_add_exclusions', array($this, 'ajax_add_exclusions'));
        add_action('wp_ajax_aieo_dmm_free_shipping_remove_exclusion', array($this, 'ajax_remove_exclusion'));
        add_action('wp_ajax_aieo_dmm_free_shipping_export_exclusions', array($this, 'ajax_export_exclusions'));

        
        
        add_action('wp_ajax_aieo_dmm_free_shipping_save_rule',   array($this, 'ajax_save_rule'));
        add_action('wp_ajax_aieo_dmm_free_shipping_delete_rule', array($this, 'ajax_delete_rule'));

        
        
        
        
        
        if (AIEO_DMM_Settings::is_module_enabled('free_shipping')) {
            add_action('wp_enqueue_scripts', array($this, 'enqueue_css_vars'), 99);
        }

        
        
        
        
        
        
        
        if (AIEO_DMM_Settings::get('recipe.no_free_shipping_gate', 'hard') !== 'off'
            && AIEO_DMM_Settings::is_module_enabled('free_shipping')) {

            if ( ! defined( 'AIEO_RUNTIME_OWNS_AJAX' ) ) {
                add_filter('woocommerce_package_rates', array($this, 'filter_package_rates'), 100, 2);
                add_filter('woocommerce_package_rates', array($this, 'apply_unified_free_shipping_rules'), 110, 2);
            }

            $settings = $this->get_settings();
            $notify_on_atc = !isset($settings['notify_on_add_to_cart']) || $settings['notify_on_add_to_cart'] === 'yes';
            if ($notify_on_atc) {
                if ( ! defined( 'AIEO_RUNTIME_OWNS_AJAX' ) ) {
                    add_action('woocommerce_add_to_cart', array($this, 'notify_on_add_to_cart'), 20, 6);
                }
                
                add_action('woocommerce_after_add_to_cart_form', array($this, 'render_product_page_notice'));
            }
        }

        
        
        
        
        
        
        
        if ( ! defined( 'AIEO_RUNTIME_OWNS_AJAX' ) ) {
            add_action('woocommerce_cart_calculate_fees',                  array($this, 'apply_cod_fee_to_cart'), 11, 1);
            
            
            
            
            add_filter('woocommerce_available_payment_gateways', array($this, 'force_cod_visible_when_aieo_enabled'), 999);
        }
        add_action('woocommerce_admin_order_data_after_billing_address', array($this, 'apply_cod_fee_admin'), 10, 1);
        add_action('wp_footer',                                         array($this, 'output_cod_refresh_js'));
        
        
        
        add_action('woocommerce_blocks_loaded',                         array($this, 'maybe_register_cod_for_blocks'));
    }

    public function render_subtab() {
        
        $paged = isset($_GET['paged']) ? max(1, absint($_GET['paged'])) : 1;
        
        
        
        
        $this->render_unified_rules_section();
        
        
        
        $this->render_template('free-shipping.php', array(
            'settings' => $this->get_settings(),
            'exclusions' => $this->fetch_exclusions(100, $paged),
            'exclusion_count' => $this->count_exclusions(),
            'per_page' => 100,
            'current_page' => $paged,
        ));
        
        
        
        $this->render_cod_card();

        
        
        
        do_action('aieo_dmm_free_shipping_after_cod_card');
    }

    
    private function render_cod_card() {
        $settings = $this->get_settings();
        if (!function_exists('is_plugin_active')) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        $legacy_active = is_plugin_active('om-checkout-handling/om-checkout-handling.php');
        ?>
        <div class="aieo-dmm-card" style="margin-top:24px;">
            <h2><?php esc_html_e('Cash on Delivery', 'ai-eshop-optimizer'); ?></h2>
            <p class="description">
                <?php esc_html_e('Adds a fee to the order total when the customer picks the Cash on Delivery payment method at checkout. The fee is recalculated whenever the cart total or payment method changes (mini-cart qty changes included).', 'ai-eshop-optimizer'); ?>
            </p>
            <?php if ($legacy_active && $settings['cod_enabled'] === 'yes') : ?>
                <div class="notice notice-warning inline" style="margin:12px 0;padding:8px 12px;">
                    <p><strong><?php esc_html_e('Heads-up:', 'ai-eshop-optimizer'); ?></strong>
                    <?php esc_html_e('OM Checkout Handling is also active and may add its own COD fee. Disable COD there (or deactivate the whole plugin) to avoid a double-charge.', 'ai-eshop-optimizer'); ?></p>
                </div>
            <?php endif; ?>
            <form id="aieo-dmm-fs-cod-form" class="aieo-dmm-form">
                <input type="hidden" name="form_section" value="cod">
                <table class="form-table">
                    <tr>
                        <th><?php esc_html_e('Enable COD fee', 'ai-eshop-optimizer'); ?></th>
                        <td>
                            <label>
                                <input type="checkbox" name="cod_enabled" value="1" <?php checked($settings['cod_enabled'] === 'yes'); ?>>
                                <?php esc_html_e('Add a fee when the customer pays with Cash on Delivery', 'ai-eshop-optimizer'); ?>
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th><?php esc_html_e('Fee amount', 'ai-eshop-optimizer'); ?></th>
                        <td>
                            <input type="number" name="cod_fee" step="0.01" min="0" value="<?php echo esc_attr((string) $settings['cod_fee']); ?>" style="width:120px;">
                            <span class="description"><?php esc_html_e('In your shop currency. Typical Greek COD fee is €1.50–€2.50.', 'ai-eshop-optimizer'); ?></span>
                        </td>
                    </tr>
                    <tr>
                        <th><?php esc_html_e('Fee label', 'ai-eshop-optimizer'); ?></th>
                        <td>
                            <input type="text" name="cod_label" value="<?php echo esc_attr((string) $settings['cod_label']); ?>" class="regular-text" maxlength="100">
                            <p class="description"><?php esc_html_e('Shown to the customer on cart/checkout/order — also used to detect duplicate fees so we never add it twice.', 'ai-eshop-optimizer'); ?></p>
                        </td>
                    </tr>
                    <?php
                    
                    do_action('aieo_dmm_cod_card_after_fee_label', $settings);
                    ?>
                    <tr>
                        <th><?php esc_html_e('Taxable', 'ai-eshop-optimizer'); ?></th>
                        <td>
                            <label>
                                <input type="checkbox" name="cod_taxable" value="1" <?php checked($settings['cod_taxable'] === 'yes'); ?>>
                                <?php esc_html_e('Apply tax to the COD fee', 'ai-eshop-optimizer'); ?>
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th><?php esc_html_e('Payment gateway slug', 'ai-eshop-optimizer'); ?></th>
                        <td>
                            <input type="text" name="cod_gateway_slug" value="<?php echo esc_attr((string) $settings['cod_gateway_slug']); ?>" style="width:200px;" maxlength="50">
                            <p class="description"><?php esc_html_e('WooCommerce payment-method ID that triggers this fee. Default "cod" matches WooCommerce\'s built-in Cash on Delivery gateway.', 'ai-eshop-optimizer'); ?></p>
                        </td>
                    </tr>
                </table>
                <p>
                    <button type="button" class="button button-primary" id="aieo-dmm-fs-cod-save">
                        <?php esc_html_e('Save COD settings', 'ai-eshop-optimizer'); ?>
                    </button>
                    <span id="aieo-dmm-fs-cod-status" style="margin-left:10px;color:#646970;font-size:13px;"></span>
                </p>
            </form>
            <script>(function(){
                var btn = document.getElementById('aieo-dmm-fs-cod-save');
                var status = document.getElementById('aieo-dmm-fs-cod-status');
                if (!btn) return;
                btn.addEventListener('click', function(){
                    var fd = new FormData(document.getElementById('aieo-dmm-fs-cod-form'));
                    fd.set('action', 'aieo_dmm_free_shipping_save');
                    fd.set('nonce', '<?php echo esc_js(wp_create_nonce(AIEO_DMM::NONCE_ACTION)); ?>');
                    status.style.color = '#646970';
                    status.textContent = '<?php echo esc_js(__('Saving…', 'ai-eshop-optimizer')); ?>';
                    fetch('<?php echo esc_js(admin_url('admin-ajax.php')); ?>', {method:'POST', credentials:'same-origin', body:fd})
                        .then(function(r){return r.json();})
                        .then(function(j){
                            if (j && j.success) {
                                status.style.color = '#15803d';
                                status.textContent = j.data.message;
                            } else {
                                status.style.color = '#b91c1c';
                                status.textContent = (j && j.data && j.data.message) || '<?php echo esc_js(__('Save failed.', 'ai-eshop-optimizer')); ?>';
                            }
                        });
                });
            })();</script>
        </div>
        <?php
    }

    
    public function render_display_settings_card() {
        $settings = $this->get_settings();
        $weight_unit = function_exists('get_option') ? (string) get_option('woocommerce_weight_unit', 'kg') : 'kg';
        ?>
        <form id="aieo-dmm-free-shipping-display-form" class="aieo-dmm-form">
            <input type="hidden" name="form_section" value="display">
            <table class="form-table">
                <tr>
                    <th><?php esc_html_e('Message (initial)', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="msg_initial" value="<?php echo esc_attr((string) $settings['msg_initial']); ?>" class="large-text"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Message (progress)', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="msg_progress" value="<?php echo esc_attr((string) $settings['msg_progress']); ?>" class="large-text"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Message (success)', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="msg_success" value="<?php echo esc_attr((string) $settings['msg_success']); ?>" class="large-text"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Display on', 'ai-eshop-optimizer'); ?></th>
                    <td>
                        <label><input type="checkbox" name="display_cart"     value="1" <?php checked($settings['display_cart']     === 'yes'); ?>> <?php esc_html_e('Cart', 'ai-eshop-optimizer'); ?></label>
                        <label><input type="checkbox" name="display_checkout" value="1" <?php checked($settings['display_checkout'] === 'yes'); ?>> <?php esc_html_e('Checkout', 'ai-eshop-optimizer'); ?></label>
                        <label><input type="checkbox" name="display_mini_cart" value="1" <?php checked($settings['display_mini_cart'] === 'yes'); ?>> <?php esc_html_e('Mini-cart', 'ai-eshop-optimizer'); ?></label>
                        <label><input type="checkbox" name="display_product"  value="1" <?php checked($settings['display_product']  === 'yes'); ?>> <?php esc_html_e('Product page', 'ai-eshop-optimizer'); ?></label>
                        <label><input type="checkbox" name="display_floating" value="1" <?php checked($settings['display_floating'] === 'yes'); ?>> <?php esc_html_e('Floating bar', 'ai-eshop-optimizer'); ?></label>
                    </td>
                </tr>

                <tr>
                    <th colspan="2" style="padding-top:18px;">
                        <h3 style="margin:0;"><?php esc_html_e('Early-signal notice', 'ai-eshop-optimizer'); ?></h3>
                        <p class="description" style="font-weight:400; margin:4px 0 0;">
                            <?php esc_html_e('Tell customers immediately (not only at checkout) when a product they touch will disqualify their order from free shipping.', 'ai-eshop-optimizer'); ?>
                        </p>
                    </th>
                </tr>
                <tr>
                    <th><?php esc_html_e('Signal at add-to-cart', 'ai-eshop-optimizer'); ?></th>
                    <td>
                        <label class="aieo-dmm-choice">
                            <input type="checkbox" name="notify_on_add_to_cart" value="1"
                                   <?php checked((isset($settings['notify_on_add_to_cart']) ? $settings['notify_on_add_to_cart'] : 'yes') === 'yes'); ?>>
                            <?php esc_html_e('Show a WooCommerce notice when an excluded product is added to cart, and show an inline banner on its single-product page.', 'ai-eshop-optimizer'); ?>
                        </label>
                    </td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Notice text', 'ai-eshop-optimizer'); ?></th>
                    <td>
                        <textarea name="notify_message" rows="2" class="large-text"><?php echo esc_textarea(isset($settings['notify_message']) ? (string) $settings['notify_message'] : ''); ?></textarea>
                        <p class="description"><?php esc_html_e('Shown both as a WooCommerce notice on add-to-cart AND as an inline banner under the add-to-cart button on each excluded product\'s single-product page. Leave blank to suppress.', 'ai-eshop-optimizer'); ?></p>
                    </td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Notice type', 'ai-eshop-optimizer'); ?></th>
                    <td>
                        <label class="aieo-dmm-choice"><input type="radio" name="notify_type" value="notice" <?php checked(!isset($settings['notify_type']) || $settings['notify_type'] === 'notice'); ?>> <?php esc_html_e('Info (grey)', 'ai-eshop-optimizer'); ?></label>
                        <label class="aieo-dmm-choice"><input type="radio" name="notify_type" value="error"  <?php checked(isset($settings['notify_type']) && $settings['notify_type'] === 'error'); ?>> <?php esc_html_e('Warning (red)', 'ai-eshop-optimizer'); ?></label>
                    </td>
                </tr>

                <tr>
                    <th colspan="2" style="padding-top:18px;">
                        <h3 style="margin:0;"><?php esc_html_e('Appearance', 'ai-eshop-optimizer'); ?></h3>
                        <p class="description" style="font-weight:400; margin:4px 0 0;">
                            <?php esc_html_e('Styling for the progress bar and the threshold card. Applied via CSS variables so the same values drive cart / checkout / mini-cart / side-cart / product-page / floating surfaces.', 'ai-eshop-optimizer'); ?>
                        </p>
                    </th>
                </tr>
                <tr>
                    <th><?php esc_html_e('Bar height (px)', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="number" min="1" max="60" name="bar_height" value="<?php echo esc_attr((string) (int) $settings['bar_height']); ?>" class="small-text"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Bar border radius (px)', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="number" min="0" max="40" name="bar_border_radius" value="<?php echo esc_attr((string) (int) $settings['bar_border_radius']); ?>" class="small-text"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Bar background', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="bar_bg_color" value="<?php echo esc_attr((string) $settings['bar_bg_color']); ?>" class="aieo-dmm-fs-color" data-default-color="#e0e0e0"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Bar progress color', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="bar_progress_color" value="<?php echo esc_attr((string) $settings['bar_progress_color']); ?>" class="aieo-dmm-fs-color" data-default-color="#4caf50"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Text color', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="text_color" value="<?php echo esc_attr((string) $settings['text_color']); ?>" class="aieo-dmm-fs-color" data-default-color="#333333"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Success color', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="success_color" value="<?php echo esc_attr((string) $settings['success_color']); ?>" class="aieo-dmm-fs-color" data-default-color="#2e7d32"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Amount color', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="amount_color" value="<?php echo esc_attr((string) $settings['amount_color']); ?>" class="aieo-dmm-fs-color" data-default-color="#e65100"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Font size (px)', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="number" min="8" max="40" name="font_size" value="<?php echo esc_attr((string) (int) $settings['font_size']); ?>" class="small-text"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Card background', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="card_bg_color" value="<?php echo esc_attr((string) $settings['card_bg_color']); ?>" class="aieo-dmm-fs-color" data-default-color="#ffffff"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Card padding (px)', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="number" min="0" max="80" name="card_padding" value="<?php echo esc_attr((string) (int) $settings['card_padding']); ?>" class="small-text"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Card border radius (px)', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="number" min="0" max="40" name="card_border_radius" value="<?php echo esc_attr((string) (int) $settings['card_border_radius']); ?>" class="small-text"></td>
                </tr>
                <tr>
                    <th><?php esc_html_e('Card border color', 'ai-eshop-optimizer'); ?></th>
                    <td><input type="text" name="card_border_color" value="<?php echo esc_attr((string) $settings['card_border_color']); ?>" class="aieo-dmm-fs-color" data-default-color="#e0e0e0"></td>
                </tr>
            </table>
            <p class="submit">
                <button type="submit" class="button button-primary" data-action="aieo_dmm_free_shipping_save">
                    <?php esc_html_e('Save display settings', 'ai-eshop-optimizer'); ?>
                </button>
            </p>
        </form>
        <?php
    }

    
    public function render_unified_rules_section() {
        global $wpdb;
        $tbl = $wpdb->prefix . 'aieo_dmm_offers';
        
        $rules = aieo_dmm_table_exists($tbl)
            ? $wpdb->get_results("SELECT * FROM {$tbl} WHERE type='free_shipping' ORDER BY enabled DESC, id DESC", ARRAY_A)
            : array();
        if (!is_array($rules)) { $rules = array(); }
        ?>
        <div class="aieo-dmm-section" style="margin-top:24px;">
            <h2><?php esc_html_e('Free shipping rules (unified)', 'ai-eshop-optimizer'); ?></h2>
            <p class="description">
                <?php
                printf(
                    
                    esc_html__('Brand / category / need-targeted free-shipping rules. Stored in the unified offers table %2$s with %1$s. They run AFTER the legacy threshold + exclusion list above — when a rule\'s targeting + threshold are both satisfied, every shipping rate in the package is forced to %3$s.', 'ai-eshop-optimizer'),
                    '<code>type=\'free_shipping\'</code>',
                    '<code>wp_aieo_dmm_offers</code>',
                    '<code>cost = 0</code>'
                );
                ?>
            </p>

            <form id="aieo-dmm-fs-rule-form" class="aieo-dmm-form">
                <input type="hidden" name="id" value="0">

                <!-- ============================================================
                     Shared eligibility section — IDENTICAL layout/order across
                     gifts, discounts, and free-shipping rules. Type-specific
                     actionable fields go in the second section below.
                     ============================================================ -->
                <div class="aieo-dmm-grid">
                    <p>
                        <label><?php esc_html_e('Label (internal)', 'ai-eshop-optimizer'); ?></label>
                        <input type="text" name="label" placeholder="<?php esc_attr_e('e.g. Free shipping for MUA over €30', 'ai-eshop-optimizer'); ?>">
                    </p>
                    <p>
                        <label><?php esc_html_e('Brands', 'ai-eshop-optimizer'); ?></label>
                        <select name="brand_term_ids[]" multiple class="aieo-dmm-brand-select"></select>
                        <span class="description"><?php esc_html_e('Leave empty to apply to any brand.', 'ai-eshop-optimizer'); ?></span>
                    </p>
                    <p>
                        <label><?php esc_html_e('Categories', 'ai-eshop-optimizer'); ?></label>
                        <select name="category_term_ids[]" multiple class="aieo-dmm-category-select"></select>
                        <span class="description"><?php esc_html_e('Leave empty to apply to any category.', 'ai-eshop-optimizer'); ?></span>
                    </p>
                    <p>
                        <label><?php esc_html_e('Needs', 'ai-eshop-optimizer'); ?></label>
                        <select name="need_term_ids[]" multiple class="aieo-dmm-need-select"></select>
                        <span class="description"><?php esc_html_e('Leave empty to apply to any need.', 'ai-eshop-optimizer'); ?></span>
                    </p>
                    <p>
                        <label><?php esc_html_e('Minimum qualifying subtotal', 'ai-eshop-optimizer'); ?></label>
                        <input type="number" name="min_subtotal" step="0.01" min="0" value="0">
                        <span class="description"><?php esc_html_e('0 = no minimum; the rule applies to every matching cart.', 'ai-eshop-optimizer'); ?></span>
                    </p>
                    <p>
                        <label><?php esc_html_e('Threshold scope', 'ai-eshop-optimizer'); ?></label>
                        <select name="min_subtotal_scope">
                            <option value="cart_total"><?php esc_html_e('Whole cart total', 'ai-eshop-optimizer'); ?></option>
                            <option value="targeted"><?php esc_html_e('Subtotal of matching items only', 'ai-eshop-optimizer'); ?></option>
                        </select>
                        <span class="description"><?php esc_html_e('"Whole cart total" = sum of every line. "Subtotal of matching items" = only lines hit by the filters above.', 'ai-eshop-optimizer'); ?></span>
                    </p>
                </div>

                <div style="margin-top:14px;">
                    <?php echo AIEO_DMM_Product_Picker::render_field(array(
                        'name'     => 'product_ids',
                        'mode'     => 'include',
                        'label'    => __('Specific products (optional)', 'ai-eshop-optimizer'),
                        'help'     => __('Pick simple products, whole variable products, or specific variations. When set, the rule applies ONLY when the cart contains at least one of these (a positive whitelist, in addition to the targeting filters above). Variations roll up to their parent.', 'ai-eshop-optimizer'),
                        'selected' => isset($edit_product_ids) ? $edit_product_ids : array(),
                    )); ?>
                </div>
                <p>
                    <label><strong><?php esc_html_e('Combine targeting filters with', 'ai-eshop-optimizer'); ?></strong></label>
                    <span class="description" style="display:block;">
                        <label class="aieo-dmm-choice"><input type="radio" name="rule_operator" value="AND" checked> <strong>AND</strong> — <?php esc_html_e('every set targeting filter must match (brand AND category AND need AND specific-products), with the cart totalling at least the minimum subtotal', 'ai-eshop-optimizer'); ?></label>
                    </span>
                    <span class="description" style="display:block;">
                        <label class="aieo-dmm-choice"><input type="radio" name="rule_operator" value="OR"> <strong>OR</strong> — <?php esc_html_e('any non-empty targeting filter that hits qualifies the offer, OR the whole cart reaches the minimum subtotal', 'ai-eshop-optimizer'); ?></label>
                    </span>
                </p>
                <p>
                    <label class="aieo-dmm-choice" style="margin-top:8px;">
                        <input type="checkbox" name="enabled" value="1" checked>
                        <?php esc_html_e('Enabled', 'ai-eshop-optimizer'); ?>
                    </label>
                </p>

                <details style="margin:14px 0;">
                    <summary style="cursor:pointer;font-weight:600;color:#1f2937;"><?php esc_html_e('Show exclusions ▾', 'ai-eshop-optimizer'); ?></summary>
                    <p class="description" style="margin:6px 0 8px;">
                        <?php esc_html_e('Negative filters — when the cart contains any product matching one of these, the rule does NOT apply (overrides positive targeting).', 'ai-eshop-optimizer'); ?>
                    </p>
                    <div class="aieo-dmm-grid">
                        <p>
                            <label><?php esc_html_e('Excluded brands', 'ai-eshop-optimizer'); ?></label>
                            <select name="excluded_brand_ids[]" multiple class="aieo-dmm-brand-select"></select>
                        </p>
                        <p>
                            <label><?php esc_html_e('Excluded categories', 'ai-eshop-optimizer'); ?></label>
                            <select name="excluded_category_ids[]" multiple class="aieo-dmm-category-select"></select>
                        </p>
                        <p>
                            <label><?php esc_html_e('Excluded needs', 'ai-eshop-optimizer'); ?></label>
                            <select name="excluded_need_ids[]" multiple class="aieo-dmm-need-select"></select>
                        </p>
                    </div>
                    <div style="margin-top:10px;">
                        <?php echo AIEO_DMM_Product_Picker::render_field(array(
                            'name'     => 'excluded_product_ids',
                            'mode'     => 'exclude',
                            'label'    => __('Excluded specific products', 'ai-eshop-optimizer'),
                            'help'     => __('When the cart contains ANY of these products, the rule does NOT apply (overrides positive targeting). Variations roll up to their parent.', 'ai-eshop-optimizer'),
                            'selected' => isset($edit_excluded_product_ids) ? $edit_excluded_product_ids : array(),
                        )); ?>
                    </div>
                </details>

                <!-- ============================================================
                     Type-specific actionable section (free-shipping only here).
                     This is what differs between offer types — gifts have a
                     gift product picker, discounts have %/fixed selectors,
                     free-shipping has an action selector.
                     ============================================================ -->
                <h3 style="margin:24px 0 6px;"><?php esc_html_e('Action when matched', 'ai-eshop-optimizer'); ?></h3>
                <p class="description" style="margin:0 0 8px;">
                    <?php esc_html_e('What happens at checkout when a cart satisfies the eligibility above.', 'ai-eshop-optimizer'); ?>
                </p>
                <p>
                    <select name="action_kind">
                        <option value="force_free"><?php esc_html_e('Force every shipping rate to free', 'ai-eshop-optimizer'); ?></option>
                        <option value="force_free_first"><?php esc_html_e('Force only the cheapest rate to free', 'ai-eshop-optimizer'); ?></option>
                    </select>
                </p>

                <p class="submit">
                    <button type="submit" class="button button-primary" data-action="aieo_dmm_free_shipping_save_rule">
                        <?php esc_html_e('Save free-shipping rule', 'ai-eshop-optimizer'); ?>
                    </button>
                </p>
            </form>

            <h3 style="margin-top:18px;"><?php esc_html_e('Existing rules', 'ai-eshop-optimizer'); ?></h3>
            <?php if (empty($rules)): ?>
                <p><em><?php esc_html_e('No unified rules yet. Create one above.', 'ai-eshop-optimizer'); ?></em></p>
            <?php else: ?>
                <table class="widefat striped">
                    <thead>
                        <tr>
                            <th><?php esc_html_e('Label', 'ai-eshop-optimizer'); ?></th>
                            <th><?php esc_html_e('Brands', 'ai-eshop-optimizer'); ?></th>
                            <th><?php esc_html_e('Categories', 'ai-eshop-optimizer'); ?></th>
                            <th><?php esc_html_e('Op', 'ai-eshop-optimizer'); ?></th>
                            <th><?php esc_html_e('Threshold', 'ai-eshop-optimizer'); ?></th>
                            <th><?php esc_html_e('Scope', 'ai-eshop-optimizer'); ?></th>
                            <th><?php esc_html_e('Action', 'ai-eshop-optimizer'); ?></th>
                            <th><?php esc_html_e('Enabled', 'ai-eshop-optimizer'); ?></th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                    <?php foreach ($rules as $r):
                        $brands = json_decode((string) ($r['brand_term_ids'] ?? '[]'), true) ?: array();
                        $cats   = json_decode((string) ($r['category_term_ids'] ?? '[]'), true) ?: array();
                        $payload = json_decode((string) ($r['payload'] ?? '{}'), true) ?: array();
                        $action  = isset($payload['action']) ? (string) $payload['action'] : 'force_free';
                        ?>
                        <tr>
                            <td><strong><?php echo esc_html($r['label']); ?></strong> <span style="color:#888;">#<?php echo (int) $r['id']; ?></span></td>
                            <td><?php echo esc_html(empty($brands) ? __('(any)', 'ai-eshop-optimizer') : count($brands) . ' selected'); ?></td>
                            <td><?php echo esc_html(empty($cats) ? __('(any)', 'ai-eshop-optimizer') : count($cats) . ' selected'); ?></td>
                            <td><code><?php echo esc_html($r['rule_operator']); ?></code></td>
                            <td><?php echo esc_html(wc_price((float) $r['min_subtotal'])); ?></td>
                            <td><code><?php echo esc_html($r['min_subtotal_scope']); ?></code></td>
                            <td><code><?php echo esc_html($action); ?></code></td>
                            <td><?php echo (int) $r['enabled'] ? '✓' : '—'; ?></td>
                            <td><button type="button" class="button button-small aieo-dmm-delete-row" data-action="aieo_dmm_free_shipping_delete_rule" data-id="<?php echo (int) $r['id']; ?>"><?php esc_html_e('Delete', 'ai-eshop-optimizer'); ?></button></td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            <?php endif; ?>
        </div>
        <?php
    }

    
    
    public static function add_eligibility_row($rows, $product_id, $audience_key) {
        if (!is_array($rows)) { $rows = array(); }
        if ((int) $product_id !== 0) { return $rows; }
        if (!class_exists('AIEO_Effective_Eligibility')) { return $rows; }
        $rows[AIEO_Effective_Eligibility::SURFACE_FREE_SHIPPING_BAR] = self::is_audience_eligible((string) $audience_key);
        return $rows;
    }

    
    public static function is_audience_eligible($audience_key = 'guest') {
        if (class_exists('AIEO_DMM_Settings')) {
            if (!AIEO_DMM_Settings::is_module_enabled('free_shipping')) { return array('eligible' => false); }
        }
        $instance = self::eligibility_instance();
        $s = $instance->get_settings();
        $enabled   = isset($s['enabled']) ? ($s['enabled'] === 'yes') : false;
        $threshold = isset($s['free_shipping_threshold']) ? (float) $s['free_shipping_threshold'] : 0.0;
        if (!$enabled || $threshold <= 0) { return array('eligible' => false); }
        return array(
            'eligible' => true,
            'offer_id' => null,
            'payload'  => array(
                'threshold'    => $threshold,
                'msg_initial'  => isset($s['msg_initial'])  ? (string) $s['msg_initial']  : '',
                'msg_progress' => isset($s['msg_progress']) ? (string) $s['msg_progress'] : '',
                'msg_success'  => isset($s['msg_success'])  ? (string) $s['msg_success']  : '',
            ),
        );
    }

    private static function eligibility_instance() {
        static $inst = null;
        if ($inst === null) {
            if (class_exists('AIEO_DMM') && method_exists('AIEO_DMM', 'instance')) {
                $mod = AIEO_DMM::instance()->get_module('free_shipping');
                $inst = ($mod instanceof self) ? $mod : new self();
            } else {
                $inst = new self();
            }
        }
        return $inst;
    }

    public function get_settings() {
        $stored = get_option(self::OPTION_KEY, array());
        if (!is_array($stored)) {
            $stored = array();
        }
        
        $legacy = get_option('om_fs_settings', array());
        if (!is_array($legacy)) {
            $legacy = array();
        }
        return array_merge(array(
            'enabled'                    => 'yes',
            'free_shipping_threshold'    => isset($legacy['free_shipping_threshold']) ? (float) $legacy['free_shipping_threshold'] : 0,
            'include_tax'                => isset($legacy['include_tax']) ? $legacy['include_tax'] : 'no',
            'msg_initial'                => isset($legacy['msg_initial']) ? (string) $legacy['msg_initial'] : __('Free shipping for orders over {amount}!', 'ai-eshop-optimizer'),
            'msg_progress'               => isset($legacy['msg_progress']) ? (string) $legacy['msg_progress'] : __('Only {remaining} left for free shipping!', 'ai-eshop-optimizer'),
            'msg_success'                => isset($legacy['msg_success']) ? (string) $legacy['msg_success'] : __('You qualified for free shipping!', 'ai-eshop-optimizer'),
            'display_cart'               => isset($legacy['display_cart']) ? $legacy['display_cart'] : 'yes',
            'display_checkout'           => isset($legacy['display_checkout']) ? $legacy['display_checkout'] : 'yes',
            'display_mini_cart'          => isset($legacy['display_mini_cart']) ? $legacy['display_mini_cart'] : 'yes',
            'display_product'            => isset($legacy['display_product']) ? $legacy['display_product'] : 'no',
            'display_floating'           => isset($legacy['display_floating']) ? $legacy['display_floating'] : 'no',
            'default_country'            => isset($legacy['default_country']) ? $legacy['default_country'] : '',
            'default_postcode'           => isset($legacy['default_postcode']) ? $legacy['default_postcode'] : '',
            
            
            
            
            'bar_height'                 => isset($legacy['bar_height']) ? (int) $legacy['bar_height'] : 8,
            'bar_border_radius'          => isset($legacy['bar_border_radius']) ? (int) $legacy['bar_border_radius'] : 4,
            'bar_bg_color'               => isset($legacy['bar_bg_color']) ? (string) $legacy['bar_bg_color'] : '#e0e0e0',
            'bar_progress_color'         => isset($legacy['bar_progress_color']) ? (string) $legacy['bar_progress_color'] : '#4caf50',
            'text_color'                 => isset($legacy['text_color']) ? (string) $legacy['text_color'] : '#333333',
            'success_color'              => isset($legacy['success_color']) ? (string) $legacy['success_color'] : '#2e7d32',
            'amount_color'               => isset($legacy['amount_color']) ? (string) $legacy['amount_color'] : '#e65100',
            'font_size'                  => isset($legacy['font_size']) ? (int) $legacy['font_size'] : 14,
            'card_bg_color'              => isset($legacy['card_bg_color']) ? (string) $legacy['card_bg_color'] : '#ffffff',
            'card_padding'               => isset($legacy['card_padding']) ? (int) $legacy['card_padding'] : 16,
            'card_border_radius'         => isset($legacy['card_border_radius']) ? (int) $legacy['card_border_radius'] : 8,
            'card_border_color'          => isset($legacy['card_border_color']) ? (string) $legacy['card_border_color'] : '#e0e0e0',
            
            
            'notify_on_add_to_cart'      => 'yes',
            'notify_message'             => __('Note: this product is not eligible for free shipping. Your order total will be charged for shipping regardless of amount.', 'ai-eshop-optimizer'),
            'notify_type'                => 'notice', 

            
            
            
            
            
            
            'cod_enabled'                => 'no',
            'cod_fee'                    => 1.50,
            'cod_label'                  => __('Κόστος Αντικαταβολής', 'ai-eshop-optimizer'),
            'cod_taxable'                => 'no',
            'cod_gateway_slug'           => 'cod', 
            
            
            
            'weight_exclusion_enabled'   => 'no',
            'max_cart_weight'            => 0,
            'weight_notify_message'      => __('Heads up: your cart is heavier than our free-shipping limit, so shipping will be charged on this order.', 'ai-eshop-optimizer'),
        ), $stored);
    }

    
    public function notify_on_add_to_cart($cart_item_key, $product_id, $quantity = 0, $variation_id = 0, $variation = array(), $cart_item_data = array()) {
        if (!function_exists('wc_add_notice') || !class_exists('AIEO_DMM_Pricing_Engine')) {
            return;
        }
        
        
        $check_id = $variation_id > 0 ? (int) $variation_id : (int) $product_id;
        if ($check_id <= 0) { return; }

        if (AIEO_DMM_Pricing_Engine::instance()->is_excluded_from_free_shipping($check_id)) {
            $settings = $this->get_settings();
            $msg = isset($settings['notify_message']) && $settings['notify_message'] !== ''
                ? (string) $settings['notify_message']
                : __('Note: this product is not eligible for free shipping.', 'ai-eshop-optimizer');
            $type = (isset($settings['notify_type']) && $settings['notify_type'] === 'error') ? 'error' : 'notice';
            
            
            wc_add_notice($msg, $type);
        }
    }

    
    public function render_product_page_notice() {
        if (!function_exists('wc_get_product') || !class_exists('AIEO_DMM_Pricing_Engine')) {
            return;
        }
        global $product;
        if (!$product || !is_a($product, 'WC_Product')) {
            return;
        }
        $pid = (int) $product->get_id();
        if (!AIEO_DMM_Pricing_Engine::instance()->is_excluded_from_free_shipping($pid)) {
            return;
        }
        $settings = $this->get_settings();
        $msg = isset($settings['notify_message']) && $settings['notify_message'] !== ''
            ? (string) $settings['notify_message']
            : __('Note: this product is not eligible for free shipping.', 'ai-eshop-optimizer');
        echo '<div class="aieo-dmm-nfs-product-notice" style="margin:10px 0; padding:10px 14px; background:#fef7e0; border-left:3px solid #f59e0b; border-radius:4px; font-size:14px; color:#78350f;">';
        echo esc_html($msg);
        echo '</div>';
    }

    
    public function enqueue_css_vars() {
        if (!$this->should_emit_css()) { return; }
        $s = $this->get_settings();
        $vars = sprintf(
            ':root{'
          . '--om-fs-bar-h:%dpx;--om-fs-bar-r:%dpx;'
          . '--om-fs-bar-bg:%s;--om-fs-bar-fg:%s;'
          . '--om-fs-text:%s;--om-fs-success:%s;--om-fs-amount:%s;'
          . '--om-fs-font:%dpx;'
          . '--om-fs-card-bg:%s;--om-fs-card-p:%dpx;--om-fs-card-r:%dpx;--om-fs-card-b:%s;'
          . '}',
            (int) $s['bar_height'],
            (int) $s['bar_border_radius'],
            $s['bar_bg_color'] ?: '#e0e0e0',
            $s['bar_progress_color'] ?: '#4caf50',
            $s['text_color'] ?: '#333333',
            $s['success_color'] ?: '#2e7d32',
            $s['amount_color'] ?: '#e65100',
            (int) $s['font_size'],
            $s['card_bg_color'] ?: '#ffffff',
            (int) $s['card_padding'],
            (int) $s['card_border_radius'],
            $s['card_border_color'] ?: '#e0e0e0'
        );
        
        
        
        if (wp_style_is('om-free-shipping', 'enqueued')) {
            wp_add_inline_style('om-free-shipping', $vars);
            return;
        }
        $handle = 'aieo-dmm-free-shipping-vars';
        wp_register_style($handle, false, array(), AIEO_VERSION);
        wp_enqueue_style($handle);
        wp_add_inline_style($handle, $vars);
    }

    private function should_emit_css() {
        
        
        $s = $this->get_settings();
        if (!empty($s['display_floating']) && $s['display_floating'] === 'yes') { return true; }
        if (function_exists('is_cart') && is_cart())         { return true; }
        if (function_exists('is_checkout') && is_checkout()) { return true; }
        if (function_exists('is_product') && is_product())   { return true; }
        
        return AIEO_DMM_Settings::is_module_enabled('side_cart')
            || AIEO_DMM_Settings::get('side_cart_enabled', false);
    }

    public function enqueue_admin_assets() {
        
        wp_enqueue_style('wp-color-picker');
        wp_enqueue_script('wp-color-picker');
        wp_add_inline_script('wp-color-picker',
            'jQuery(function($){$(".aieo-dmm-fs-color").wpColorPicker();});'
        );
    }

    public function ajax_save() {
        AIEO_DMM::verify_ajax_request();

        
        
        
        
        
        
        $section = isset($_POST['form_section']) ? sanitize_key(wp_unslash($_POST['form_section'])) : '';
        if (!in_array($section, array('eligibility', 'display', 'cod'), true)) {
            
            
            $section = '';
        }

        $current = $this->get_settings();
        $patch = array();

        if ($section === '' || $section === 'eligibility') {
            $patch['enabled']                  = !empty($_POST['enabled']) ? 'yes' : 'no';
            $patch['free_shipping_threshold']  = isset($_POST['free_shipping_threshold']) ? (float) $_POST['free_shipping_threshold'] : 0;
            $patch['include_tax']              = !empty($_POST['include_tax']) ? 'yes' : 'no';
            $patch['default_country']          = isset($_POST['default_country']) ? sanitize_text_field(wp_unslash($_POST['default_country'])) : '';
            $patch['default_postcode']         = isset($_POST['default_postcode']) ? sanitize_text_field(wp_unslash($_POST['default_postcode'])) : '';
            $patch['weight_exclusion_enabled'] = !empty($_POST['weight_exclusion_enabled']) ? 'yes' : 'no';
            $patch['max_cart_weight']          = isset($_POST['max_cart_weight']) ? max(0, (float) $_POST['max_cart_weight']) : 0;
            $patch['weight_notify_message']    = isset($_POST['weight_notify_message']) ? sanitize_textarea_field(wp_unslash($_POST['weight_notify_message'])) : '';
        }

        if ($section === '' || $section === 'cod') {
            $patch['cod_enabled']      = !empty($_POST['cod_enabled']) ? 'yes' : 'no';
            $patch['cod_fee']          = isset($_POST['cod_fee']) ? max(0, (float) $_POST['cod_fee']) : 0;
            $patch['cod_label']        = isset($_POST['cod_label']) ? mb_substr(sanitize_text_field(wp_unslash($_POST['cod_label'])), 0, 100) : '';
            $patch['cod_taxable']      = !empty($_POST['cod_taxable']) ? 'yes' : 'no';
            $patch['cod_gateway_slug'] = isset($_POST['cod_gateway_slug']) ? sanitize_key(wp_unslash($_POST['cod_gateway_slug'])) : 'cod';
            if ($patch['cod_label'] === '') {
                $patch['cod_label'] = __('Κόστος Αντικαταβολής', 'ai-eshop-optimizer');
            }
            if ($patch['cod_gateway_slug'] === '') {
                $patch['cod_gateway_slug'] = 'cod';
            }
        }

        if ($section === '' || $section === 'display') {
            $patch['msg_initial']            = isset($_POST['msg_initial']) ? sanitize_text_field(wp_unslash($_POST['msg_initial'])) : '';
            $patch['msg_progress']           = isset($_POST['msg_progress']) ? sanitize_text_field(wp_unslash($_POST['msg_progress'])) : '';
            $patch['msg_success']            = isset($_POST['msg_success']) ? sanitize_text_field(wp_unslash($_POST['msg_success'])) : '';
            $patch['display_cart']           = !empty($_POST['display_cart']) ? 'yes' : 'no';
            $patch['display_checkout']       = !empty($_POST['display_checkout']) ? 'yes' : 'no';
            $patch['display_mini_cart']      = !empty($_POST['display_mini_cart']) ? 'yes' : 'no';
            $patch['display_product']        = !empty($_POST['display_product']) ? 'yes' : 'no';
            $patch['display_floating']       = !empty($_POST['display_floating']) ? 'yes' : 'no';
            $patch['notify_on_add_to_cart']  = !empty($_POST['notify_on_add_to_cart']) ? 'yes' : 'no';
            $patch['notify_message']         = isset($_POST['notify_message']) ? sanitize_textarea_field(wp_unslash($_POST['notify_message'])) : '';
            $patch['notify_type']            = (isset($_POST['notify_type']) && sanitize_key(wp_unslash($_POST['notify_type'])) === 'error') ? 'error' : 'notice';

            
            $num_clamps = array(
                'bar_height'         => array(1, 60),
                'bar_border_radius'  => array(0, 40),
                'font_size'          => array(8, 40),
                'card_padding'       => array(0, 80),
                'card_border_radius' => array(0, 40),
            );
            foreach ($num_clamps as $f => $clamp) {
                $v = isset($_POST[$f]) ? (int) $_POST[$f] : 0;
                $patch[$f] = max($clamp[0], min($clamp[1], $v));
            }
            $color_fields = array('bar_bg_color', 'bar_progress_color', 'text_color', 'success_color',
                                  'amount_color', 'card_bg_color', 'card_border_color');
            foreach ($color_fields as $f) {
                $raw = isset($_POST[$f]) ? sanitize_text_field(wp_unslash($_POST[$f])) : '';
                $patch[$f] = sanitize_hex_color($raw) ?: '';
            }
        }

        $data = array_merge($current, $patch);
        update_option(self::OPTION_KEY, $data, false);

        
        update_option('om_fs_settings', $data, false);

        AIEO_DMM_Cache::bump_version('shipping');

        wp_send_json_success(array('message' => __('Free shipping settings saved.', 'ai-eshop-optimizer')));
    }

    public function ajax_add_exclusions() {
        AIEO_DMM::verify_ajax_request();

        $mode = isset($_POST['mode']) && sanitize_key(wp_unslash($_POST['mode'])) === 'replace' ? 'replace' : 'append';

        $ids_raw = isset($_POST['product_ids']) ? sanitize_text_field(wp_unslash($_POST['product_ids'])) : '';
        $ids = preg_split('/[\s,;]+/', $ids_raw, -1, PREG_SPLIT_NO_EMPTY);
        $ids = array_map('absint', $ids);

        
        
        if (!empty($_FILES['csv_file']['tmp_name']) && is_uploaded_file($_FILES['csv_file']['tmp_name'])) {
            $handle = fopen($_FILES['csv_file']['tmp_name'], 'r');
            
            if ($handle) {
                while (($row = fgetcsv($handle)) !== false) {
                    foreach ($row as $cell) {
                        $v = absint($cell);
                        if ($v > 0) {
                            $ids[] = $v;
                        }
                    }
                }
                fclose($handle);
            }
        }
        $ids = array_unique(array_filter($ids));

        if (empty($ids)) {
            wp_send_json_error(array('message' => __('No product IDs received.', 'ai-eshop-optimizer')));
        }

        global $wpdb;
        $tables = array(
            $wpdb->prefix . 'aieo_dmm_no_free_shipping',
            $wpdb->prefix . 'om_no_free_shipping',
        );

        if ($mode === 'replace') {
            foreach ($tables as $table) {
                if (aieo_dmm_table_exists($table)) {
                    
                    $wpdb->query("TRUNCATE TABLE {$table}");
                }
            }
        }

        $added = 0;
        foreach ($ids as $pid) {
            $post = get_post($pid);
            if (!$post || !in_array($post->post_type, array('product', 'product_variation'), true)) {
                continue;
            }
            
            if ($post->post_type === 'product_variation') {
                $pid = (int) $post->post_parent;
            }
            $sku = get_post_meta($pid, '_sku', true);

            foreach ($tables as $table) {
                if (!aieo_dmm_table_exists($table)) {
                    continue;
                }
                $exists = $wpdb->get_var($wpdb->prepare(
                    
                    "SELECT 1 FROM {$table} WHERE product_id = %d LIMIT 1",
                    $pid
                ));
                if (!$exists) {
                    $wpdb->insert($table, array(
                        'product_id' => $pid,
                        'sku' => (string) $sku,
                    ), array('%d', '%s'));
                    $added++;
                }
            }
        }

        AIEO_DMM_Cache::bump_version('shipping');
        wp_cache_delete('om_no_free_shipping_ids', 'om_shipping');

        wp_send_json_success(array(
            'added' => $added,
            'message' => sprintf(
                
                _n('%d product excluded from free shipping.', '%d products excluded from free shipping.', $added, 'ai-eshop-optimizer'),
                $added
            ),
        ));
    }

    public function ajax_remove_exclusion() {
        AIEO_DMM::verify_ajax_request();

        $pid = isset($_POST['product_id']) ? absint(wp_unslash($_POST['product_id'])) : 0;
        if ($pid <= 0) {
            wp_send_json_error(array('message' => __('Invalid id.', 'ai-eshop-optimizer')));
        }
        global $wpdb;
        foreach (array($wpdb->prefix . 'aieo_dmm_no_free_shipping', $wpdb->prefix . 'om_no_free_shipping') as $table) {
            if (aieo_dmm_table_exists($table)) {
                $wpdb->delete($table, array('product_id' => $pid), array('%d'));
            }
        }
        AIEO_DMM_Cache::bump_version('shipping');
        wp_cache_delete('om_no_free_shipping_ids', 'om_shipping');
        wp_send_json_success();
    }

    public function ajax_export_exclusions() {
        AIEO_DMM::verify_ajax_request();

        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_no_free_shipping';
        if (!aieo_dmm_table_exists($table)) {
            wp_send_json_error(array('message' => __('Table missing.', 'ai-eshop-optimizer')));
        }
        
        $rows = $wpdb->get_results("SELECT product_id, sku FROM {$table} ORDER BY product_id ASC", ARRAY_A);

        $dir = AIEO_DMM::get_upload_path('exports');
        $filename = 'no-free-shipping-' . gmdate('Ymd-His') . '.csv';
        $path = trailingslashit($dir['path']) . $filename;
        $url  = trailingslashit($dir['url']) . $filename;

        $h = fopen($path, 'w');
        AIEO_DMM_Sample::write_csv_bom($h);
        fputcsv($h, array('product_id', 'sku'));
        foreach ((array) $rows as $row) {
            fputcsv($h, $row);
        }
        fclose($h);

        wp_send_json_success(array('url' => $url, 'filename' => $filename));
    }

    private function fetch_exclusions($per_page, $page) {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_no_free_shipping';
        if (!aieo_dmm_table_exists($table)) {
            return array();
        }
        $offset = max(0, ((int) $page - 1) * (int) $per_page);
        $rows = $wpdb->get_results($wpdb->prepare(
            
            "SELECT * FROM {$table} ORDER BY product_id ASC LIMIT %d OFFSET %d",
            (int) $per_page,
            $offset
        ), ARRAY_A);
        if (!is_array($rows)) {
            return array();
        }
        foreach ($rows as &$row) {
            $post = get_post((int) $row['product_id']);
            $row['title'] = $post ? $post->post_title : '';
        }
        return $rows;
    }

    private function count_exclusions() {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_no_free_shipping';
        if (!aieo_dmm_table_exists($table)) {
            return 0;
        }
        
        return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table}");
    }

    
    public function filter_package_rates($rates, $package) {
        if (empty($rates) || empty($package['contents']) || !is_array($package['contents'])) {
            return $rates;
        }

        $engine = AIEO_DMM_Pricing_Engine::instance();
        $gate   = AIEO_DMM_Settings::get('recipe.no_free_shipping_gate', 'hard');
        $s      = $this->get_settings();

        
        $hit_product = false;
        foreach ($package['contents'] as $item) {
            $pid = !empty($item['variation_id']) ? (int) $item['variation_id'] : (int) $item['product_id'];
            if ($engine->is_excluded_from_free_shipping($pid)) {
                $hit_product = true;
                break;
            }
        }

        
        
        
        
        $hit_weight = false;
        $weight_enabled = (string) ($s['weight_exclusion_enabled'] ?? 'no') === 'yes';
        $max_weight     = (float) ($s['max_cart_weight'] ?? 0);
        if ($weight_enabled && $max_weight > 0) {
            $package_weight = 0.0;
            foreach ($package['contents'] as $item) {
                $product = isset($item['data']) ? $item['data'] : null;
                if ($product && is_a($product, 'WC_Product') && $product->has_weight()) {
                    $qty = isset($item['quantity']) ? (float) $item['quantity'] : 1;
                    $package_weight += (float) $product->get_weight() * $qty;
                }
            }
            if ($package_weight > $max_weight) {
                $hit_weight = true;
            }
        }

        if (!$hit_product && !$hit_weight) {
            return $rates;
        }

        if ($gate === 'soft' && !$hit_weight) {
            
            
            
            return $rates;
        }

        
        
        
        
        if ($hit_weight && function_exists('wc_add_notice') && function_exists('is_cart')) {
            $msg = trim((string) ($s['weight_notify_message'] ?? ''));
            if ($msg !== '' && (is_cart() || is_checkout()) && !wc_has_notice($msg, 'notice')) {
                wc_add_notice($msg, 'notice');
            }
        }

        
        foreach (array_keys($rates) as $rate_id) {
            if (strpos($rate_id, 'free_shipping') === 0) {
                unset($rates[$rate_id]);
            }
        }
        return $rates;
    }

    
    
    

    
    public function get_free_shipping_rules() {
        global $wpdb;
        $tbl = $wpdb->prefix . 'aieo_dmm_offers';
        if (!aieo_dmm_table_exists($tbl)) { return array(); }
        $today = current_time('Y-m-d');
        
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$tbl}
             WHERE type = 'free_shipping' AND enabled = 1
               AND (start_date IS NULL OR start_date <= %s)
               AND (end_date   IS NULL OR end_date   >= %s)
             ORDER BY priority ASC, id ASC",
            $today, $today
        ), ARRAY_A);
        if (!is_array($rows)) { return array(); }

        
        foreach ($rows as &$row) {
            foreach (array('brand_term_ids','category_term_ids','need_term_ids','product_ids',
                           'excluded_brand_ids','excluded_category_ids','excluded_need_ids','excluded_product_ids',
                           'customer_role_slugs','customer_segment_ids') as $k) {
                $row[$k] = isset($row[$k]) ? json_decode((string) $row[$k], true) : array();
                if (!is_array($row[$k])) { $row[$k] = array(); }
            }
            $row['payload'] = isset($row['payload']) ? json_decode((string) $row['payload'], true) : array();
            if (!is_array($row['payload'])) { $row['payload'] = array(); }
            $row['display'] = isset($row['display']) ? json_decode((string) $row['display'], true) : array();
            if (!is_array($row['display'])) { $row['display'] = array(); }
        }
        unset($row);
        return $rows;
    }

    
    public function apply_unified_free_shipping_rules($rates, $package) {
        if (empty($rates) || empty($package['contents']) || !is_array($package['contents'])) {
            return $rates;
        }
        $rules = $this->get_free_shipping_rules();
        if (empty($rules)) { return $rates; }

        
        
        
        $matched = AIEO_DMM_Offer_Matcher::for_cart((array) $package['contents'], $rules);
        $any_qualifies = false;
        foreach ($matched as $rule) {
            if (!empty($rule['_qualified'])) { $any_qualifies = true; break; }
        }
        if (!$any_qualifies) { return $rates; }

        
        
        
        $action = 'force_free';
        foreach ($matched as $rule) {
            if (!empty($rule['_qualified']) && !empty($rule['payload']['action'])) {
                $action = (string) $rule['payload']['action'];
                break;
            }
        }

        if ($action === 'force_free') {
            foreach ($rates as $rate_id => $rate) {
                if (is_object($rate) && method_exists($rate, 'set_cost')) {
                    $rate->set_cost('0');
                    if (method_exists($rate, 'set_taxes')) { $rate->set_taxes(array()); }
                    $rates[$rate_id] = $rate;
                }
            }
        } elseif ($action === 'force_free_first') {
            $cheapest_id = null;
            $cheapest_cost = PHP_FLOAT_MAX;
            foreach ($rates as $rate_id => $rate) {
                $cost = (float) (is_object($rate) && method_exists($rate, 'get_cost') ? $rate->get_cost() : 0);
                if ($cost < $cheapest_cost) {
                    $cheapest_cost = $cost;
                    $cheapest_id = $rate_id;
                }
            }
            if ($cheapest_id !== null) {
                $rate = $rates[$cheapest_id];
                if (is_object($rate) && method_exists($rate, 'set_cost')) {
                    $rate->set_cost('0');
                    if (method_exists($rate, 'set_taxes')) { $rate->set_taxes(array()); }
                    $rates[$cheapest_id] = $rate;
                }
            }
        }

        return $rates;
    }

    
    public function ajax_save_rule() {
        AIEO_DMM::verify_ajax_request();
        global $wpdb;
        $tbl = $wpdb->prefix . 'aieo_dmm_offers';
        if (!aieo_dmm_table_exists($tbl)) {
            wp_send_json_error(array('message' => __('Unified offers table missing — re-activate the plugin.', 'ai-eshop-optimizer')));
        }

        $id = isset($_POST['id']) ? absint(wp_unslash($_POST['id'])) : 0;

        $brand_ids = isset($_POST['brand_term_ids']) && is_array($_POST['brand_term_ids'])
            ? array_values(array_filter(array_map('absint', wp_unslash($_POST['brand_term_ids']))))
            : array();
        $cat_ids = isset($_POST['category_term_ids']) && is_array($_POST['category_term_ids'])
            ? array_values(array_filter(array_map('absint', wp_unslash($_POST['category_term_ids']))))
            : array();
        $need_ids = isset($_POST['need_term_ids']) && is_array($_POST['need_term_ids'])
            ? array_values(array_filter(array_map('absint', wp_unslash($_POST['need_term_ids']))))
            : array();
        $excl_brand = isset($_POST['excluded_brand_ids']) && is_array($_POST['excluded_brand_ids'])
            ? array_values(array_filter(array_map('absint', wp_unslash($_POST['excluded_brand_ids']))))
            : array();
        $excl_cat = isset($_POST['excluded_category_ids']) && is_array($_POST['excluded_category_ids'])
            ? array_values(array_filter(array_map('absint', wp_unslash($_POST['excluded_category_ids']))))
            : array();

        
        
        
        $positive_product_ids = AIEO_DMM_Product_Picker::roll_up_to_parents(
            AIEO_DMM_Product_Picker::collect_ids('product_ids')
        );
        $excluded_product_ids = AIEO_DMM_Product_Picker::roll_up_to_parents(
            AIEO_DMM_Product_Picker::collect_ids('excluded_product_ids')
        );

        $rule_op = isset($_POST['rule_operator']) && strtoupper(sanitize_key(wp_unslash($_POST['rule_operator']))) === 'OR' ? 'OR' : 'AND';
        $threshold = isset($_POST['min_subtotal']) ? (float) $_POST['min_subtotal'] : 0;
        $threshold_scope = isset($_POST['min_subtotal_scope']) && sanitize_key(wp_unslash($_POST['min_subtotal_scope'])) === 'targeted' ? 'targeted' : 'cart_total';
        $action = isset($_POST['action_kind']) && sanitize_key(wp_unslash($_POST['action_kind'])) === 'force_free_first' ? 'force_free_first' : 'force_free';

        
        
        if (empty($brand_ids) && empty($cat_ids) && empty($need_ids) && $threshold <= 0) {
            wp_send_json_error(array('message' => __('Set a brand, category, need, or minimum subtotal — otherwise the rule applies unconditionally.', 'ai-eshop-optimizer')));
        }

        $data = array(
            'type'                  => 'free_shipping',
            'enabled'               => !empty($_POST['enabled']) ? 1 : 0,
            'label'                 => isset($_POST['label']) ? sanitize_text_field(wp_unslash($_POST['label'])) : '',
            'priority'              => 100,
            'rule_operator'         => $rule_op,
            'brand_term_ids'        => wp_json_encode($brand_ids),
            'category_term_ids'     => wp_json_encode($cat_ids),
            'need_term_ids'         => wp_json_encode($need_ids),
            'product_ids'           => wp_json_encode($positive_product_ids),
            'excluded_brand_ids'    => wp_json_encode($excl_brand),
            'excluded_category_ids' => wp_json_encode($excl_cat),
            'excluded_product_ids'  => wp_json_encode($excluded_product_ids),
            'min_subtotal'          => $threshold,
            'min_subtotal_scope'    => $threshold_scope,
            'application_scope'     => 'whole_cart',         
            'payload'               => wp_json_encode(array('action' => $action)),
        );
        $formats = array('%s','%d','%s','%d','%s','%s','%s','%s','%s','%s','%s','%s','%f','%s','%s','%s');

        if ($id > 0) {
            
            $wpdb->update($tbl, $data, array('id' => $id), $formats, array('%d'));
        } else {
            $wpdb->insert($tbl, $data, $formats);
            $id = (int) $wpdb->insert_id;
        }

        wp_send_json_success(array(
            'id'      => $id,
            'message' => __('Free-shipping rule saved.', 'ai-eshop-optimizer'),
        ));
    }

    public function ajax_delete_rule() {
        AIEO_DMM::verify_ajax_request();
        global $wpdb;
        $id = isset($_POST['id']) ? absint(wp_unslash($_POST['id'])) : 0;
        if ($id <= 0) {
            wp_send_json_error(array('message' => __('Invalid id.', 'ai-eshop-optimizer')));
        }
        $tbl = $wpdb->prefix . 'aieo_dmm_offers';
        $wpdb->delete($tbl, array('id' => $id, 'type' => 'free_shipping'), array('%d', '%s'));
        wp_send_json_success();
    }

    
    
    
    
    

    
    public function apply_cod_fee_to_cart($cart) {
        if (is_admin() && !defined('DOING_AJAX')) { return; }
        if (!function_exists('WC') || !WC() || !WC()->session) { return; }

        $s = $this->get_settings();
        if ($s['cod_enabled'] !== 'yes') { return; }

        $chosen = (string) WC()->session->get('chosen_payment_method');
        if ($chosen !== (string) $s['cod_gateway_slug']) { return; }

        $fee_amount = (float) $s['cod_fee'];
        
        
        if (class_exists('AIEO_DMM_COD_Country_Block')
            && method_exists('AIEO_DMM_COD_Country_Block', 'cod_fee_override_for_chosen')) {
            $override = AIEO_DMM_COD_Country_Block::cod_fee_override_for_chosen();
            if ($override !== null) { $fee_amount = (float) $override; }
        }
        if ($fee_amount <= 0) { return; }

        $fee_label = (string) $s['cod_label'];
        if ($fee_label === '') { return; }

        $taxable = $s['cod_taxable'] === 'yes';

        
        
        
        
        
        
        
        
        foreach ($cart->get_fees() as $existing) {
            $existing_name = isset($existing->name) ? (string) $existing->name : '';
            if (mb_strtolower(trim($existing_name)) === mb_strtolower(trim($fee_label))) {
                $existing->amount  = $fee_amount;
                $existing->total   = $fee_amount;
                $existing->taxable = $taxable;
                return;
            }
        }

        $cart->add_fee($fee_label, $fee_amount, $taxable);
    }

    
    public function force_cod_visible_when_aieo_enabled($gateways) {
        
        
        
        
        
        
        
        if (is_admin() && !wp_doing_ajax()) { return $gateways; }
        if (!is_array($gateways)) { return $gateways; }
        $s = $this->get_settings();
        if ($s['cod_enabled'] !== 'yes') { return $gateways; }
        $slug = (string) $s['cod_gateway_slug'];
        if ($slug === '' || isset($gateways[$slug])) { return $gateways; }
        if (!function_exists('WC') || !WC() || !WC()->payment_gateways) { return $gateways; }
        $all = WC()->payment_gateways->payment_gateways();
        if (isset($all[$slug]) && $all[$slug]->enabled === 'yes') {
            $gateways[$slug] = $all[$slug];
        }
        return $gateways;
    }

    
    public function apply_cod_fee_admin($order_id) {
        $s = $this->get_settings();
        if ($s['cod_enabled'] !== 'yes') { return; }

        $order = wc_get_order($order_id);
        if (!$order) { return; }

        $new_method = isset($_POST['_payment_method']) ? wc_clean(wp_unslash($_POST['_payment_method'])) : '';
        if ($new_method !== (string) $s['cod_gateway_slug']) { return; }

        $fee_amount = (float) $s['cod_fee'];
        if ($fee_amount <= 0) { return; }

        $fee_label = (string) $s['cod_label'];
        $taxable   = $s['cod_taxable'] === 'yes';

        
        
        
        foreach ($order->get_items('fee') as $fee_item_id => $fee_item) {
            if (mb_strtolower(trim((string) $fee_item->get_name())) === mb_strtolower(trim($fee_label))) {
                $order->remove_item($fee_item_id);
            }
        }

        $fee = new WC_Order_Item_Fee();
        $fee->set_name($fee_label);
        $fee->set_total(wc_format_decimal($fee_amount));
        $fee->set_props(array('tax_status' => $taxable ? 'taxable' : 'none'));
        $order->add_item($fee);
        $order->calculate_totals();

        if (class_exists('WC_Data_Store')) {
            WC_Data_Store::load('order')->update($order);
        }
    }

    
    public function output_cod_refresh_js() {
        $s = $this->get_settings();
        if ($s['cod_enabled'] !== 'yes') { return; }
        if (!function_exists('is_checkout') || !is_checkout()) { return; }
        if (function_exists('is_wc_endpoint_url') && is_wc_endpoint_url()) { return; }
        ?>
        <script>
            (function(){
                if (typeof jQuery === 'undefined') return;
                jQuery(function($){
                    $(document.body).on('change', 'form.checkout input[name="payment_method"]', function(){
                        $(document.body).trigger('update_checkout');
                    });
                });
            })();
        </script>
        <?php
    }

    
    public function maybe_register_cod_for_blocks() {
        
        
    }
}
