<?php

/**
 * Plugin Name: Woo 5E Shipping 2
 * Plugin URI:  https://conconrdsoft.solutions
 * Description: Shipping integration for WooCommerce with 5E API.
 * Version:     0.4.6
 * Author:      Concordsoft Solutions
 * Author URI:  https://concordsoft.solutions
 * Text Domain: woo-5e
 * Domain Path: /languages
 * Requires PHP: 7.4
 * Requires at least: 6.0
 * License:     GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 */

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

define('W5E_VER', '0.3.0');
define('W5E_BASENAME', plugin_basename(__FILE__));
define('W5E_PATH', plugin_dir_path(__FILE__));
define('W5E_URL',  plugin_dir_url(__FILE__));

if (!function_exists('w5e_is_debug_enabled')) {
    function w5e_is_debug_enabled()
    {
        return get_option('w5e_debug_mode', 'no') === 'yes';
    }
}

if (!function_exists('w5e_log_debug')) {
    function w5e_log_debug($message, array $context = [])
    {
        if (!w5e_is_debug_enabled()) {
            return;
        }
        if (!function_exists('wc_get_logger')) {
            return;
        }
        $logger = wc_get_logger();
        $logger->debug($message, array_merge(['source' => 'woo-5e'], $context));
    }
}

if (!function_exists('w5e_format_tracking_number')) {
    function w5e_format_tracking_number($tracking, $prefix = '')
    {
        $tracking = trim((string)$tracking);
        $prefix = trim((string)$prefix);
        if ($tracking === '') {
            return '';
        }
        if ($prefix === '') {
            return $tracking;
        }
        $glue = preg_match('/[\\s\\-\\/_]$/', $prefix) ? '' : ' ';
        return $prefix . $glue . $tracking;
    }
}

if (!defined('W5E_WEBHOOK_SECRET')) {
    define('W5E_WEBHOOK_SECRET', 'wordpress_5e_connector');
}

require_once W5E_PATH . 'includes/class-w5e-settings.php';
require_once W5E_PATH . 'includes/class-w5e-api.php';
require_once W5E_PATH . 'includes/class-w5e-i18n.php';
require_once W5E_PATH . 'includes/class-w5e-orders.php';
require_once W5E_PATH . 'includes/class-w5e-address-directory.php';

W5E_I18n::setup();

// Enforce address line 2 as required while the plugin is active.
add_filter('pre_option_woocommerce_checkout_address_2_field', function () {
    return 'required';
});

add_filter('woocommerce_default_address_fields', function ($fields) {
    if (isset($fields['state'])) {
        $fields['state']['type'] = 'text';
        $fields['state']['required'] = true;
        $fields['state']['priority'] = 65;
    }
    if (isset($fields['postcode'])) {
        $fields['postcode']['priority'] = 67;
    }
    if (isset($fields['address_2'])) {
        $fields['address_2']['required'] = true;
        if (!empty($fields['address_2']['placeholder']) && stripos($fields['address_2']['placeholder'], 'optional') !== false) {
            $fields['address_2']['placeholder'] = __('Apartment, suite, unit, etc.', 'woocommerce');
        }
    }
    return $fields;
});

// Treat Serbian "state" as free-text so we can store BEX/5E place values in District field.
add_filter('woocommerce_states', function ($states) {
    if (isset($states['RS']) && is_array($states['RS'])) {
        $states['RS'] = [];
    }
    return $states;
});

add_filter('woocommerce_package_rates', function ($rates, $package) {
    // Add "Free shipping" note to zero-cost 5E rates.
    foreach ($rates as $key => $rate) {
        if (!is_object($rate) || !method_exists($rate, 'get_method_id')) {
            continue;
        }
        if ($rate->get_method_id() !== 'w5e') {
            continue;
        }
        $source = method_exists($rate, 'get_meta') ? $rate->get_meta('w5e_cost_source', true) : '';
        $cost = method_exists($rate, 'get_cost') ? (float)$rate->get_cost() : 0.0;
        if ($cost > 0) {
            continue;
        }
        if (in_array($source, ['recipient_tariff', 'sender_pays'], true)) {
            continue;
        }
        $label = method_exists($rate, 'get_label') ? (string)$rate->get_label() : '';
        $payerNote = __('Will be charged on delivery per courier tariff.', 'woo-5e');
        $senderNote = __('Sender pays shipping.', 'woo-5e');
        if (($payerNote && stripos($label, $payerNote) !== false) || ($senderNote && stripos($label, $senderNote) !== false)) {
            continue;
        }
        $freeText = __('Free shipping', 'woo-5e');
        // Avoid double-appending if label already contains the free text.
        if ($label && stripos($label, $freeText) === false) {
            $newLabel = sprintf('%s — %s', $label, $freeText);
            if (method_exists($rate, 'set_label')) {
                $rate->set_label($newLabel);
            } else {
                $rates[$key]->label = $newLabel;
            }
        }
    }
    return $rates;
}, 999, 2);


add_action('woocommerce_shipping_init', function () {
    require_once W5E_PATH . 'includes/class-w5e-shipping.php';
});

add_filter('woocommerce_shipping_methods', function ($methods) {
    if (class_exists('WC_Shipping_5E')) {
        $enabled = get_option('w5e_enabled_partners', []);
        if (is_array($enabled) && !empty($enabled)) {
            $methods['w5e'] = 'WC_Shipping_5E';
        }
    }
    return $methods;
});

add_action('plugins_loaded', function () {
    W5E_Settings::init();
    W5E_Orders::init();
    W5E_Address_Directory::init();
});

add_filter('plugin_action_links_' . W5E_BASENAME, function ($links) {
    $url = admin_url('admin.php?page=wc-settings&tab=shipping&section=w5e');
    $settingsLink = '<a href="' . esc_url($url) . '">' . esc_html__('Settings', 'woo-5e') . '</a>';
    array_unshift($links, $settingsLink);
    return $links;
});

add_action('admin_init', function () {
    if (!class_exists('WooCommerce')) {
        add_action('admin_notices', function () {
            echo '<div class="notice notice-error"><p><strong>' . esc_html__('Woo 5E Shipping', 'woo-5e') . '</strong> ' . esc_html__('requires an active WooCommerce plugin.', 'woo-5e') . '</p></div>';
        });
    }
});

add_filter('woocommerce_shipping_maybe_use_cached_rates', '__return_false');

/**
 * Custom order statuses for 5E orders.
 */
add_action('init', function () {
    register_post_status('wc-w5e_waiting_payme', [
        'label'                     => _x('Awaiting payment', 'Order status', 'woo-5e'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('Awaiting payment <span class="count">(%s)</span>', 'Awaiting payment <span class="count">(%s)</span>', 'woo-5e'),
    ]);

    register_post_status('wc-w5e_processing', [
        'label'                     => _x('Awaiting warehouse selection', 'Order status', 'woo-5e'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('Awaiting warehouse selection <span class="count">(%s)</span>', 'Awaiting warehouse selection <span class="count">(%s)</span>', 'woo-5e'),
    ]);

    register_post_status('wc-w5e_in_transit', [
        'label'                     => _x('5E u isporuci', 'Order status', 'woo-5e'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('5E u isporuci <span class="count">(%s)</span>', '5E u isporuci <span class="count">(%s)</span>', 'woo-5e'),
    ]);

    register_post_status('wc-w5e_returned', [
        'label'                     => _x('5E vraćena', 'Order status', 'woo-5e'),
        'public'                    => true,
        'exclude_from_search'       => false,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'label_count'               => _n_noop('5E vraćena <span class="count">(%s)</span>', '5E vraćena <span class="count">(%s)</span>', 'woo-5e'),
    ]);
});

add_filter('wc_order_statuses', function ($statuses) {
    $new = [];
    foreach ($statuses as $key => $label) {
        $new[$key] = $label;
        if ($key === 'wc-pending') {
            $new['wc-w5e_waiting_payme'] = _x('Awaiting payment', 'Order status', 'woo-5e');
        }
        if ($key === 'wc-processing') {
            $new['wc-w5e_processing'] = _x('Awaiting warehouse selection', 'Order status', 'woo-5e');
            $new['wc-w5e_in_transit'] = _x('5E u isporuci', 'Order status', 'woo-5e');
        }
    }
    if (!isset($new['wc-w5e_waiting_payme'])) {
        $new['wc-w5e_waiting_payme'] = _x('Awaiting payment', 'Order status', 'woo-5e');
    }
    if (!isset($new['wc-w5e_processing'])) {
        $new['wc-w5e_processing'] = _x('Awaiting warehouse selection', 'Order status', 'woo-5e');
    }
    if (!isset($new['wc-w5e_in_transit'])) {
        $new['wc-w5e_in_transit'] = _x('5E u isporuci', 'Order status', 'woo-5e');
    }
    $new['wc-w5e_returned'] = _x('5E vraćena', 'Order status', 'woo-5e');
    return $new;
});

add_filter('woocommerce_shop_order_list_table_default_statuses', function ($statuses) {
    if (!is_array($statuses)) {
        $statuses = [];
    }
    if (!in_array('wc-pending', $statuses, true)) {
        $statuses[] = 'wc-pending';
    }
    if (!in_array('wc-w5e_waiting_payme', $statuses, true)) {
        $statuses[] = 'wc-w5e_waiting_payme';
    }
    if (!in_array('wc-w5e_in_transit', $statuses, true)) {
        $statuses[] = 'wc-w5e_in_transit';
    }
    if (!in_array('wc-w5e_returned', $statuses, true)) {
        $statuses[] = 'wc-w5e_returned';
    }
    return $statuses;
});

add_filter('woocommerce_order_list_table_default_statuses', function ($statuses) {
    if (!is_array($statuses)) {
        $statuses = [];
    }
    if (!in_array('wc-pending', $statuses, true)) {
        $statuses[] = 'wc-pending';
    }
    if (!in_array('wc-w5e_waiting_payme', $statuses, true)) {
        $statuses[] = 'wc-w5e_waiting_payme';
    }
    if (!in_array('wc-w5e_in_transit', $statuses, true)) {
        $statuses[] = 'wc-w5e_in_transit';
    }
    if (!in_array('wc-w5e_returned', $statuses, true)) {
        $statuses[] = 'wc-w5e_returned';
    }
    return $statuses;
});

add_filter('woocommerce_shop_order_list_table_prepare_items_query_args', function ($args) {
    if (!is_array($args)) {
        return $args;
    }

    $requestedStatus = isset($_GET['status']) ? sanitize_text_field((string)$_GET['status']) : '';
    if ($requestedStatus !== '' && $requestedStatus !== 'all') {
        return $args;
    }

    $statuses = isset($args['status']) && is_array($args['status']) ? $args['status'] : [];
    if (!in_array('wc-pending', $statuses, true)) {
        $statuses[] = 'wc-pending';
    }
    if (!in_array('wc-w5e_waiting_payme', $statuses, true)) {
        $statuses[] = 'wc-w5e_waiting_payme';
    }
    if (!in_array('wc-w5e_in_transit', $statuses, true)) {
        $statuses[] = 'wc-w5e_in_transit';
    }
    if (!in_array('wc-w5e_returned', $statuses, true)) {
        $statuses[] = 'wc-w5e_returned';
    }
    $args['status'] = $statuses;

    return $args;
}, 999);

add_filter('woocommerce_order_list_table_prepare_items_query_args', function ($args) {
    if (!is_array($args)) {
        return $args;
    }

    $requestedStatus = isset($_GET['status']) ? sanitize_text_field((string)$_GET['status']) : '';
    if ($requestedStatus !== '' && $requestedStatus !== 'all') {
        if ($requestedStatus === 'wc-w5e_returned' || $requestedStatus === 'w5e_returned') {
            $args['status'] = ['wc-w5e_returned', 'w5e_returned'];
        }
        return $args;
    }

    $statuses = isset($args['status']) && is_array($args['status']) ? $args['status'] : [];
    if (!in_array('wc-pending', $statuses, true)) {
        $statuses[] = 'wc-pending';
    }
    if (!in_array('wc-w5e_waiting_payme', $statuses, true)) {
        $statuses[] = 'wc-w5e_waiting_payme';
    }
    if (!in_array('wc-w5e_in_transit', $statuses, true)) {
        $statuses[] = 'wc-w5e_in_transit';
    }
    if (!in_array('wc-w5e_returned', $statuses, true)) {
        $statuses[] = 'wc-w5e_returned';
    }
    $args['status'] = $statuses;

    return $args;
}, 999);

add_filter('woocommerce_shop_order_list_table_order_count', function ($count, $status) {
    if ($count > 0 || !is_array($status)) {
        return $count;
    }
    if (!in_array('wc-w5e_returned', $status, true) && !in_array('w5e_returned', $status, true)) {
        return $count;
    }
    if (class_exists('\\Automattic\\WooCommerce\\Utilities\\OrderUtil')) {
        $orderUtil = '\\Automattic\\WooCommerce\\Utilities\\OrderUtil';
        if ($orderUtil::custom_orders_table_usage_is_enabled()) {
            global $wpdb;
            $table = $orderUtil::get_table_for_orders();
            if ($table) {
                // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
                $sql = "SELECT COUNT(*) FROM {$table} WHERE type = %s AND status IN (%s, %s)";
                $found = (int) $wpdb->get_var($wpdb->prepare($sql, 'shop_order', 'wc-w5e_returned', 'w5e_returned'));
                if ($found > 0) {
                    return $found;
                }
            }
        }
    }
    $orders = wc_get_orders([
        'status'   => ['wc-w5e_returned', 'w5e_returned'],
        'limit'    => 1,
        'paginate' => true,
        'type'     => 'shop_order',
    ]);
    if (is_object($orders) && isset($orders->total)) {
        return (int) $orders->total;
    }
    return $count;
}, 10, 2);

add_filter('woocommerce_order_list_table_order_count', function ($count, $status) {
    if ($count > 0 || !is_array($status)) {
        return $count;
    }
    if (!in_array('wc-w5e_returned', $status, true) && !in_array('w5e_returned', $status, true)) {
        return $count;
    }
    if (class_exists('\\Automattic\\WooCommerce\\Utilities\\OrderUtil')) {
        $orderUtil = '\\Automattic\\WooCommerce\\Utilities\\OrderUtil';
        if ($orderUtil::custom_orders_table_usage_is_enabled()) {
            global $wpdb;
            $table = $orderUtil::get_table_for_orders();
            if ($table) {
                // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
                $sql = "SELECT COUNT(*) FROM {$table} WHERE type = %s AND status IN (%s, %s)";
                $found = (int) $wpdb->get_var($wpdb->prepare($sql, 'shop_order', 'wc-w5e_returned', 'w5e_returned'));
                if ($found > 0) {
                    return $found;
                }
            }
        }
    }
    $orders = wc_get_orders([
        'status'   => ['wc-w5e_returned', 'w5e_returned'],
        'limit'    => 1,
        'paginate' => true,
        'type'     => 'shop_order',
    ]);
    if (is_object($orders) && isset($orders->total)) {
        return (int) $orders->total;
    }
    return $count;
}, 10, 2);

add_filter('woocommerce_email_classes', function ($emails) {
    if (!class_exists('W5E_Email_In_Transit')) {
        include_once W5E_PATH . 'includes/class-w5e-email-in-transit.php';
    }
    if (class_exists('W5E_Email_In_Transit')) {
        $emails['W5E_Email_In_Transit'] = new W5E_Email_In_Transit();
    }
    return $emails;
});

add_filter('woocommerce_locate_template', function ($template, $template_name, $template_path) {
    $plugin_path = W5E_PATH . 'templates/';
    if (file_exists($plugin_path . $template_name)) {
        return $plugin_path . $template_name;
    }
    return $template;
}, 10, 3);

add_action('admin_notices', function () {
    if (!is_admin()) return;
    $screen = function_exists('get_current_screen') ? get_current_screen() : null;
    if (!$screen || $screen->id !== 'shop_order') {
        return;
    }
    echo '<div class="notice notice-info"><p>' .
        esc_html__('Ako se porudžbina plaća predračunom/fakturom, po uspešnoj uplati promenite status u "U obradi" i pošaljite porudžbinu u 5E akcijom “Pošalji u 5E”.', 'woo-5e') .
        '</p></div>';
});

add_action('admin_init', function () {
    if (!is_admin()) {
        return;
    }
    if (!current_user_can('manage_woocommerce')) {
        return;
    }
    $page = isset($_GET['page']) ? sanitize_text_field((string) $_GET['page']) : '';
    $status = isset($_GET['status']) ? sanitize_text_field((string) $_GET['status']) : '';
    if ($page !== 'wc-orders' || $status !== 'wc-w5e_returned') {
        return;
    }
    if (get_transient('w5e_returned_backfill_lock')) {
        return;
    }
    set_transient('w5e_returned_backfill_lock', 1, 5 * MINUTE_IN_SECONDS);

    $orders = wc_get_orders([
        'status'     => 'any',
        'limit'      => -1,
        'orderby'    => 'date',
        'order'      => 'DESC',
        'meta_query' => [
            'relation' => 'OR',
            [
                'key'     => '_w5e_last_status',
                'value'   => 'returned_to_sender',
                'compare' => '=',
            ],
            [
                'key'     => '_w5e_last_webhook',
                'value'   => 'returned_to_sender',
                'compare' => 'LIKE',
            ],
        ],
    ]);

    if (!empty($orders)) {
        foreach ($orders as $order) {
            if (!$order || !is_a($order, 'WC_Order')) {
                continue;
            }
            if ($order->has_status('w5e_returned')) {
                continue;
            }
            $storedStatus = (string) $order->get_meta('_w5e_last_status', true);
            $normalized = $storedStatus !== '' ? sanitize_key(preg_replace('/[\\s\\-]+/', '_', $storedStatus)) : '';
            if ($normalized !== 'returned_to_sender') {
                $payload = $order->get_meta('_w5e_last_webhook', true);
                $statusRaw = '';
                if (is_array($payload)) {
                    $statusRaw = isset($payload['status']) ? (string) $payload['status'] : '';
                } elseif (is_string($payload) && $payload !== '') {
                    $decoded = json_decode($payload, true);
                    if (is_array($decoded)) {
                        $statusRaw = isset($decoded['status']) ? (string) $decoded['status'] : '';
                    }
                }
                $normalized = $statusRaw !== '' ? sanitize_key(preg_replace('/[\\s\\-]+/', '_', $statusRaw)) : '';
            }
            if ($normalized === 'returned_to_sender') {
                $order->set_status('w5e_returned', '5E status sync');
                $order->save();
            }
        }
    }
});

add_action('woocommerce_order_status_w5e_in_transit', function ($order_id) {
    $order = wc_get_order($order_id);
    if (!$order || !is_a($order, 'WC_Order')) {
        return;
    }

    $trackingRaw = $order->get_meta('_w5e_tracking_number');
    $trackingPrefix = $order->get_meta('_w5e_tracking_prefix');
    $tracking = w5e_format_tracking_number($trackingRaw, $trackingPrefix);
    $message  = $tracking
        ? sprintf(__('Vaša pošiljka je predata kuriru. Broj za praćenje: %s', 'woo-5e'), $tracking)
        : __('Vaša pošiljka je predata kuriru.', 'woo-5e');

    $order->add_order_note($message, true);

    $mailer = WC()->mailer();
    $emails = $mailer->get_emails();
    if (!empty($emails['W5E_Email_In_Transit'])) {
        $emails['W5E_Email_In_Transit']->trigger($order_id, $tracking);
    }
}, 10, 1);

add_action('woocommerce_admin_order_data_after_order_details', function ($order) {
    if (!is_admin()) {
        return;
    }
    echo '<p class="form-field w5e-status-note description" style="margin-top:8px;">' .
        esc_html__('Ako je porudzbina u statusu "cekanje" ili "ceka se uplata" molimo vas rucno promenite u statusu "u obradi" kada je izvrseno placanje.', 'woo-5e') .
        '</p>';
});

/**
 * 5E webhook endpoint: POST /wp-json/5e/v1/status-update
 * Expected JSON:
 * {
 *   "order_id": "123",
 *   "tracking_number": "5E-789",
 *   "status": "delivered",
 *   "timestamp": "2024-01-10T12:34:56Z",
 *   "signature": "HMAC_HEX"
 * }
 */
add_action('rest_api_init', function () {
    register_rest_route('5e/v1', '/status-update', [
        'methods'             => 'POST',
        'callback'            => function (\WP_REST_Request $request) {
            $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
            $logCtx = ['source' => 'woo-5e-webhook'];

            $body    = $request->get_body();
            if ($logger) {
                $logger->info('[Webhook] Hit received', $logCtx + [
                    'body_snippet' => substr($body, 0, 1000),
                    'headers'      => $request->get_headers(),
                ]);
            }
            w5e_log_debug('[Webhook] Hit received', [
                'source'       => 'woo-5e-webhook',
                'body_snippet' => substr($body, 0, 1000),
                'headers'      => $request->get_headers(),
            ]);
            $payload = json_decode($body, true);
            if (!is_array($payload)) {
                if ($logger) {
                    $logger->error('[Webhook] Invalid JSON body.', $logCtx);
                }
                return new \WP_REST_Response(['error' => 'Invalid JSON'], 400);
            }

            $secret = defined('W5E_WEBHOOK_SECRET') ? W5E_WEBHOOK_SECRET : '';
            if ($secret !== '') {
                $sigHeader = $request->get_header('x-5e-signature');
                $calc      = hash_hmac('sha256', $body, $secret);
                if (!$sigHeader || !hash_equals($calc, $sigHeader)) {
                    if ($logger) {
                        $logger->error('[Webhook] Invalid signature.', $logCtx);
                    }
                    return new \WP_REST_Response(['error' => 'Invalid signature'], 403);
                }
            }

            $orderId         = isset($payload['order_id']) ? absint($payload['order_id']) : 0;
            $trackingNumber  = isset($payload['tracking_number']) ? sanitize_text_field($payload['tracking_number']) : '';
            $statusIncoming  = isset($payload['status']) ? (string)$payload['status'] : '';
            $statusNormalized = $statusIncoming !== '' ? preg_replace('/[\\s\\-]+/', '_', $statusIncoming) : '';
            $statusKey       = $statusNormalized ? sanitize_key($statusNormalized) : '';
            $trackingPrefix  = '';
            if (isset($payload['CityShipmentTrackingPrefix'])) {
                $trackingPrefix = sanitize_text_field((string)$payload['CityShipmentTrackingPrefix']);
            } elseif (isset($payload['cityShipmentTrackingPrefix'])) {
                $trackingPrefix = sanitize_text_field((string)$payload['cityShipmentTrackingPrefix']);
            } elseif (isset($payload['city_shipment_tracking_prefix'])) {
                $trackingPrefix = sanitize_text_field((string)$payload['city_shipment_tracking_prefix']);
            }
            w5e_log_debug('[Webhook] Status parsed', [
                'source'     => 'woo-5e-webhook',
                'order_id'   => $orderId,
                'status_raw' => $statusIncoming,
                'status_key' => $statusKey,
                'status_norm' => $statusNormalized,
            ]);

            if (!$orderId && !$trackingNumber) {
                if ($logger) {
                    $logger->error('[Webhook] Missing order_id and tracking_number.', $logCtx);
                }
                return new \WP_REST_Response(['error' => 'order_id or tracking_number required'], 400);
            }

            $order = null;
            if ($orderId) {
                $order = wc_get_order($orderId);
            }
            if (!$order && $trackingNumber) {
                $orders = wc_get_orders([
                    'limit'      => 1,
                    'meta_key'   => '_w5e_tracking_number',
                    'meta_value' => $trackingNumber,
                ]);
                if (!empty($orders)) {
                    $order = $orders[0];
                }
            }

            if (!$order || !is_a($order, 'WC_Order')) {
                if ($logger) {
                    $logger->error('[Webhook] Order not found for id/tracking.', $logCtx);
                }
                return new \WP_REST_Response(['error' => 'Order not found'], 404);
            }

            if ($trackingNumber) {
                $order->update_meta_data('_w5e_tracking_number', $trackingNumber);
            }
            if ($trackingPrefix !== '') {
                $order->update_meta_data('_w5e_tracking_prefix', $trackingPrefix);
            }
            $order->update_meta_data('_w5e_last_webhook', $payload);
            if ($statusKey !== '') {
                $order->update_meta_data('_w5e_last_status', $statusKey);
            }
            if (method_exists($order, 'save_meta_data')) {
                $order->save_meta_data();
            }
            w5e_log_debug('[Webhook] Payload received', [
                'source'  => 'woo-5e-webhook',
                'order_id' => $order->get_id(),
                'payload' => $payload,
            ]);
            if ($trackingNumber) {
                w5e_log_debug('[Webhook] Tracking number received', [
                    'source'   => 'woo-5e-webhook',
                    'order_id' => $order->get_id(),
                    'tracking' => $trackingNumber,
                    'prefix'   => $trackingPrefix,
                ]);
            }

            $aliases = apply_filters('w5e_webhook_status_aliases', [
                'pending'               => 'pending',
                'awaiting_confirmation' => 'awaiting_confirmation',
                'in_progress'           => 'in_progress',
                'in-progress'           => 'in_progress',
                'processing'            => 'processing',
                'with_courier'          => 'with_courier',
                'processed'             => 'processed',
                'returned_to_sender'    => 'returned_to_sender',
                'canceled'              => 'cancelled',
                'cancelled'             => 'cancelled',
                'deleted'               => 'deleted',
            ], $payload, $order);

            $canonicalStatus = isset($aliases[$statusKey]) ? $aliases[$statusKey] : '';
            w5e_log_debug('[Webhook] Status canonicalized', [
                'source'     => 'woo-5e-webhook',
                'order_id'   => $order->get_id(),
                'status_key' => $statusKey,
                'canonical'  => $canonicalStatus,
            ]);
            if (!$canonicalStatus) {
                return new \WP_REST_Response(['error' => 'Unknown status', 'status_received' => $statusIncoming], 400);
            }

            if (w5e_is_debug_enabled() && in_array($statusKey, ['in-progress', 'in_progress'], true)) {
                $alreadyNotified = $order->get_meta('_w5e_debug_in_progress_notified', true);
                w5e_log_debug('[Webhook] Debug in_progress email check', [
                    'source' => 'woo-5e-webhook',
                    'order_id' => $order->get_id(),
                    'status_raw' => $statusIncoming,
                    'canonical' => $canonicalStatus,
                    'tracking' => $trackingNumber,
                    'already_notified' => $alreadyNotified ? 'yes' : 'no',
                ]);
                if (!$alreadyNotified) {
                    $trackingForEmailRaw = $trackingNumber ?: $order->get_meta('_w5e_tracking_number');
                    $prefixForEmail = $trackingPrefix ?: $order->get_meta('_w5e_tracking_prefix');
                    $trackingForEmail = w5e_format_tracking_number($trackingForEmailRaw, $prefixForEmail);
                    $mailer = WC()->mailer();
                    $emails = $mailer->get_emails();
                    if (empty($emails['W5E_Email_In_Transit'])) {
                        w5e_log_debug('[Webhook] Debug in_progress email missing', [
                            'source' => 'woo-5e-webhook',
                            'order_id' => $order->get_id(),
                        ]);
                    } else {
                        $emailObj = $emails['W5E_Email_In_Transit'];
                        $recipient = $order->get_billing_email();
                        if (!$emailObj->is_enabled()) {
                            w5e_log_debug('[Webhook] Debug in_progress email disabled', [
                                'source' => 'woo-5e-webhook',
                                'order_id' => $order->get_id(),
                            ]);
                        } elseif (!$recipient) {
                            w5e_log_debug('[Webhook] Debug in_progress missing recipient', [
                                'source' => 'woo-5e-webhook',
                                'order_id' => $order->get_id(),
                            ]);
                        } else {
                            $emailObj->trigger($order->get_id(), $trackingForEmail);
                            w5e_log_debug('[Webhook] Debug in_progress email triggered', [
                                'source' => 'woo-5e-webhook',
                                'order_id' => $order->get_id(),
                                'tracking' => $trackingForEmail,
                                'recipient' => $recipient,
                            ]);
                            $order->update_meta_data('_w5e_debug_in_progress_notified', $trackingForEmail ?: '1');
                            if (method_exists($order, 'save_meta_data')) {
                                $order->save_meta_data();
                            }
                        }
                    }
                }
            }

            $map = [
                'pending'               => 'processing',
                'awaiting_confirmation' => 'processing',
                'in_progress'           => 'processing',
                'with_courier'          => 'wc-w5e_in_transit',
                'processed'             => 'completed',
                'returned_to_sender'    => 'wc-w5e_returned',
                'cancelled'             => 'cancelled',
                'deleted'               => '',
            ];
            $map = apply_filters('w5e_webhook_status_map', $map, $payload, $order);

            $targetStatus = isset($map[$canonicalStatus]) ? $map[$canonicalStatus] : '';
            if ($targetStatus && $order->get_status() !== $targetStatus) {
                if ($logger) {
                    $logger->info('[Webhook] Updating order status', $logCtx + [
                        'order_id'      => $order->get_id(),
                        'from'          => $order->get_status(),
                        'to'            => $targetStatus,
                        'canonical'     => $canonicalStatus,
                        'status_raw'    => $statusIncoming,
                        'tracking'      => $trackingNumber,
                    ]);
                }
                w5e_log_debug('[Webhook] Updating order status', [
                    'source'        => 'woo-5e-webhook',
                    'order_id'      => $order->get_id(),
                    'from'          => $order->get_status(),
                    'to'            => $targetStatus,
                    'canonical'     => $canonicalStatus,
                    'status_raw'    => $statusIncoming,
                    'tracking'      => $trackingNumber,
                ]);
                $order->set_status($targetStatus, '5E webhook');
            } else {
                if ($logger) {
                    $logger->info('[Webhook] No status change applied', $logCtx + [
                        'order_id'   => $order->get_id(),
                        'current'    => $order->get_status(),
                        'canonical'  => $canonicalStatus,
                        'status_raw' => $statusIncoming,
                        'tracking'   => $trackingNumber,
                    ]);
                }
                w5e_log_debug('[Webhook] No status change applied', [
                    'source'     => 'woo-5e-webhook',
                    'order_id'   => $order->get_id(),
                    'current'    => $order->get_status(),
                    'canonical'  => $canonicalStatus,
                    'status_raw' => $statusIncoming,
                    'tracking'   => $trackingNumber,
                ]);
            }

            $order->save();

            return new \WP_REST_Response([
                'success'  => true,
                'order_id' => $order->get_id(),
                'status'   => $order->get_status(),
            ], 200);
        },
        'permission_callback' => '__return_true',
    ]);
});

/**
 * Add a bold subtotal row directly above shipping rows in cart when free 5E shipping applies.
 */
function w5e_render_inline_subtotal_before_shipping()
{
    if (!function_exists('WC')) {
        return;
    }
    $cart = WC()->cart;
    if (!$cart) {
        return;
    }

    if (!w5e_cart_has_free_5e_rate()) {
        return;
    }

    $subtotal_html = $cart->get_cart_subtotal();
    if (!$subtotal_html) {
        return;
    }
    $label = esc_html__('Subtotal', 'woo-5e');
?>
    <tr class="w5e-inline-subtotal">
        <th><strong><?php echo $label; ?></strong></th>
        <td data-title="<?php echo $label; ?>"><strong><?php echo $subtotal_html; ?></strong></td>
    </tr>
<?php
}
add_action('woocommerce_cart_totals_before_shipping', 'w5e_render_inline_subtotal_before_shipping');

/**
 * Detect if the chosen (or available) shipping rate is a free 5E rate.
 */
function w5e_cart_has_free_5e_rate()
{
    if (!function_exists('WC')) {
        return false;
    }
    $shipping = WC()->shipping();
    if (!$shipping) {
        return false;
    }

    $packages = $shipping->get_packages();
    $needs_calc = true;
    foreach ($packages as $package) {
        if (!empty($package['rates'])) {
            $needs_calc = false;
            break;
        }
    }
    if ($needs_calc) {
        $shipping->calculate_shipping($packages);
        $packages = $shipping->get_packages();
    }

    $chosen_methods    = WC()->session && isset(WC()->session->chosen_shipping_methods) ? WC()->session->chosen_shipping_methods : [];

    foreach ($packages as $index => $package) {
        if (empty($package['rates'])) {
            continue;
        }

        $chosen = isset($chosen_methods[$index]) ? $chosen_methods[$index] : '';
        if ($chosen && isset($package['rates'][$chosen])) {
            $rate = $package['rates'][$chosen];
            if ($rate && method_exists($rate, 'get_method_id') && $rate->get_method_id() === 'w5e') {
                $source = method_exists($rate, 'get_meta') ? $rate->get_meta('w5e_cost_source', true) : '';
                $cost   = method_exists($rate, 'get_cost') ? (float)$rate->get_cost() : 0.0;
                if ($source === 'free' || ($cost <= 0 && $source !== 'recipient_tariff')) {
                    return true;
                }
            }
        }

        foreach ($package['rates'] as $rate) {
            if (!method_exists($rate, 'get_method_id') || $rate->get_method_id() !== 'w5e') {
                continue;
            }
            $source = method_exists($rate, 'get_meta') ? $rate->get_meta('w5e_cost_source', true) : '';
            $cost   = method_exists($rate, 'get_cost') ? (float)$rate->get_cost() : 0.0;
            if ($source === 'free' || ($cost <= 0 && $source !== 'recipient_tariff')) {
                return true;
            }
        }
    }

    return false;
}

/**
 * Inject a subtotal row above shipping in the cart block when 5E free shipping applies.
 */
function w5e_enqueue_cart_block_subtotal_injector()
{
    if (!function_exists('WC') || !is_cart() || is_checkout()) {
        return;
    }
    $cart = WC()->cart;
    if (!$cart) {
        return;
    }

    $subtotal_html = wp_kses_post($cart->get_cart_subtotal());
    if (!$subtotal_html) {
        return;
    }
    $label = esc_html__('Subtotal', 'woo-5e');
    $script = "
    (function() {
        var subtotalHtml = '" . str_replace("'", "\\'", $subtotal_html) . "';
        var label = '" . str_replace("'", "\\'", $label) . "';
        function hasFree5E() {
            var shipping = document.querySelector('.wc-block-components-totals-shipping');
            if (!shipping) return false;
            var text = shipping.textContent ? shipping.textContent.toLowerCase() : '';
            if (text.indexOf('5e') === -1) return false;
            return text.indexOf('free') !== -1 || text.indexOf('0') !== -1;
        }
        function insertRow() {
            if (!hasFree5E()) return;
            var totals = document.querySelector('.wc-block-components-totals');
            if (!totals) return;
            if (totals.querySelector('.w5e-block-inline-subtotal')) return;
            var shipping = totals.querySelector('.wc-block-components-totals-shipping');
            if (!shipping || !shipping.parentElement) return;
            var row = document.createElement('div');
            row.className = 'wc-block-components-totals-item w5e-block-inline-subtotal';
            row.innerHTML = '<span class=\"wc-block-components-totals-item__label\"><strong>' + label + '</strong></span>' +
                            '<span class=\"wc-block-components-totals-item__value\"><strong>' + subtotalHtml + '</strong></span>';
            shipping.parentElement.insertBefore(row, shipping);
        }
        var observer = new MutationObserver(function() { insertRow(); });
        observer.observe(document.body, { childList: true, subtree: true });
        insertRow();
    })();";

    wp_register_script('w5e-cart-inline', '', [], W5E_VER, true);
    wp_enqueue_script('w5e-cart-inline');
    wp_add_inline_script('w5e-cart-inline', $script);
}
add_action('wp_footer', 'w5e_enqueue_cart_block_subtotal_injector');

register_activation_hook(__FILE__, function () {
    add_option('w5e_id', '');
    add_option('w5e_api_key', '');
    add_option('w5e_env', 'staging');
    add_option('w5e_flat_price', '0');
    add_option('w5e_enabled_partners', []);
    add_option('w5e_couriers_cache', []);
    add_option('w5e_warehouses_cache', []);
    add_option('w5e_pricing_matrix', W5E_Settings::get_default_pricing_matrix());
    add_option('w5e_order_forwarding_enabled', 'no');
    add_option('w5e_order_export_statuses', ['processing', 'completed']);
    add_option('w5e_import_mode', 'auto');
    add_option('w5e_default_warehouse_id', '');
    add_option('w5e_client_warehouse_id', '');
    add_option('w5e_client_user_id', '');
    add_option('w5e_created_user_id', 1);
    add_option('w5e_buyout_account', '');
    add_option('w5e_buyout_payer', 'recipient');
    add_option('w5e_delivery_type', 1);
    add_option('w5e_shipment_type', 1);
    add_option('w5e_del_payment_by', 1);
    add_option('w5e_recipient_pre_notification', 0);
    add_option('w5e_auto_approve', 'no');
    add_option('w5e_return_doc', 'no');
    add_option('w5e_orders_base_url_staging', '');
    add_option('w5e_orders_base_url_production', '');
    add_option('w5e_debug_mode', 'no');
});

/**
 * Highlight orders that use the 5E shipping method in the admin list (purple status badge).
 */
add_filter('manage_edit-shop_order_columns', function ($columns) {
    $columns['w5e_badge'] = __('5E', 'woo-5e');
    return $columns;
});

add_action('manage_shop_order_posts_custom_column', function ($column, $post_id) {
    if ($column !== 'w5e_badge') {
        return;
    }
    $order = wc_get_order($post_id);
    if (!$order) {
        return;
    }
    foreach ($order->get_items('shipping') as $item) {
        $methodId = $item->get_method_id();
        if ($methodId === 'w5e' || strpos($methodId, 'w5e') === 0) {
            echo '<span class="w5e-badge">5E</span>';
            return;
        }
    }
}, 10, 2);

add_action('admin_head', function () {
    if (!is_admin()) {
        return;
    }
    echo '<style>
        .column-w5e_badge { width: 60px; }
        .w5e-badge {
            display: inline-block;
            background: rgba(124,58,237,0.7) !important;
            color: #fff;
            padding: 2px 8px;
            border-radius: 12px;
            font-size: 11px;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        /* Highlight status badge only for the 5E "u obradi" status. */
        mark.order-status.status-w5e_processing,
        mark.order-status.status-w5e-processing,
        .wc-order-status.status-w5e_processing,
        .wc-order-status.status-w5e-processing,
        .order-status.status-w5e_processing,
        .order-status.status-w5e-processing {
            background: rgba(124,58,237,0.7) !important;
            color: #fff !important;
        }
    </style>';
});

// Add a row class to orders that use 5E shipping so we can style the status badge.
add_filter('post_class', function ($classes, $class, $post_id) {
    if (!is_admin() || get_post_type($post_id) !== 'shop_order') {
        return $classes;
    }
    $order = wc_get_order($post_id);
    if (!$order) {
        return $classes;
    }
    foreach ($order->get_items('shipping') as $item) {
        $methodId = $item->get_method_id();
        if ($methodId === 'w5e' || strpos($methodId, 'w5e') === 0) {
            $classes[] = 'w5e-shipping-order';
            break;
        }
    }
    return $classes;
}, 10, 3);

// HPOS / wc-orders table: mark rows that contain 5E shipping so CSS can style the status badge.
add_action('admin_print_footer_scripts', function () {
    if (!is_admin()) {
        return;
    }
?>
    <script>
        (function() {
            function markW5E() {
                var rows = document.querySelectorAll('.wc-orders-table__row');
                rows.forEach(function(row) {
                    if (row.classList.contains('w5e-shipping-order')) return;
                    if (row.querySelector('.w5e-badge')) {
                        row.classList.add('w5e-shipping-order');
                        return;
                    }
                    var shipCell = row.querySelector('.wc-orders-table__column--shipping, .order_shipping');
                    var text = shipCell ? (shipCell.textContent || '').toLowerCase() : '';
                    if (text.indexOf('5e') !== -1 || text.indexOf('bex') !== -1 || text.indexOf('d express') !== -1 || text.indexOf('aks') !== -1 || text.indexOf('gls') !== -1 || text.indexOf('post express') !== -1) {
                        row.classList.add('w5e-shipping-order');
                    }
                });
                var classicRows = document.querySelectorAll('tr.type-shop_order');
                classicRows.forEach(function(row) {
                    if (row.classList.contains('w5e-shipping-order')) return;
                    if (row.querySelector('.w5e-badge')) {
                        row.classList.add('w5e-shipping-order');
                        return;
                    }
                    var shipCell = row.querySelector('.column-order_shipping, .order_shipping, .column-order_total, .column-shipping_address .description, .column-shipping_address');
                    var txt = shipCell ? (shipCell.textContent || '').toLowerCase() : '';
                    if (txt.indexOf('5e') !== -1 || txt.indexOf('bex') !== -1 || txt.indexOf('d express') !== -1 || txt.indexOf('aks') !== -1 || txt.indexOf('gls') !== -1 || txt.indexOf('post express') !== -1) {
                        row.classList.add('w5e-shipping-order');
                    }
                });
            }
            markW5E();
            var obs = new MutationObserver(function() {
                markW5E();
            });
            obs.observe(document.body, {
                childList: true,
                subtree: true
            });
        })();
    </script>
<?php
});
