<?php

namespace BWDK\API;

use Automattic\WooCommerce\Enums\OrderStatus;
use BWDK\Enums\BWDK_OrderStatus;
use BWDK\Integrations\Digify\Client;
use BWDK\Integrations\Digify\OrderPusher;
use BWDK\Support\OrderNoteHelper;
use BWDK\Support\ReturnUrlHelper;
use BWDK\Woo\Order\OrderService;
use BWDK\Woo\Order\OrderSyncService;
use Exception;
use WC_Order;
use WP_Error;

class AjaxHandler
{
    use OrderNoteHelper;
    public function register(): void
    {
        add_action('wp_ajax_bwdk_get_cart', [$this, 'create_order']);
        add_action('wp_ajax_nopriv_bwdk_get_cart', [$this, 'create_order']);

        add_action('wp_ajax_bwdk_refund_digipay', [$this, 'refund_digipay']);
        add_action('wp_ajax_nopriv_bwdk_refund_digipay', [$this, 'refund_digipay']);

        add_action('wp_ajax_bwdk_sync_order', [$this, 'sync_order']);
    }

    public function create_order()
    {
        $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
        
        // STEP 0: Cleanup abandoned BWDK orders BEFORE stock validation
        // This prevents out-of-stock errors when user returns from Digikala without completing payment
        $this->cleanupAbandonedBwdkOrders();
        
        // STEP 1: Check for reusable existing BWDK order BEFORE stock validation
        $reusable_order = $this->findReusableOrder();
        $is_reusing_order = ($reusable_order instanceof WC_Order);
        
        if ($is_reusing_order) {
            // Reusing existing order - skip stock validation
            if ($logger) {
                $bwdk_uuid = $reusable_order->get_meta(\BWDK\Support\Constant::META_BWDK_UUID);
                $cart_hash = function_exists('WC') && WC()->cart ? WC()->cart->get_cart_hash() : '';
                $reservation_expired_at = $reusable_order->get_meta('_bwdk_reservation_expired_at');
                
                $logger->info(
                    sprintf(
                        'BWDK REUSE: Reusable order detected - order_id=%d cart_sig=%s uuid=%s reservation_expired_at=%s',
                        $reusable_order->get_id(),
                        $cart_hash ?: 'N/A',
                        $bwdk_uuid ?: 'N/A',
                        $reservation_expired_at ?: 'N/A'
                    ),
                    ['source' => 'bwdk_reuse']
                );
            }
            
            if ($logger) {
                $logger->info(
                    'BWDK STOCK GUARD: Skipped (reusing existing order)',
                    ['source' => 'bwdk_stock_guard']
                );
            }
        } else {
            // No reusable order - run stock validation for NEW order creation
            if ($logger) {
                $logger->info(
                    'BWDK STOCK GUARD: Running (new order creation)',
                    ['source' => 'bwdk_stock_guard']
                );
            }
            $this->validateCartOrFail();
        }

        $data = [
            'terms' => 0,
            'terms-field' => 0,
            'createaccount' => 0,
            'payment_method' => 'پرداخت امن دیجیکالا',
            'shipping_method' => '',
            'ship_to_different_address' => false,
            'woocommerce_checkout_update_totals' => false,
            'billing_first_name' => '',
            'billing_country' => '',
            'billing_state' => '',
            'billing_city' => '',
            'billing_address_1' => '',
            'billing_address_2' => '',
            'billing_postcode' => '',
            'billing_phone' => '',
            'billing_email' => '',
            'order_comments' => '',
        ];
        try {

            $callback_url = $_POST["callback_url"] ?? "";

            if (!empty($_POST['payload'])) {
                $incoming = is_array($_POST['payload']) ? $_POST['payload'] : json_decode(stripslashes((string)$_POST['payload']), true);
                if (is_array($incoming)) {
                    $data = array_merge($data, $incoming);
                }
            }

            // Always use OrderService to ensure order is updated with current cart data
            // It will find and reuse the same order if cart_hash matches
            $service = new OrderService();
            $order = $service->createFromCurrentCart($data);
            
            // If we detected a reusable order, get existing UUID and assign_url
            if ($is_reusing_order) {
                $uuid = $order->get_meta(\BWDK\Support\Constant::META_BWDK_UUID);
                $assign_url = $order->get_meta(\BWDK\Support\Constant::META_BWDK_ASSIGN_URL);
                
                if ($logger) {
                    $logger->info(
                        sprintf(
                            'BWDK REUSE: Using existing order - order_id=%d uuid=%s assign_url=%s',
                            $order->get_id(),
                            $uuid ?: 'N/A',
                            $assign_url ? 'EXISTS' : 'N/A'
                        ),
                        ['source' => 'bwdk_reuse']
                    );
                }
            }
            
            $pusher = new Client();
            $assign_url = $assign_url ?? null;
            $uuid = $uuid ?? null;

            if ($pusher) {
                // Capture origin page (cart/checkout) - prefer frontend-sent value
                $origin = isset($_POST['bwdk_origin']) ? sanitize_text_field($_POST['bwdk_origin']) : null;
                
                // Fallback to server-side detection if not provided
                if (empty($origin) || !in_array($origin, ['cart', 'checkout'], true)) {
                    $origin = $this->captureOriginPage();
                }
                
                // Ensure origin is valid
                if (!in_array($origin, ['cart', 'checkout'], true)) {
                    $origin = 'checkout'; // Default fallback
                }
                
                // Compute return_to URL based on origin
                $return_to = null;
                if ($origin === 'checkout') {
                    $return_to = function_exists('wc_get_checkout_url') ? wc_get_checkout_url() : home_url('/checkout/');
                } elseif ($origin === 'cart') {
                    $return_to = function_exists('wc_get_cart_url') ? wc_get_cart_url() : home_url('/cart/');
                }
                
                // Store origin and return_to in order meta
                $order->update_meta_data('_bwdk_origin', $origin);
                if ($return_to) {
                    $order->update_meta_data('_bwdk_return_to', $return_to);
                    // Also store in session for fallback
                    if (function_exists('WC') && WC()->session) {
                        WC()->session->set('bwdk_return_to', $return_to);
                    }
                }
                
                // Log origin capture
                $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
                if ($logger) {
                    $logger->info(
                        sprintf(
                            'BWDK RETURN TRACE: Origin captured - order_id=%d origin=%s return_to=%s',
                            $order->get_id(),
                            $origin,
                            $return_to ?: 'N/A'
                        ),
                        ['source' => 'bwdk_return_trace']
                    );
                }

                // Remember entry point before redirecting to Digikala
                if (!empty($callback_url)) {
                    // Parse the callback URL to determine if it's cart or checkout
                    $cart_url = function_exists('wc_get_cart_url') ? wc_get_cart_url() : '';
                    $checkout_url = function_exists('wc_get_checkout_url') ? wc_get_checkout_url() : '';
                    
                    // Normalize URLs for comparison (remove query strings and trailing slashes)
                    $normalized_callback = rtrim(preg_replace('/\?.*$/', '', $callback_url), '/');
                    $normalized_cart = rtrim(preg_replace('/\?.*$/', '', $cart_url), '/');
                    $normalized_checkout = rtrim(preg_replace('/\?.*$/', '', $checkout_url), '/');
                    
                    if ($normalized_cart && strpos($normalized_callback, $normalized_cart) !== false) {
                        ReturnUrlHelper::remember_cart_or_checkout();
                    } elseif ($normalized_checkout && strpos($normalized_callback, $normalized_checkout) !== false) {
                        ReturnUrlHelper::remember_cart_or_checkout();
                    } else {
                        // Fallback: check path patterns
                        $parsed_url = parse_url($callback_url);
                        $path = $parsed_url['path'] ?? '';
                        if (strpos($path, '/cart') !== false) {
                            ReturnUrlHelper::remember_cart_or_checkout();
                        } elseif (strpos($path, '/checkout') !== false) {
                            ReturnUrlHelper::remember_cart_or_checkout();
                        }
                    }
                } else {
                    // Fallback: check REQUEST_URI
                    $request_uri = $_SERVER['REQUEST_URI'] ?? '';
                    if (strpos($request_uri, '/cart') !== false) {
                        ReturnUrlHelper::remember_cart_or_checkout();
                    } elseif (strpos($request_uri, '/checkout') !== false) {
                        ReturnUrlHelper::remember_cart_or_checkout();
                    }
                }

                // ثبت نوت شروع فرایند خرید
                if ($order instanceof WC_Order) {
                    $flow = 'cart';
                    $source = strpos($_SERVER['REQUEST_URI'] ?? '', '/cart') !== false ? 'cart' : 'checkout';
                    $this->bwdk_note_started($order, ['flow' => $flow, 'source' => $source]);
                }

                $initiator = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(home_url($_SERVER['REQUEST_URI'])) : '';
                if (!$initiator) {
                    $initiator = wc_get_checkout_url();
                }
                $order->update_meta_data('_bwdk_initiator_url', $initiator);
                $order->save();

                // Always call createRemoteOrder to get fresh assign_url (even if UUID exists)
                // assign_url expires and needs to be refreshed for authentication
                $existing_uuid = $order->get_meta(\BWDK\Support\Constant::META_BWDK_UUID);
                $reservation_expired_at = $order->get_meta('_bwdk_reservation_expired_at');
                
                if (!empty($existing_uuid)) {
                    $is_reservation_valid = true;
                    if (!empty($reservation_expired_at)) {
                        $expired_timestamp = is_numeric($reservation_expired_at) ? (int) $reservation_expired_at : 0;
                        $is_reservation_valid = ($expired_timestamp > 0 && $expired_timestamp > time());
                    }
                    
                    if ($logger) {
                        $logger->info(
                            sprintf(
                                'BWDK REUSE: Existing UUID found - order_id=%d uuid=%s reservation_valid=%s - will refresh assign_url',
                                $order->get_id(),
                                $existing_uuid,
                                $is_reservation_valid ? 'yes' : 'no'
                            ),
                            ['source' => 'bwdk_reuse']
                        );
                    }
                }
                
                // Always create/refresh remote order to get fresh assign_url
                // assign_url expires and needs to be refreshed for authentication
                // Pass origin to createRemoteOrder so it can be embedded in return_url/cancel_url
                $res = $pusher->createRemoteOrder($order, $origin);
                if ($res['ok']) {
                    $assign_url = $res['order_start_url'] ?? null;
                    $uuid = $res['order_uuid'] ?? null;

                    if (!empty($uuid)) {
                        $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_UUID, $uuid);
                    }

                    if (!empty($assign_url)) {
                        $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_ASSIGN_URL, $assign_url);
                    }

                    if (!empty($callback_url)) {
                        $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_CB_URL, $callback_url);
                    } else {
                        // Set default callback URL if not provided
                        $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_CB_URL, wc_get_checkout_url());
                    }

                    $order->set_payment_method_title('پرداخت امن دیجیکالا');
                    $order_id = $order->save();

                    do_action('woocommerce_checkout_update_order_meta', $order_id, $data);
                    if (!$is_reusing_order) {
                    do_action('woocommerce_checkout_order_created', $order);
                    }
                } else {
                    error_log('[BWDK] Digify createRemoteOrder failed for order #' . $order->get_id() . ' code: ' . ($res['code'] ?? 0) . ' err: ' . ($res['error'] ?? 'unknown'));
                    wp_send_json_error(['message' => 'متاسفانه در حال حاضر امکان خرید با دیجیکالا در دسترس نمی‌باشد.'], 400);
                }
            }

            wp_send_json_success([
                'order_id' => $order->get_id(),
                'order_key' => $order->get_order_key(),
                'status' => $order->get_status(),
                'order_start_url' => $assign_url,
                'order_uuid' => $uuid,
            ]);


        } catch (Exception $e) {
            if (isset($order) && $order instanceof WC_Order) {
                wc_release_coupons_for_order($order);
                do_action('woocommerce_checkout_order_exception', $order);
            }
            wp_send_json_error(['message' => $e->getMessage()], 400);
            return new WP_Error('checkout-error', $e->getMessage());
        }
    }

    public function refund_digipay()
    {

        $order_uuid = $_POST["order_uuid"] ?? "";
        $order_id = $_POST["order_id"] ?? "";
        $order = wc_get_order($order_id);
        
        if (!$order instanceof WC_Order) {
            wp_send_json_error(['status' => false, 'message' => 'سفارش یافت نشد']);
            return;
        }

        $raw_json =  $order->get_meta(\BWDK\Support\Constant::META_BWDK_JSON_CB);

        try {
            $pusher = new Client();
            if ($pusher) {
                // ثبت نوت درخواست استرداد
                $this->bwdk_note_refundRequested($order, ['order_uuid' => $order_uuid]);
                
                $res = $pusher->refundOrder($order_uuid);





                if ($res) {
                    $res_status = isset($res['status']) ? (int) $res['status'] : 0;
                    if (BWDK_OrderStatus::isRefundFinalStatus($res_status)) {
                        // Refund final/success (status 13 or 17) – rely on status, not message
                        $status_label = isset($res['status_display']) && (string) $res['status_display'] !== ''
                            ? (string) $res['status_display']
                            : BWDK_OrderStatus::label($res_status);
                        $this->bwdk_note_refundStatus($order, $status_label, $res);

                        $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_REFUND_STATUS, $res);
                        $order->set_status("wc-refunded");
                        $raw_json["status"] = $res_status;
                        $raw_json["status_display"] = $status_label;
                        $raw = $raw_json ?? [];
                        $order->update_meta_data(\BWDK\Support\Constant::META_BWDK_JSON_CB, $raw);
                        $order->save();
                        wp_send_json_success([
                            'status' => true,
                            'message' => "ادمین گرامی، ازانجایی که مبلغ این سفارش با شما تسویه نشده است،  درخواست استرداد به دیجی پی ارسال شد و این مجموعه جهت تسویه حساب با کاربر طی چند روز کاری آتی اقدام خواهد کرد. لطفا مبلغی به کاربر پرداخت نفرمایید.",
                        ]);
                    } elseif (isset($res['non_field_errors']) && count($res['non_field_errors']) > 0) {
                        // ثبت نوت خطای استرداد
                        $error_msg = $res['non_field_errors'][0];
                        $this->bwdk_note_refundStatus($order, 'خطا: ' . $error_msg, $res);
                        
                        wp_send_json_success([
                            'status' => false,
                            'message' => $error_msg,
                        ]);
                    } else {
                        // ثبت نوت خطای استرداد
                        $this->bwdk_note_refundStatus($order, 'خطا در استرداد', $res);
                    }
                }
                
                // ثبت نوت خطای استرداد
                $error_data = is_array($res) ? $res : ['error' => 'پاسخ نامعتبر از API'];
                $this->bwdk_note_refundStatus($order, 'خطا در استرداد', $error_data);
                
                error_log('[BWDK] Digify refund failed for order #' . $order->get_id() . ' message: ' . ($res['message'] ?? 0) . ' refund_reason: ' . ($res['refund_reason'] ?? 'unknown'));
                wp_send_json_error([
                    'status' => false,
                    'message' => 'ادمین گرامی ،دیجی پی مبلغ این سفارش را با شما تسویه کرده است. لطفا جهت استرداد مبلغ سفارش با کاربر، شخصا اقدام نمایید و پرداختی به کاربر انجام دهید'
                ]);
            }
        } catch (Exception $e) {
            // ثبت نوت خطای استثنا در استرداد
            $this->bwdk_note_debug($order, 'خطا در استرداد (Exception)', ['message' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
            
            wp_send_json_error([
                'status' => false,
                'message' => $e->getMessage()
            ]);
            return new WP_Error('refund-error', $e->getMessage());
        }

        return false;
    }

    /**
     * Sync and verify BWDK order status from Digify API
     * Called via AJAX from admin order edit screen
     */
    public function sync_order()
    {
        // Check user capabilities
        if (!current_user_can('edit_shop_orders')) {
            wp_send_json_error(['message' => 'دسترسی غیرمجاز'], 403);
            return;
        }

        // Verify nonce
        if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'bwdk_admin_ajax')) {
            wp_send_json_error(['message' => 'درخواست نامعتبر'], 403);
            return;
        }

        $order_id = isset($_POST['order_id']) ? absint($_POST['order_id']) : 0;
        if (!$order_id) {
            wp_send_json_error(['message' => 'شناسه سفارش مشخص نیست'], 400);
            return;
        }

        $order = wc_get_order($order_id);
        if (!$order instanceof WC_Order) {
            wp_send_json_error(['message' => 'سفارش یافت نشد'], 404);
            return;
        }

        $order_uuid = $order->get_meta(\BWDK\Support\Constant::META_BWDK_UUID);
        if (empty($order_uuid)) {
            wp_send_json_error(['message' => 'این سفارش متعلق به BWDK نیست'], 400);
            return;
        }

        try {
            // Use the reusable sync service
            $sync_result = OrderSyncService::refresh_from_bwdk($order_id, [
                'source' => 'admin_button',
            ]);
            
            if (!$sync_result['ok']) {
                wp_send_json_error([
                    'message' => $sync_result['message'],
                ], 400);
                return;
            }

            // Prepare success message (do not say "verify انجام شد اما تأیید نشد" when request was not sent)
            $message = 'وضعیت سفارش به‌روزرسانی شد';
            if ($sync_result['verify_called'] && $sync_result['verify_ok']) {
                $message = 'وضعیت سفارش به‌روزرسانی و تأیید شد';
            } elseif (!empty($sync_result['verify_network_error'])) {
                $message = 'وضعیت سفارش به‌روزرسانی شد (Verify ارسال نشد - خطای شبکه/DNS)';
            } elseif ($sync_result['verify_called'] && !$sync_result['verify_ok']) {
                $message = 'وضعیت سفارش به‌روزرسانی شد (verify انجام شد اما تأیید نشد)';
            }

            // Set admin notice via transient (will be displayed after redirect/reload)
            $notice_key = 'bwdk_sync_notice_' . $order_id;
            set_transient($notice_key, [
                'message' => $message,
                'type' => $sync_result['verify_ok'] ? 'success' : 'info',
            ], 30);

            // Check if this is an AJAX request (from JavaScript) or form submit
            $is_ajax = wp_doing_ajax() || (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
            
            if ($is_ajax) {
                // AJAX request - return JSON response
                wp_send_json_success([
                    'message' => $message,
                    'verified' => $sync_result['verify_ok'],
                    'order_id' => $order_id,
                ]);
                return;
            } else {
                // Form submit - redirect to order edit page
                // Check if HPOS is enabled
                $redirect_url = '';
                if (function_exists('wc_get_container')) {
                    try {
                        $cot_util = wc_get_container()->get(\Automattic\WooCommerce\Internal\Utilities\COTMigrationUtil::class);
                        if ($cot_util && method_exists($cot_util, 'is_custom_orders_table_usage_enabled')) {
                            if ($cot_util->is_custom_orders_table_usage_enabled()) {
                                // HPOS enabled - use new admin URL
                                $redirect_url = admin_url('admin.php?page=wc-orders&action=edit&id=' . $order_id);
                            }
                        }
                    } catch (Exception $e) {
                        // Fallback to legacy
                    }
                }
                
                // Fallback to legacy post edit URL
                if (empty($redirect_url)) {
                    $redirect_url = admin_url('post.php?post=' . $order_id . '&action=edit');
                }

                wp_safe_redirect($redirect_url);
                exit;
            }

        } catch (Exception $e) {
            wp_send_json_error([
                'message' => 'خطا در به‌روزرسانی سفارش',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Extract merchant_unique_id from BWDK API response
     * Checks multiple possible locations in the response
     * 
     * @param array $raw BWDK API response data
     * @return string|null
     */
    private function extractMerchantUniqueIdFromResponse(array $raw): ?string
    {
        // Try multiple possible locations
        $possible_paths = [
            'merchant_unique_id',           // Top level
            'merchant.unique_id',           // Nested in merchant
            'merchant.merchant_unique_id',  // Alternative nested
            'order.merchant_unique_id',     // Nested in order
            'payment.merchant_unique_id',    // Nested in payment
        ];
        
        foreach ($possible_paths as $path) {
            $parts = explode('.', $path);
            $value = $raw;
            
            foreach ($parts as $part) {
                if (is_array($value) && isset($value[$part])) {
                    $value = $value[$part];
                } else {
                    $value = null;
                    break;
                }
            }
            
            if (!empty($value) && is_string($value)) {
                return trim($value);
            }
        }
        
        return null;
    }

    /**
     * Sync order address and customer info from BWDK response
     * Only fills empty fields - does not overwrite existing data
     * 
     * @param WC_Order $order
     * @param array $raw BWDK API response data
     * @return array ['updated_count' => int, 'updated_fields' => array, 'checked' => bool]
     */
    private function syncOrderAddressFromBwdk(WC_Order $order, array $raw): array
    {
        $updated_fields = [];
        $checked = false;

        // Helper function to check if field is empty
        $isEmpty = static function($value): bool {
            return empty(trim((string)$value));
        };

        // Helper function to clean value
        $clean = static function($value): string {
            return wc_clean(trim((string)$value));
        };

        // Extract destination_address (priority source for shipping address)
        $destination = $raw['destination_address'] ?? null;
        
        // Extract user info (for billing and name fields)
        $user = $raw['user'] ?? null;

        // ---------- Shipping Address from destination_address ----------
        if (!empty($destination) && is_array($destination)) {
            $checked = true;
            
            // Shipping Address 1
            $addr1 = $clean($destination['address'] ?? '');
            if (!empty($addr1) && $isEmpty($order->get_shipping_address_1())) {
                $order->set_shipping_address_1($addr1);
                $updated_fields[] = 'shipping_address_1';
            }

            // Shipping Address 2 (building, unit, district)
            $building = $clean($destination['building_number'] ?? '');
            $unit = $clean($destination['unit'] ?? '');
            $district = $clean($destination['district_name'] ?? '');
            
            $addr2Parts = array_filter([
                $district ?: null,
                $building ? "پلاک {$building}" : null,
                $unit ? "واحد {$unit}" : null,
            ]);
            $addr2 = $clean(implode('، ', $addr2Parts));
            
            if (!empty($addr2) && $isEmpty($order->get_shipping_address_2())) {
                $order->set_shipping_address_2($addr2);
                $updated_fields[] = 'shipping_address_2';
            }

            // Shipping City
            $city = $clean($destination['city_name'] ?? '');
            if (!empty($city) && $isEmpty($order->get_shipping_city())) {
                $order->set_shipping_city($city);
                $updated_fields[] = 'shipping_city';
            }

            // Shipping State
            $stateName = $clean($destination['state_name'] ?? '');
            if (!empty($stateName)) {
                $stateCode = $stateName;
                // Try to find state code from WooCommerce states
                if (function_exists('WC') && WC()->countries) {
                    $states = WC()->countries->get_states('IR') ?: [];
                    $found = array_search($stateName, $states, true);
                    if ($found !== false) {
                        $stateCode = $found;
                    }
                }
                
                if ($isEmpty($order->get_shipping_state())) {
                    $order->set_shipping_state($stateCode);
                    $updated_fields[] = 'shipping_state';
                }
            }

            // Shipping Postcode
            $postal = preg_replace('/\D+/', '', (string)($destination['postal_code'] ?? ''));
            if (!empty($postal) && $isEmpty($order->get_shipping_postcode())) {
                $order->set_shipping_postcode($postal);
                $updated_fields[] = 'shipping_postcode';
            }

            // Shipping Country (default to IR if not set)
            if ($isEmpty($order->get_shipping_country())) {
                $order->set_shipping_country('IR');
                $updated_fields[] = 'shipping_country';
            }

            // Shipping Phone from receiver_phone
            $receiver_phone_raw = $clean($destination['receiver_phone'] ?? '');
            if (!empty($receiver_phone_raw)) {
                $order->update_meta_data('_bwdk_receiver_phone', sanitize_text_field($receiver_phone_raw));
                // Normalize phone to local format (0...)
                $normalize_e164 = static function($p) {
                    $d = preg_replace('/\D+/', '', (string)$p);
                    if ($d && $d[0] === '0') $d = '98' . substr($d, 1);
                    if ($d && strpos($d, '98') !== 0) $d = '98' . $d;
                    return $d;
                };
                $to_local_0 = static function($e164) {
                    if (strpos($e164, '98') === 0) return '0' . substr($e164, 2);
                    return $e164;
                };
                
                $e164 = $normalize_e164($receiver_phone_raw);
                $local = $to_local_0($e164);
                
                $current_shipping_phone = '';
                if (method_exists($order, 'get_shipping_phone')) {
                    $current_shipping_phone = $order->get_shipping_phone();
                } else {
                    $current_shipping_phone = get_post_meta($order->get_id(), '_shipping_phone', true);
                }
                
                if ($isEmpty($current_shipping_phone)) {
                    if (method_exists($order, 'set_shipping_phone')) {
                        $order->set_shipping_phone($local);
                    } else {
                        update_post_meta($order->get_id(), '_shipping_phone', $local);
                    }
                    $order->update_meta_data('_bwdk_receiver_phone_e164', $e164);
                    $updated_fields[] = 'shipping_phone';
                }
            }

            // Receiver name (split to first/last if available)
            $receiver_name = $clean($destination['receiver_name'] ?? '');
            if (!empty($receiver_name)) {
                $order->update_meta_data('_bwdk_receiver_name', sanitize_text_field($receiver_name));
                // Try to split by first space
                $nameParts = explode(' ', $receiver_name, 2);
                $receiver_first = $nameParts[0] ?? '';
                $receiver_last = isset($nameParts[1]) ? trim($nameParts[1]) : '';
                
                if (!empty($receiver_first) && $isEmpty($order->get_shipping_first_name())) {
                    $order->set_shipping_first_name($receiver_first);
                    $updated_fields[] = 'shipping_first_name';
                }
                
                if (!empty($receiver_last) && $isEmpty($order->get_shipping_last_name())) {
                    $order->set_shipping_last_name($receiver_last);
                    $updated_fields[] = 'shipping_last_name';
                }
            }

            // Save extra meta fields (always, not just if empty)
            $dkId = $clean($destination['digikala_id'] ?? '');
            if (!empty($dkId)) {
                $order->update_meta_data('_dest_digikala_id', $dkId);
            }
            
            $district = $clean($destination['district_name'] ?? '');
            if (!empty($district)) {
                $order->update_meta_data('_dest_district_name', $district);
            }
            
            $lat = $clean($destination['latitude'] ?? '');
            if (!empty($lat)) {
                $order->update_meta_data('_dest_latitude', $lat);
            }
            
            $lng = $clean($destination['longitude'] ?? '');
            if (!empty($lng)) {
                $order->update_meta_data('_dest_longitude', $lng);
            }
        }

        // ---------- User info (for billing and name fallback) ----------
        if (!empty($user) && is_array($user)) {
            $checked = true;
            
            // Billing First Name
            $user_first_name = $clean($user['first_name'] ?? '');
            if (!empty($user_first_name) && $isEmpty($order->get_billing_first_name())) {
                $order->set_billing_first_name($user_first_name);
                $updated_fields[] = 'billing_first_name';
            }

            // Billing Last Name
            $user_last_name = $clean($user['last_name'] ?? '');
            if (!empty($user_last_name) && $isEmpty($order->get_billing_last_name())) {
                $order->set_billing_last_name($user_last_name);
                $updated_fields[] = 'billing_last_name';
            }

            // Billing Phone
            $user_phone = $clean($user['phone_number'] ?? '');
            if (!empty($user_phone) && $isEmpty($order->get_billing_phone())) {
                $order->set_billing_phone($user_phone);
                $updated_fields[] = 'billing_phone';
            }

            // Shipping First/Last Name (fallback if not set from receiver_name)
            if (!empty($user_first_name) && $isEmpty($order->get_shipping_first_name())) {
                $order->set_shipping_first_name($user_first_name);
                $updated_fields[] = 'shipping_first_name';
            }
            
            if (!empty($user_last_name) && $isEmpty($order->get_shipping_last_name())) {
                $order->set_shipping_last_name($user_last_name);
                $updated_fields[] = 'shipping_last_name';
            }

            // Shipping Phone (fallback if not set from receiver_phone)
            if (!empty($user_phone)) {
                $current_shipping_phone = '';
                if (method_exists($order, 'get_shipping_phone')) {
                    $current_shipping_phone = $order->get_shipping_phone();
                } else {
                    $current_shipping_phone = get_post_meta($order->get_id(), '_shipping_phone', true);
                }
                
                if ($isEmpty($current_shipping_phone)) {
                    if (method_exists($order, 'set_shipping_phone')) {
                        $order->set_shipping_phone($user_phone);
                    } else {
                        update_post_meta($order->get_id(), '_shipping_phone', $user_phone);
                    }
                    $updated_fields[] = 'shipping_phone';
                }
            }

            // Billing Address (copy from shipping if billing is empty)
            if ($isEmpty($order->get_billing_address_1()) && !$isEmpty($order->get_shipping_address_1())) {
                $order->set_billing_address_1($order->get_shipping_address_1());
                $updated_fields[] = 'billing_address_1';
            }
            
            if ($isEmpty($order->get_billing_address_2()) && !$isEmpty($order->get_shipping_address_2())) {
                $order->set_billing_address_2($order->get_shipping_address_2());
                $updated_fields[] = 'billing_address_2';
            }
            
            if ($isEmpty($order->get_billing_city()) && !$isEmpty($order->get_shipping_city())) {
                $order->set_billing_city($order->get_shipping_city());
                $updated_fields[] = 'billing_city';
            }
            
            if ($isEmpty($order->get_billing_state()) && !$isEmpty($order->get_shipping_state())) {
                $order->set_billing_state($order->get_shipping_state());
                $updated_fields[] = 'billing_state';
            }
            
            if ($isEmpty($order->get_billing_postcode()) && !$isEmpty($order->get_shipping_postcode())) {
                $order->set_billing_postcode($order->get_shipping_postcode());
                $updated_fields[] = 'billing_postcode';
            }
            
            if ($isEmpty($order->get_billing_country())) {
                $order->set_billing_country('IR');
                $updated_fields[] = 'billing_country';
            }
        }

        // Save order if any fields were updated
        if (!empty($updated_fields)) {
            $order->save();
        }

        return [
            'updated_count' => count($updated_fields),
            'updated_fields' => array_values(array_unique($updated_fields)),
            'checked' => $checked,
        ];
    }

    /**
     * Validate cart using WooCommerce native validation BEFORE creating any order.
     * If validation fails, sends JSON error response and stops execution.
     * 
     * @return void Exits with wp_send_json_error if validation fails
     */
    private function validateCartOrFail(): void
    {
        $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
        
        if ($logger) {
            $logger->info('BWDK STOCK GUARD: Validation start', ['source' => 'bwdk_stock_guard']);
        }
        
        // Check if WooCommerce cart is available
        if (!function_exists('WC') || !WC()->cart) {
            $error_msg = __('سبد خرید در دسترس نیست.', 'bwdk');
            if ($logger) {
                $logger->warning('BWDK STOCK GUARD: Cart not available', ['source' => 'bwdk_stock_guard']);
            }
            status_header(409);
            wp_send_json_error([
                'message' => $error_msg,
                'errors' => [$error_msg],
                'code' => 'cart_invalid'
            ], 409);
            exit;
        }
        
        $cart = WC()->cart;
        
        // Check if cart is empty
        if ($cart->is_empty()) {
            $error_msg = __('سبد خرید شما خالی است.', 'bwdk');
            if ($logger) {
                $logger->warning('BWDK STOCK GUARD: Cart is empty', ['source' => 'bwdk_stock_guard']);
            }
            status_header(409);
            wp_send_json_error([
                'message' => $error_msg,
                'errors' => [$error_msg],
                'code' => 'cart_invalid'
            ], 409);
            exit;
        }
        
        // Calculate totals to ensure cart state is up to date
        $cart->calculate_totals();
        
        // Clear any existing error notices before validation
        wc_clear_notices();
        
        // Use WooCommerce native cart validation (includes out-of-stock checks)
        $cart->check_cart_items();
        
        // Get error notice count
        $error_count = wc_notice_count('error');
        
                if ($logger) {
            $logger->info(
                sprintf('BWDK STOCK GUARD: wc_notice_count(error)=%d', $error_count),
                        ['source' => 'bwdk_stock_guard']
                    );
                }
        
        // If there are errors, collect them and stop execution
        if ($error_count > 0) {
            $error_notices = wc_get_notices('error');
            $error_messages = [];
            
            foreach ($error_notices as $notice) {
                // Strip HTML tags from notice message
                $message = isset($notice['notice']) ? strip_tags($notice['notice']) : '';
                if (!empty($message)) {
                    $error_messages[] = $message;
                }
            }
            
                if ($logger) {
                    $logger->warning(
                        sprintf(
                        'BWDK STOCK GUARD: Cart validation failed - error_count=%d messages=%s',
                        $error_count,
                        implode(' | ', $error_messages)
                        ),
                        ['source' => 'bwdk_stock_guard']
                    );
                $logger->info('BWDK STOCK GUARD: Order creation skipped', ['source' => 'bwdk_stock_guard']);
            }
            
            // Get first error message for main message
            $first_message = !empty($error_messages) ? $error_messages[0] : __('خطا در اعتبارسنجی سبد خرید.', 'bwdk');
            
            // DO NOT create any order - send error response and exit
            status_header(409);
            wp_send_json_error([
                'message' => $first_message,
                'errors' => $error_messages,
                'code' => 'cart_invalid'
            ], 409);
            exit;
        }
        
                        if ($logger) {
            $logger->info('BWDK STOCK GUARD: Cart validation passed', ['source' => 'bwdk_stock_guard']);
        }
    }

    /**
     * Find reusable existing BWDK order with same cart signature
     * 
     * @return WC_Order|null Reusable order if found, null otherwise
     */
    private function findReusableOrder(): ?WC_Order
    {
        if (!function_exists('WC') || !WC()->cart || !WC()->session) {
            return null;
        }
        
        $cart_hash = WC()->cart->get_cart_hash();
        if (empty($cart_hash)) {
            return null;
        }
        
        // Check for existing reusable BWDK order with same cart hash
        $existing_orders = wc_get_orders([
            'limit' => 1,
            'meta_key' => '_bwdk_cart_hash',
            'meta_value' => $cart_hash,
            'status' => ['pending', 'on-hold', 'failed', 'bwdk-pending'],
            'return' => 'objects',
        ]);
        
        if (empty($existing_orders)) {
            return null;
        }
        
        $existing_order = reset($existing_orders);
        
        // Verify it has BWDK UUID (active BWDK flow)
        $bwdk_uuid = $existing_order->get_meta(\BWDK\Support\Constant::META_BWDK_UUID);
        if (empty($bwdk_uuid)) {
            return null;
        }
        
        // Verify order is not cancelled
        if ($existing_order->get_status() === 'cancelled') {
            return null;
        }
        
        // Check reservation expiration if it exists
        $reservation_expired_at = $existing_order->get_meta('_bwdk_reservation_expired_at');
        if (!empty($reservation_expired_at)) {
            $expired_timestamp = is_numeric($reservation_expired_at) ? (int) $reservation_expired_at : 0;
            if ($expired_timestamp > 0 && $expired_timestamp <= time()) {
                // Reservation expired - don't reuse
                return null;
            }
        }
        
        return $existing_order;
    }

    /**
     * Capture origin page (cart/checkout) before redirecting to Digify
     */
    protected function captureOriginPage(): ?string
    {
        // Check if currently on checkout page
        if (function_exists('is_checkout') && is_checkout()) {
            return 'checkout';
        }
        
        // Check if currently on cart page
        if (function_exists('is_cart') && is_cart()) {
            return 'cart';
        }
        
        // Try to determine from referer
        $referer = wp_get_referer();
        if ($referer) {
            $parsed = wp_parse_url($referer);
            if ($parsed && isset($parsed['host'])) {
                $home_parsed = wp_parse_url(home_url());
                // Only check if same host
                if (isset($home_parsed['host']) && $parsed['host'] === $home_parsed['host']) {
                    $path = $parsed['path'] ?? '';
                    if (strpos($path, '/checkout') !== false) {
                        return 'checkout';
                    } elseif (strpos($path, '/cart') !== false) {
                        return 'cart';
                    }
                }
            }
        }
        
        // Fallback: check cart contents
        if (function_exists('WC') && WC()->cart && !WC()->cart->is_empty()) {
            return 'checkout';
        } else {
            return 'cart';
        }
    }

    /**
     * Cleanup abandoned BWDK orders (pending/failed/on-hold that are not paid)
     * This releases stock before stock validation to prevent out-of-stock errors
     * when user returns from Digikala without completing payment
     * 
     * @return void
     */
    private function cleanupAbandonedBwdkOrders(): void
    {
        $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
        
        // Get current user/session identifiers
        $customer_id = get_current_user_id();
        $session_id = function_exists('WC') && WC()->session ? WC()->session->get_customer_id() : '';
        
        // Find abandoned BWDK orders for this user/session
        // Orders must have BWDK UUID (active BWDK flow) and be in non-paid status
        $query_args = [
            'limit' => 10, // Limit to prevent too many queries
            'meta_key' => \BWDK\Support\Constant::META_BWDK_UUID,
            'meta_compare' => 'EXISTS',
            'status' => ['pending', 'on-hold', 'failed'],
            'return' => 'ids',
            'orderby' => 'date',
            'order' => 'DESC',
        ];
        
        // Filter by customer if logged in
        if ($customer_id > 0) {
            $query_args['customer_id'] = $customer_id;
        } else {
            // For guest users, try to match by session
            // Note: WooCommerce doesn't directly support session-based queries,
            // so we'll get recent orders and filter by session meta if available
            $query_args['customer_id'] = 0;
        }
        
        $abandoned_order_ids = wc_get_orders($query_args);
        
        if (empty($abandoned_order_ids)) {
            return;
        }
        
        // Filter orders: must be BWDK orders and not paid
        $orders_to_cleanup = [];
        foreach ($abandoned_order_ids as $order_id) {
            $order = wc_get_order($order_id);
            if (!$order instanceof \WC_Order) {
                continue;
            }
            
            // Must have BWDK UUID
            $bwdk_uuid = $order->get_meta(\BWDK\Support\Constant::META_BWDK_UUID);
            if (empty($bwdk_uuid)) {
                continue;
            }
            
            // Check if order is paid (has payment completed)
            $is_paid = $order->is_paid();
            if ($is_paid) {
                continue; // Skip paid orders
            }
            
            // For guest users, also check session match if available
            if ($customer_id === 0 && !empty($session_id)) {
                $order_session_id = $order->get_meta('_bwdk_session_id');
                if (!empty($order_session_id) && $order_session_id !== $session_id) {
                    continue; // Different session
                }
            }
            
            $orders_to_cleanup[] = $order;
        }
        
        if (empty($orders_to_cleanup)) {
            return;
        }
        
        // Cleanup each abandoned order
        foreach ($orders_to_cleanup as $order) {
            $order_id = $order->get_id();
            
            if ($logger) {
                $logger->info(
                    sprintf(
                        'BWDK CLEANUP: Cleaning up abandoned order - order_id=%d status=%s customer_id=%d',
                        $order_id,
                        $order->get_status(),
                        $order->get_customer_id()
                    ),
                    ['source' => 'bwdk_cleanup']
                );
            }
            
            // 1) Cancel the order (releases stock)
            if ($order->get_status() !== 'cancelled') {
                $order->update_status(
                    'cancelled',
                    'BWDK Cleanup: سفارش نیمه‌کاره لغو شد قبل از شروع خرید جدید.'
                );
            }
            
            // 2) Release stock (if not already released)
            if (!metadata_exists('post', $order_id, '_bwdk_stock_released')) {
                wc_maybe_increase_stock_levels($order_id);
                $order->update_meta_data('_bwdk_stock_released', 1);
                $order->save();
            }
            
            // 3) Move to trash (instead of permanent delete)
            wp_trash_post($order_id);
            
            if ($logger) {
                $logger->info(
                    sprintf(
                        'BWDK CLEANUP: Abandoned order trashed - order_id=%d',
                        $order_id
                    ),
                    ['source' => 'bwdk_cleanup']
                );
            }
        }
    }
}
