<?php
if (!defined('ABSPATH')) exit;

if (!class_exists('WC_Shipping_Method')) {
    return;
}

class WC_Shipping_5E extends WC_Shipping_Method
{
    public function __construct($instance_id = 0)
    {
        $this->id                 = 'w5e';
        $this->instance_id        = absint($instance_id);
        $this->method_title       = __('5E Shipping', 'woo-5e');
        $this->method_description = __('Shipping via 5E (multiple couriers exposed as WooCommerce rates).', 'woo-5e');
        $this->supports           = ['shipping-zones', 'instance-settings', 'instance-settings-modal'];
        $this->tax_status         = 'none'; // Default to non-taxable; we handle tax inclusion manually below.
        $this->init();
    }
    public function init()
    {
        $this->init_form_fields();
        $this->init_settings();
        $this->init_instance_settings();
        $this->enabled = $this->get_instance_option('enabled', 'yes');
        $this->title   = $this->get_instance_option('title', __('Delivery (5E)', 'woo-5e'));
        if (class_exists('W5E_I18n')) {
            W5E_I18n::register_shipping_title($this->get_instance_option('title'), $this->instance_id);
        }
        add_action("woocommerce_update_options_shipping_{$this->id}", [$this, 'process_admin_options']);
        add_action("woocommerce_update_options_shipping_{$this->id}_{$this->instance_id}", [$this, 'process_admin_options']);
        add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']);
    }
    public function init_form_fields()
    {
        $courierChoices = $this->get_enabled_courier_choices();

        $fields = [
            'enabled' => [
                'title' => __('Enable', 'woo-5e'),
                'type' => 'checkbox',
                'label' => __('Enable 5E delivery', 'woo-5e'),
                'default' => 'yes',
            ],
            'title' => [
                'title' => __('Method title', 'woo-5e'),
                'type'  => 'text',
                'default' => __('Delivery (5E)', 'woo-5e'),
            ],
        ];

        if (count($courierChoices) >= 1) {
            $fields['courier_key'] = [
                'title'       => __('Courier selection', 'woo-5e'),
                'type'        => 'select',
                'description' => __('Choose which 5E courier this shipping method instance should use.', 'woo-5e'),
                'options'     => $courierChoices,
                'default'     => '',
            ];
        }

        $fields += [
            'pricing_mode' => [
                'title'       => __('Pricing mode', 'woo-5e'),
                'type'        => 'select',
                'description' => __('Default is Fixed price. If you prefer multiple rates, choose Automatic (matrix/flat) below. The matrix/flat values are managed in the 5E pricing table (WooCommerce > Settings > Shipping > 5E).', 'woo-5e'),
                'default'     => 'fixed_price',
                'options'     => [
                    'fixed_price' => __('Fixed price', 'woo-5e'),
                    'auto'        => __('Automatic (matrix/flat)', 'woo-5e'),
                    'free_over'   => __('Free shipping', 'woo-5e'),
                    'recipient_pays' => __('Recipient pays on delivery', 'woo-5e'),
                ],
            ],
            'fixed_price' => [
                'title'             => __('Fixed delivery price', 'woo-5e'),
                'type'              => 'number',
                'description'       => __('Used when Pricing mode is set to Fixed price.', 'woo-5e'),
                'default'           => '',
                'custom_attributes' => ['step' => '0.01', 'min' => '0'],
            ],
            'recipient_pays_limit' => [
                'title'             => __('Recipient pays below amount', 'woo-5e'),
                'type'              => 'number',
                'description'       => __('When Pricing mode is Recipient pays on delivery, the buyer pays shipping below this cart subtotal. Leave empty to always charge on delivery.', 'woo-5e'),
                'default'           => '',
                'custom_attributes' => ['step' => '0.01', 'min' => '0'],
            ],
            'free_shipping_over' => [
                'title'             => __('Free shipping over amount', 'woo-5e'),
                'type'              => 'number',
                'description'       => __('When Pricing mode is Automatic (matrix/flat) or Fixed price, make shipping free over this cart subtotal. Leave empty to disable.', 'woo-5e'),
                'default'           => '',
                'custom_attributes' => ['step' => '0.01', 'min' => '0'],
            ],
            'requires' => [
                'title'       => __('Free shipping requires', 'woo-5e'),
                'type'        => 'select',
                'description' => __('Applies only when Pricing mode is Free shipping.', 'woo-5e'),
                'default'     => '',
                'options'     => [
                    ''           => __('No requirement', 'woo-5e'),
                    'min_amount' => __('Free over amount', 'woo-5e'),
                    'weight_over' => __('Weight over (kg)', 'woo-5e'),
                ],
            ],
            'min_amount' => [
                'title'             => __('Minimum order amount', 'woo-5e'),
                'type'              => 'number',
                'description'       => __('Used when Pricing mode is Free shipping and condition is Free over amount.', 'woo-5e'),
                'default'           => '0',
                'custom_attributes' => ['step' => '0.01', 'min' => '0'],
            ],
            'free_shipping_weight_over' => [
                'title'             => __('Free shipping weight over (kg)', 'woo-5e'),
                'type'              => 'number',
                'description'       => __('When Pricing mode is Free shipping, make shipping free when cart weight exceeds this value. Leave empty to disable.', 'woo-5e'),
                'default'           => '',
                'custom_attributes' => ['step' => '0.01', 'min' => '0'],
            ],
        ];

        $this->instance_form_fields = $fields;
        $this->form_fields          = $fields;
    }
    public function enqueue_admin_scripts($hook_suffix)
    {
        if (!is_admin()) {
            return;
        }
        // Limit to WooCommerce settings/shipping screens to avoid leaking into other admin pages.
        $allowed_hooks = [
            'woocommerce_page_wc-settings',
            'woocommerce_page_wc-shipping',
        ];
        if (!in_array($hook_suffix, $allowed_hooks, true)) {
            return;
        }
        wc_enqueue_js("
            (function($){
                function w5eToggleFreeOver(){
                    $('select[id$=\"_pricing_mode\"], select[name$=\"[pricing_mode]\"]').each(function() {
                        var modeSelect = $(this);
                        var container = modeSelect.closest('table, form, .wc-shipping-zone-method-settings');
                        var requiresSelect = container.find('select[id$=\"_requires\"], select[name$=\"[requires]\"]').first();
                        var overInput = container.find('input[id$=\"_free_shipping_over\"], input[name$=\"[free_shipping_over]\"]').first();
                        var payerInput = container.find('input[id$=\"_recipient_pays_limit\"], input[name$=\"[recipient_pays_limit]\"]').first();
                        var overRow = overInput.closest('tr');
                        if (!overRow.length) {
                            overRow = overInput.closest('p, .form-field, fieldset');
                        }
                        var payerRow = payerInput.closest('tr');
                        if (!payerRow.length) {
                            payerRow = payerInput.closest('p, .form-field, fieldset');
                        }
                        var mode = modeSelect.val();
                        var hasRequirement = requiresSelect.length && requiresSelect.val() !== '';

                        if (overRow.length) {
                            if (mode === 'free_over' || hasRequirement) {
                                overRow.hide();
                            } else {
                                overRow.show();
                            }
                        }
                        if (payerRow.length) {
                            if (mode === 'recipient_pays') {
                                payerRow.show();
                            } else {
                                payerRow.hide();
                            }
                        }
                    });
                }
                $(document.body).on('change', 'select[id$=\"_pricing_mode\"], select[name$=\"[pricing_mode]\"], select[id$=\"_requires\"], select[name$=\"[requires]\"]', w5eToggleFreeOver);
                $(document.body).on('wc_backbone_modal_loaded', w5eToggleFreeOver);
                w5eToggleFreeOver();
            })(jQuery);
        ");
    }
    public function calculate_shipping($package = [])
    {
        $enabled = get_option('w5e_enabled_partners', []);
        $flat    = get_option('w5e_flat_price', '0');
        $title   = $this->get_instance_option('title');
        $matrix  = get_option('w5e_pricing_matrix', []);
        $weight  = $this->get_package_weight_kg($package);
        $limitTo = $this->get_instance_option('courier_key', '');
        $pricingMode       = $this->get_instance_option('pricing_mode', 'auto');
        $fixedPrice        = $this->to_float($this->get_instance_option('fixed_price', ''), 0.0);
        $requires          = $this->get_instance_option('requires', '');
        $minAmount         = $this->to_float($this->get_instance_option('min_amount', 0), 0.0);
        $ignoreDiscounts   = false;
        $freeShippingApplies = false;
        $subtotal            = $this->get_cart_subtotal($ignoreDiscounts);
        $hasCoupon           = false;
        $passedMin           = ($pricingMode === 'free_over' && $minAmount > 0 && $subtotal >= $minAmount);
        $freeShippingOver     = $this->to_float($this->get_instance_option('free_shipping_over', ''), 0.0);
        $freeShippingWeightOver = $this->to_float($this->get_instance_option('free_shipping_weight_over', ''), 0.0);
        $freeThresholdReached = (in_array($pricingMode, ['auto', 'fixed_price'], true) && $freeShippingOver > 0 && $subtotal >= $freeShippingOver);
        $payerLimit           = $this->to_float($this->get_instance_option('recipient_pays_limit', ''), 0.0);
        $payerMode            = ($pricingMode === 'recipient_pays');
        $payerCustomerPays    = ($payerMode && ($payerLimit <= 0 || $subtotal < $payerLimit));
        $payerNote            = __('Will be charged on delivery per courier tariff.', 'woo-5e');
        $senderNote           = __('Sender pays shipping.', 'woo-5e');

        $freeShippingByMode = false;

        if ($pricingMode === 'free_over') {
            if ($requires === 'weight_over') {
                $freeShippingByMode = ($freeShippingWeightOver > 0 && $weight >= $freeShippingWeightOver);
            } else {
                $freeShippingByMode = $this->is_free_shipping_applicable($requires, $minAmount, $ignoreDiscounts);
            }
        }

        $freeShippingApplies = ($freeShippingByMode || $freeThresholdReached);
        if ($payerMode && !$payerCustomerPays) {
            $freeShippingApplies = true;
        }

        if ($pricingMode === 'fixed_price') {
            $cost     = $freeShippingApplies ? '0' : wc_format_decimal(max(0, $fixedPrice));
            $rateLabel = $title ?: __('Delivery (5E)', 'woo-5e');
            $metaData = [
                'w5e_cost_source' => $freeShippingApplies ? 'free' : 'instance_fixed',
            ];
            $rateIdSuffix = 'fixed';

            if ($limitTo !== '') {
                $parts   = explode('|', $limitTo);
                $pid     = isset($parts[0]) ? intval($parts[0]) : 0;
                $envRaw  = isset($parts[1]) ? sanitize_text_field($parts[1]) : '';
                $envSlug = $envRaw !== '' ? sanitize_title_with_dashes($envRaw) : 'default';
                $partnerLabel = $this->resolve_partner_name_from_cache($pid, $envRaw);

                $metaData['w5e_key']        = $limitTo;
                $metaData['w5e_partner_id'] = $pid;
                $metaData['w5e_env']        = $envRaw;
                $rateIdSuffix               = $pid ? $pid . ':' . $envSlug : $limitTo;
                $rateLabel                  = $title ?: sprintf(__('Delivery - %s', 'woo-5e'), $partnerLabel ?: $rateLabel);
            } elseif (is_array($enabled) && !empty($enabled)) {
                $choiceKey  = '';
                $choiceMeta = null;
                foreach ($enabled as $key => $meta) {
                    if ($choiceKey === '') {
                        $choiceKey  = $key;
                        $choiceMeta = $meta;
                    }
                    if (!empty($meta['default'])) {
                        $choiceKey  = $key;
                        $choiceMeta = $meta;
                        break;
                    }
                }
                if ($choiceKey !== '') {
                    $pid     = intval($choiceMeta['partner_id'] ?? 0);
                    $envRaw  = isset($choiceMeta['env']) ? (string)$choiceMeta['env'] : '';
                    $envSlug = $envRaw !== '' ? sanitize_title_with_dashes($envRaw) : 'default';
                    $partnerLabel = $this->resolve_partner_name_from_cache($pid, $envRaw);

                    $metaData['w5e_key']        = $choiceKey;
                    $metaData['w5e_partner_id'] = $pid;
                    $metaData['w5e_env']        = $envRaw;
                    if (!empty($choiceMeta['default'])) {
                        $metaData['w5e_default'] = '1';
                    }
                    $rateIdSuffix = $pid ? $pid . ':' . $envSlug : $choiceKey;
                    $rateLabel    = $title ?: sprintf(__('Delivery - %s', 'woo-5e'), $partnerLabel ?: $choiceKey);
                }
            } else {
                $metaData['w5e_key'] = 'generic';
                $rateIdSuffix        = 'generic';
            }

            $this->add_rate([
                'id'        => $this->get_rate_id($rateIdSuffix),
                'label'     => $rateLabel,
                'cost'      => $this->adjust_cost_for_tax($cost),
                'meta_data' => $metaData,
            ]);
            return;
        }

        if (is_array($matrix) && isset($matrix['bex']) && !isset($matrix['dexpress'])) {
            $matrix['dexpress'] = $matrix['bex'];
        }

        $addedRate = false;
        $addedIds  = [];

        if ($limitTo !== '') {
            $parts = explode('|', $limitTo);
            $pid = isset($parts[0]) ? intval($parts[0]) : 0;
            $envRaw = isset($parts[1]) ? sanitize_text_field($parts[1]) : '';
            $envSlug = $envRaw !== '' ? sanitize_title_with_dashes($envRaw) : 'default';
            $partnerLabel = $this->resolve_partner_name_from_cache($pid, $envRaw);
            $label        = $partnerLabel ?: ($title ?: __('Courier', 'woo-5e'));
            $labelForCost = $title ?: $label;

            if ($this->should_hide_rate($pricingMode, $requires, $passedMin, $hasCoupon)) {
                return;
            }

            if ($pricingMode === 'fixed_price') {
                $costInfo = [
                    'amount' => wc_format_decimal(max(0, $fixedPrice)),
                    'source' => 'instance_fixed',
                ];
            } elseif ($freeShippingApplies) {
                $costInfo = ['amount' => '0', 'source' => 'free'];
            } else {
                $costInfo = $this->determine_rate_cost($matrix, $weight, $labelForCost, $pid, $flat, $partnerLabel);
            }

            $rateLabel = $title ?: sprintf(__('Delivery - %s', 'woo-5e'), $label);
            if ($payerMode) {
                if ($payerCustomerPays) {
                    $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $payerNote : $payerNote;
                    $costInfo = ['amount' => '0', 'source' => 'recipient_tariff'];
                } else {
                    $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $senderNote : $senderNote;
                    $costInfo = ['amount' => '0', 'source' => 'sender_pays'];
                }
            }

            $this->add_rate([
                'id'        => $this->get_rate_id($pid . ':' . $envSlug),
                'label'     => $rateLabel,
                'cost'      => $this->adjust_cost_for_tax($costInfo['amount']),
                'meta_data' => [
                    'w5e_key'         => $limitTo,
                    'w5e_partner_id'  => $pid,
                    'w5e_env'         => $envRaw,
                    'w5e_cost_source' => $costInfo['source'],
                ],
            ]);
            $addedRate = true;
            $addedIds[] = $this->get_rate_id($pid . ':' . $envSlug);
            return;
        }

        if (class_exists('W5E_I18n')) {
            $title = W5E_I18n::translate_shipping_title($title, $this->instance_id);
        }

        if (!is_array($enabled) || empty($enabled)) {
            $passedMin = ($minAmount > 0 && $this->get_cart_subtotal($ignoreDiscounts) >= $minAmount);
            if ($pricingMode === 'fixed_price') {
                $costInfo = [
                    'amount' => wc_format_decimal(max(0, $fixedPrice)),
                    'source' => 'instance_fixed',
                ];
            } elseif ($freeShippingApplies || ($pricingMode === 'free_over' && $passedMin)) {
                $costInfo = ['amount' => '0', 'source' => 'free'];
            } else {
                $costInfo = $this->determine_rate_cost($matrix, $weight, $title, 0, $flat, $title);
            }
            if ($payerMode) {
                if ($payerCustomerPays) {
                    $title = $title !== '' ? $title . ' — ' . $payerNote : $payerNote;
                    $costInfo = ['amount' => '0', 'source' => 'recipient_tariff'];
                } else {
                    $title = $title !== '' ? $title . ' — ' . $senderNote : $senderNote;
                    $costInfo = ['amount' => '0', 'source' => 'sender_pays'];
                }
            }
            $this->add_rate([
                'id'        => $this->get_rate_id('generic'),
                'label'     => $title,
                'cost'      => $this->adjust_cost_for_tax($costInfo['amount']),
                'meta_data' => [
                    'w5e_key'         => 'generic',
                    'w5e_cost_source' => $costInfo['source'],
                ],
            ]);
            $addedRate = true;
            $addedIds[] = $this->get_rate_id('generic');
            return;
        }
        foreach ($enabled as $key => $meta) {
            $pid     = intval($meta['partner_id'] ?? 0);
            $envRaw  = isset($meta['env']) ? (string)$meta['env'] : '';
            $envSlug = $envRaw !== '' ? sanitize_title_with_dashes($envRaw) : 'default';
            $partnerLabel = $this->resolve_partner_name_from_cache($pid, $envRaw);
            $envSuffix    = $envRaw ? sprintf(__(' (%s)', 'woo-5e'), $envRaw) : '';
            $label        = $partnerLabel ?: sprintf(__('Courier #%1$d%2$s', 'woo-5e'), $pid, $envSuffix);
            $applySpecial = ($limitTo === '' || $limitTo === $key);
            $labelForCost = $title ?: $label;
            $passedMin    = ($pricingMode === 'free_over' && $minAmount > 0 && $this->get_cart_subtotal($ignoreDiscounts) >= $minAmount);

            if ($this->should_hide_rate($pricingMode, $requires, $passedMin, $hasCoupon)) {
                continue;
            }

            $metaData = [
                'w5e_key'        => $key,
                'w5e_partner_id' => $pid,
                'w5e_env'        => $envRaw,
            ];
            if (!empty($meta['default'])) {
                $metaData['w5e_default'] = '1';
            }

            if ($applySpecial) {
                if ($pricingMode === 'fixed_price') {
                    $costInfo = [
                        'amount' => wc_format_decimal(max(0, $fixedPrice)),
                        'source' => 'instance_fixed',
                    ];
                } elseif ($freeShippingApplies || ($pricingMode === 'free_over' && $passedMin)) {
                    $costInfo = ['amount' => '0', 'source' => 'free'];
                } else {
                    $costInfo = $this->determine_rate_cost($matrix, $weight, $labelForCost, $pid, $flat, $partnerLabel);
                }
            } else {
                $costInfo = $this->determine_rate_cost($matrix, $weight, $labelForCost, $pid, $flat, $partnerLabel);
            }
            $rateLabel = $title ?: sprintf(__('Delivery - %s', 'woo-5e'), $label);
            if ($payerMode) {
                if ($payerCustomerPays) {
                    $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $payerNote : $payerNote;
                    $costInfo = ['amount' => '0', 'source' => 'recipient_tariff'];
                } else {
                    $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $senderNote : $senderNote;
                    $costInfo = ['amount' => '0', 'source' => 'sender_pays'];
                }
            }
            $metaData['w5e_cost_source'] = $costInfo['source'];

            $this->add_rate([
                'id'        => $this->get_rate_id($pid . ':' . $envSlug),
                'label'     => $rateLabel,
                'cost'      => $this->adjust_cost_for_tax($costInfo['amount']),
                'meta_data' => $metaData,
            ]);
            $addedRate = true;
            $addedIds[] = $this->get_rate_id($pid . ':' . $envSlug);
        }

        if (!$addedRate) {
            $passedMin = ($pricingMode === 'free_over' && $minAmount > 0 && $this->get_cart_subtotal($ignoreDiscounts) >= $minAmount);
            if ($this->should_hide_rate($pricingMode, $requires, $passedMin, $hasCoupon)) {
                return;
            }
            if ($pricingMode === 'fixed_price') {
                $costInfo = [
                    'amount' => wc_format_decimal(max(0, $fixedPrice)),
                    'source' => 'instance_fixed',
                ];
            } elseif ($freeShippingApplies || ($pricingMode === 'free_over' && $passedMin)) {
                $costInfo = ['amount' => '0', 'source' => 'free'];
            } else {
                $costInfo = $this->determine_rate_cost($matrix, $weight, $title, 0, $flat, $title);
            }
            $rateLabel = $title ?: __('Delivery (5E)', 'woo-5e');
            if ($payerMode) {
                if ($payerCustomerPays) {
                    $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $payerNote : $payerNote;
                    $costInfo = ['amount' => '0', 'source' => 'recipient_tariff'];
                } else {
                    $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $senderNote : $senderNote;
                    $costInfo = ['amount' => '0', 'source' => 'sender_pays'];
                }
            }

            $this->add_rate([
                'id'        => $this->get_rate_id('fallback'),
                'label'     => $rateLabel,
                'cost'      => $this->adjust_cost_for_tax($costInfo['amount']),
                'meta_data' => [
                    'w5e_key'         => 'fallback',
                    'w5e_cost_source' => $costInfo['source'],
                ],
            ]);
        }

        $titleSlug = sanitize_title($title);
        if ($titleSlug && isset($matrix[$titleSlug])) {
            $rateId = $this->get_rate_id('matrix-' . $titleSlug);
            if (!in_array($rateId, $addedIds, true)) {
                $passedMin = ($pricingMode === 'free_over' && $minAmount > 0 && $this->get_cart_subtotal($ignoreDiscounts) >= $minAmount);
                if ($this->should_hide_rate($pricingMode, $requires, $passedMin, $hasCoupon)) {
                    return;
                }
                if ($pricingMode === 'fixed_price') {
                    $costInfo = [
                        'amount' => wc_format_decimal(max(0, $fixedPrice)),
                        'source' => 'instance_fixed',
                    ];
                } elseif ($freeShippingApplies || ($pricingMode === 'free_over' && $passedMin)) {
                    $costInfo = ['amount' => '0', 'source' => 'free'];
                } else {
                    $costInfo = $this->determine_rate_cost($matrix, $weight, $title, 0, $flat, $title);
                }

                $rateLabel = $title ?: sprintf(__('Delivery - %s', 'woo-5e'), $matrixLabel);
                if ($payerMode) {
                    if ($payerCustomerPays) {
                        $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $payerNote : $payerNote;
                        $costInfo = ['amount' => '0', 'source' => 'recipient_tariff'];
                    } else {
                        $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $senderNote : $senderNote;
                        $costInfo = ['amount' => '0', 'source' => 'sender_pays'];
                    }
                }

                $this->add_rate([
                    'id'        => $rateId,
                    'label'     => $rateLabel,
                    'cost'      => $this->adjust_cost_for_tax($costInfo['amount']),
                    'meta_data' => [
                        'w5e_key'         => $titleSlug,
                        'w5e_cost_source' => $costInfo['source'],
                    ],
                ]);
            }
        }

        if (isset($matrix['daily'])) {
            $rateId = $this->get_rate_id('daily');
            if (!in_array($rateId, $addedIds, true)) {
                $costInfo = $this->determine_rate_cost($matrix, $weight, __('DEXPRESS', 'woo-5e'), 0, $flat, 'dexpress');
                $matrixLabel = !empty($matrix['daily']['label']) ? $matrix['daily']['label'] : __('DEXPRESS', 'woo-5e');
                $rateLabel = $title ?: sprintf(__('Delivery - %s', 'woo-5e'), $matrixLabel);
                if ($payerMode) {
                    if ($payerCustomerPays) {
                        $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $payerNote : $payerNote;
                        $costInfo = ['amount' => '0', 'source' => 'recipient_tariff'];
                    } else {
                        $rateLabel = $rateLabel !== '' ? $rateLabel . ' — ' . $senderNote : $senderNote;
                        $costInfo = ['amount' => '0', 'source' => 'sender_pays'];
                    }
                }

                $this->add_rate([
                    'id'        => $rateId,
                    'label'     => $rateLabel,
                    'cost'      => $this->adjust_cost_for_tax(($freeShippingApplies || ($pricingMode === 'free_over' && $passedMin)) ? '0' : $costInfo['amount']),
                    'meta_data' => [
                        'w5e_key'         => 'daily',
                        'w5e_cost_source' => $costInfo['source'],
                    ],
                ]);
            }
        }
    }
    private function resolve_partner_name_from_cache($partnerId, $env)
    {
        $cache = get_option('w5e_couriers_cache', []);
        if (!is_array($cache)) return '';
        foreach ($cache as $row) {
            if (intval($row['PartnerID']) === $partnerId && strtoupper($row['Env']) === strtoupper($env)) {
                return (string)$row['CourierName'];
            }
        }
        foreach ($cache as $row) {
            if (intval($row['PartnerID']) === $partnerId) {
                return (string)$row['CourierName'];
            }
        }
        return '';
    }

    private function get_enabled_courier_choices()
    {
        $enabled = get_option('w5e_enabled_partners', []);
        if (!is_array($enabled) || empty($enabled)) {
            return [];
        }

        $choices = [];
        foreach ($enabled as $key => $meta) {
            $pid       = intval($meta['partner_id'] ?? 0);
            $envRaw    = isset($meta['env']) ? (string)$meta['env'] : '';
            $name      = $this->resolve_partner_name_from_cache($pid, $envRaw);
            if ($name) {
                $choices[$key] = $name;
            } else {
                $choices[$key] = sprintf(__('Courier #%1$d', 'woo-5e'), $pid);
            }
        }

        return $choices;
    }

    public function process_admin_options()
    {
        if (!$this->instance_id) {
            return parent::process_admin_options();
        }

        $this->init_instance_settings();
        $post_data = $this->get_post_data();

        foreach ($this->get_instance_form_fields() as $key => $field) {
            try {
                $this->instance_settings[$key] = $this->get_field_value($key, $field, $post_data);
            } catch (Exception $e) {
                $this->add_error($e->getMessage());
            }
        }

        return update_option(
            $this->get_instance_option_key(),
            apply_filters('woocommerce_shipping_' . $this->id . '_instance_settings_values', $this->instance_settings, $this),
            'yes'
        );
    }

    private function is_min_amount_reached($minAmount, $ignoreDiscounts)
    {
        if ($minAmount <= 0) {
            return true;
        }
        return $this->get_cart_subtotal($ignoreDiscounts) >= $minAmount;
    }

    private function is_free_shipping_applicable($requires, $minAmount, $ignoreDiscounts)
    {
        switch ($requires) {
            case 'min_amount':
                return $this->is_min_amount_reached($minAmount, $ignoreDiscounts);
            default:
                return true;
        }
    }

    private function get_cart_subtotal($ignoreDiscounts)
    {
        $cart = WC()->cart;
        if (!$cart) {
            return 0.0;
        }
        if ($ignoreDiscounts) {
            return (float)$cart->get_subtotal();
        }
        return (float)$cart->get_displayed_subtotal();
    }

    private function has_free_shipping_coupon()
    {
        $cart = WC()->cart;
        if (!$cart) {
            return false;
        }
        $coupons = $cart->get_coupons();
        if (empty($coupons)) {
            return false;
        }
        foreach ($coupons as $coupon) {
            if (is_object($coupon) && method_exists($coupon, 'get_free_shipping') && $coupon->get_free_shipping()) {
                return true;
            }
        }
        return false;
    }

    public static function register_filters()
    {
        add_filter('woocommerce_package_rates', [__CLASS__, 'filter_package_rates'], 20, 2);
        add_filter('woocommerce_shipping_chosen_method', [__CLASS__, 'filter_shipping_chosen_method'], 20, 3);
    }

    public static function filter_package_rates($rates, $package)
    {
        if (empty($rates) || !is_array($rates)) {
            return $rates;
        }

        $defaultRateId = self::find_default_rate_id($rates);
        if (!$defaultRateId || !isset($rates[$defaultRateId])) {
            return $rates;
        }

        $defaultRate = $rates[$defaultRateId];
        unset($rates[$defaultRateId]);

        return array_merge([$defaultRateId => $defaultRate], $rates);
    }

    public static function filter_shipping_chosen_method($default, $rates, $chosen_method)
    {
        if (!is_array($rates) || empty($rates)) {
            return $default;
        }

        if (!empty($chosen_method) && isset($rates[$chosen_method])) {
            return $chosen_method;
        }

        $defaultRateId = self::find_default_rate_id($rates);
        if ($defaultRateId && isset($rates[$defaultRateId])) {
            return $defaultRateId;
        }

        return $default;
    }

    private static function find_default_rate_id($rates)
    {
        foreach ($rates as $rateId => $rate) {
            if (!is_object($rate) || !method_exists($rate, 'get_method_id')) {
                continue;
            }
            if ($rate->get_method_id() !== 'w5e') {
                continue;
            }
            $meta = method_exists($rate, 'get_meta_data') ? $rate->get_meta_data() : [];
            if (!empty($meta['w5e_default'])) {
                return $rateId;
            }
        }
        return '';
    }

    private function get_package_weight_kg($package)
    {
        $weight = 0.0;
        if (empty($package['contents']) || !is_array($package['contents'])) {
            return $weight;
        }
        foreach ($package['contents'] as $item) {
            if (empty($item['data']) || !is_object($item['data'])) {
                continue;
            }
            $product = $item['data'];
            if (method_exists($product, 'needs_shipping') && !$product->needs_shipping()) {
                continue;
            }
            if (!method_exists($product, 'get_weight')) {
                continue;
            }
            $product_weight = $product->get_weight();
            if ($product_weight === '' || $product_weight === null) {
                continue;
            }
            if (function_exists('wc_get_weight')) {
                $product_weight = wc_get_weight($product_weight, 'kg');
            }
            $qty = isset($item['quantity']) ? (int)$item['quantity'] : 1;
            if ($qty < 1) {
                $qty = 1;
            }
            $weight += max(0, (float)$product_weight) * $qty;
        }
        return max(0, (float)$weight);
    }

    private function determine_rate_cost($matrix, $weightKg, $label, $partnerId, $fallback, $altLabel = '')
    {
        $result = $this->resolve_cost_from_matrix($matrix, $weightKg, $label, $partnerId, $altLabel);
        if ($result === null) {
            return [
                'amount' => wc_format_decimal($this->to_float($fallback, 0.0)),
                'source' => 'flat',
                'label'  => '',
            ];
        }
        return [
            'amount' => wc_format_decimal($result['cost']),
            'source' => 'matrix',
            'label'  => $result['label'],
        ];
    }

    private function resolve_cost_from_matrix($matrix, $weightKg, $label, $partnerId, $altLabel = '')
    {
        if (!is_array($matrix) || empty($matrix)) {
            return null;
        }

        $slugPrimary = $this->generate_courier_slug($label, $partnerId);
        $slugAlt     = $altLabel ? sanitize_title($altLabel) : '';
        $partnerSlug = $partnerId ? 'partner-' . absint($partnerId) : '';
        $slugPrimaryLast = $this->extract_last_slug($label);
        $slugAltLast     = $this->extract_last_slug($altLabel);
        $labelSan   = $label ? sanitize_title($label) : '';
        $altSan     = $altLabel ? sanitize_title($altLabel) : '';
        $titleLast  = $this->extract_last_slug($label ?: $altLabel);

        $labelMatchedSlugs = [];
        foreach ($matrix as $mSlug => $data) {
            $matrixLabel = isset($data['label']) ? sanitize_title($data['label']) : '';
            if (!$matrixLabel) continue;
            if (($labelSan && $matrixLabel === $labelSan) || ($altSan && $matrixLabel === $altSan) || ($titleLast && $matrixLabel === $titleLast)) {
                $labelMatchedSlugs[] = $mSlug;
            }
        }

        $candidates = array_values(array_unique(array_filter([
            $slugPrimary,
            $slugAlt,
            $partnerSlug,
            $slugPrimaryLast,
            $slugAltLast,
            ...$labelMatchedSlugs,
            'default',
            'generic',
        ])));

        foreach ($candidates as $candidate) {
            if (empty($matrix[$candidate]['standard']) || !is_array($matrix[$candidate]['standard'])) {
                continue;
            }
            $cost = $this->find_cost_in_rows($matrix[$candidate]['standard'], $weightKg);
            if ($cost !== null) {
                $labelOverride = isset($matrix[$candidate]['label']) ? (string)$matrix[$candidate]['label'] : '';
                return [
                    'cost'  => $cost,
                    'label' => $labelOverride,
                ];
            }
        }

        return null;
    }

    private function find_cost_in_rows($rows, $weightKg)
    {
        $fallback = null;
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }
            $price = $this->to_float($row['price'] ?? ($row['gross'] ?? 0), 0.0);
            if ($price <= 0) {
                continue;
            }
            if ($fallback === null) {
                $fallback = $price;
            }
            $min = $this->to_float($row['min'] ?? 0, 0.0);
            $max = isset($row['max']) && $row['max'] !== '' ? $this->to_float($row['max'], 0.0) : null;
            if ($weightKg < $min) {
                continue;
            }
            if ($max !== null && $weightKg > $max) {
                continue;
            }
            return $price;
        }
        return $fallback;
    }

    private function generate_courier_slug($label, $partnerId)
    {
        $slug = $label ? sanitize_title($label) : '';
        if (!$slug && $partnerId) {
            $slug = 'partner-' . absint($partnerId);
        }
        if (!$slug) {
            $slug = 'generic';
        }
        return $slug;
    }

    private function should_hide_rate($pricingMode, $requires, $passedMin, $hasCoupon)
    {
        return false;
    }

    private function extract_last_slug($text)
    {
        if (!$text) return '';
        $parts = preg_split('/\s+/', (string)$text);
        $last = is_array($parts) ? array_pop($parts) : '';
        return sanitize_title($last);
    }

    /**
     * Keep shipping non-taxable by default, but if store prices include tax, fold shipping tax into the cost.
     */
    private function adjust_cost_for_tax($amount)
    {
        $amountFloat = $this->to_float($amount, 0.0);
        if ($amountFloat <= 0) {
            return wc_format_decimal(0);
        }
        if (!function_exists('wc_prices_include_tax') || !wc_prices_include_tax()) {
            return wc_format_decimal($amountFloat);
        }

        $taxRates = WC_Tax::get_shipping_tax_rates();
        if (empty($taxRates)) {
            return wc_format_decimal($amountFloat);
        }

        $taxes = WC_Tax::calc_shipping_tax($amountFloat, $taxRates);
        $taxTotal = is_array($taxes) ? array_sum($taxes) : 0;
        return wc_format_decimal($amountFloat + max(0, (float)$taxTotal));
    }

    private function to_float($value, $default = 0.0)
    {
        if ($value === '' || $value === null) {
            return $default;
        }
        if (is_numeric($value)) {
            return floatval($value);
        }
        $raw = str_replace(["\xC2\xA0", ' '], '', (string)$value);

        $hasComma = strpos($raw, ',') !== false;
        $hasDot   = strpos($raw, '.') !== false;

        if ($hasComma && $hasDot) {
            if (strrpos($raw, ',') > strrpos($raw, '.')) {
                $raw = str_replace('.', '', $raw);
                $raw = str_replace(',', '.', $raw);
            } else {
                $raw = str_replace(',', '', $raw);
            }
        } elseif ($hasComma) {
            if (preg_match('/^-?\d{1,3}(?:\.\d{3})*,\d{3}$/', $raw)) {
                $raw = str_replace([',', '.'], '', $raw);
            } elseif (preg_match('/^-?\d+,\d{1,2}$/', $raw)) {
                $raw = str_replace('.', '', $raw);
                $raw = str_replace(',', '.', $raw);
            } else {
                $raw = str_replace(',', '', $raw);
            }
        }

        $normalized = preg_replace('/[^0-9\.-]/', '', $raw);
        if ($normalized === '' || $normalized === '-' || $normalized === '.') {
            return $default;
        }
        return floatval($normalized);
    }
}

WC_Shipping_5E::register_filters();
