<?php

namespace BWDK\Woo\Order;

use BWDK\Enums\BWDK_OrderStatus;
use BWDK\Support\Constant;
use WC_Order;

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

/**
 * Handles automatic BWDK sync when WooCommerce orders are about to be cancelled
 * due to hold stock timeout
 */
class OrderCancelSync
{
    /**
     * Meta key for sync lock (prevents recursion)
     */
    const META_SYNC_LOCK = '_bwdk_sync_lock';
    
    /**
     * Meta key for last sync timestamp (cooldown)
     */
    const META_LAST_SYNC = '_bwdk_last_sync_timestamp';
    
    /**
     * Cooldown period in seconds (60 seconds = 1 minute)
     */
    const COOLDOWN_SECONDS = 60;

    /**
     * Register hooks
     * 
     * Note: Priority 5 is used to run BEFORE WooCommerce's stock restock (which runs at priority 10).
     * This allows us to check BWDK status and potentially change order to 'processing' before
     * WooCommerce restocks inventory. If we change status to 'processing', WooCommerce won't restock.
     * If restock already happened, handleStockConsistency() will re-reduce stock.
     */
    public function register(): void
    {
        // Hook into order status changes - specifically when transitioning to cancelled
        // Use priority 5 to run before WooCommerce's stock restock (priority 10)
        add_action('woocommerce_order_status_changed', [$this, 'handleOrderStatusChange'], 5, 4);
        
        // Also hook into pending_to_cancelled transition for more specificity
        add_action('woocommerce_order_status_pending_to_cancelled', [$this, 'handlePendingToCancelled'], 5, 2);
    }

    /**
     * Handle order status change - check if BWDK order is being cancelled
     * 
     * @param int $order_id Order ID
     * @param string $old_status Old status
     * @param string $new_status New status
     * @param WC_Order $order Order object
     */
    public function handleOrderStatusChange(int $order_id, string $old_status, string $new_status, WC_Order $order): void
    {
        // Only process transitions to cancelled
        if ($new_status !== 'cancelled') {
            return;
        }

        // Only process pending/on-hold orders (hold stock scenarios)
        if (!in_array($old_status, ['pending', 'on-hold'], true)) {
            return;
        }

        $this->processCancellationSync($order);
    }

    /**
     * Handle pending to cancelled transition
     * 
     * @param int $order_id Order ID
     * @param WC_Order $order Order object
     */
    public function handlePendingToCancelled(int $order_id, WC_Order $order): void
    {
        $this->processCancellationSync($order);
    }

    /**
     * Process BWDK sync for order cancellation
     * 
     * @param WC_Order $order Order object
     */
    private function processCancellationSync(WC_Order $order): void
    {
        // Check if this is a BWDK order
        $order_uuid = $order->get_meta(Constant::META_BWDK_UUID);
        if (empty($order_uuid)) {
            return; // Not a BWDK order
        }

        // Check sync lock to prevent recursion
        $sync_lock = $order->get_meta(self::META_SYNC_LOCK);
        if (!empty($sync_lock)) {
            $lock_time = (int) $sync_lock;
            // Lock expires after 5 minutes
            if (time() - $lock_time < 300) {
                return; // Sync already in progress or recently completed
            }
        }

        // Check cooldown to prevent multiple API calls
        $last_sync = $order->get_meta(self::META_LAST_SYNC);
        if (!empty($last_sync)) {
            $last_sync_time = (int) $last_sync;
            if (time() - $last_sync_time < self::COOLDOWN_SECONDS) {
                return; // Too soon since last sync
            }
        }

        // Set sync lock
        $order->update_meta_data(self::META_SYNC_LOCK, time());
        $order->save();

        try {
            // Call the reusable sync service
            $sync_result = OrderSyncService::refresh_from_bwdk($order->get_id(), [
                'source' => 'auto_cancel',
                'skip_address_sync' => false, // Still sync address info
            ]);

            // Update last sync timestamp
            $order->update_meta_data(self::META_LAST_SYNC, time());

            // Add order note with sync result
            $note_message = sprintf(
                'BWDK Sync: %s',
                $sync_result['ok'] ? $sync_result['message'] : sprintf('خطا: %s', $sync_result['message'])
            );
            $order->add_order_note($note_message, false); // false = internal note (customer_note=false)

            // Check if order is paid/verified and should be moved to processing
            if ($sync_result['ok']) {
                $bwdk_status = $sync_result['bwdk_status'];
                $is_paid_or_verified = (
                    $bwdk_status === BWDK_OrderStatus::PAID_BY_USER ||
                    $bwdk_status === BWDK_OrderStatus::VERIFIED_BY_MERCHANT
                );

                if ($is_paid_or_verified) {
                    // Order is paid/verified - prevent cancellation and move to processing
                    
                    // Handle stock consistency: WooCommerce may have already restocked
                    // We need to reduce stock again if it was increased
                    $this->handleStockConsistency($order);

                    // Add verify note if verify was called (do not say "انجام شد اما تأیید نشد" when request not sent)
                    if ($sync_result['verify_called']) {
                        if (!empty($sync_result['verify_network_error'])) {
                            $order->add_order_note('BWDK Sync: Verify ارسال نشد (خطای شبکه/DNS)', false);
                        } else {
                            $verify_note = sprintf(
                                'BWDK Sync: Verify %s | result=%s',
                                $sync_result['verify_ok'] ? 'انجام شد و تأیید شد' : 'انجام شد اما تأیید نشد',
                                $sync_result['verify_ok'] ? 'success' : 'failed'
                            );
                            $order->add_order_note($verify_note, false);
                        }
                    } elseif ($sync_result['was_verified']) {
                        $order->add_order_note('BWDK Sync: قبلاً Verify شده بود', false);
                    }

                    // Change status to processing only if allowed (one-time, early-status only).
                    if (function_exists('bwdk_is_admin_manual_status_change_to_final') && bwdk_is_admin_manual_status_change_to_final($order)) {
                        $order->add_order_note('BWDK debug: skipped auto-processing because admin manually changed status.', false);
                    } elseif (function_exists('bwdk_has_recent_admin_manual_status_lock') && bwdk_has_recent_admin_manual_status_lock($order, 300)) {
                        $order->add_order_note('BWDK debug: skipped auto-processing because admin manual status lock is active.', false);
                    } elseif (function_exists('bwdk_can_auto_move_to_processing') && bwdk_can_auto_move_to_processing($order)) {
                        // Use update_status with a note explaining why
                        $order->update_status(
                            'processing',
                            'BWDK Sync: پرداخت تایید شد، سفارش از لغو خارج شد',
                            false // false = not a customer note
                        );
                        $order->update_meta_data('_bwdk_auto_processing_done', 'yes');
                        $order->save();

                        $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
                        if ($logger) {
                            $logger->info(
                                sprintf(
                                    'BWDK Auto-Sync: Order #%d moved to processing (was being cancelled) | bwdk_status=%d | order_uuid=%s',
                                    $order->get_id(),
                                    $bwdk_status,
                                    $order_uuid
                                ),
                                ['source' => 'bwdk_auto_sync']
                            );
                        }
                    }
                } else {
                    // Order is not paid - allow cancellation to proceed
                    $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
                    if ($logger) {
                        $logger->info(
                            sprintf(
                                'BWDK Auto-Sync: Order #%d not paid, allowing cancellation | bwdk_status=%d | order_uuid=%s',
                                $order->get_id(),
                                $bwdk_status,
                                $order_uuid
                            ),
                            ['source' => 'bwdk_auto_sync']
                        );
                    }
                }
            } else {
                // Sync failed - log error but allow cancellation
                $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
                if ($logger) {
                    $logger->error(
                        sprintf(
                            'BWDK Auto-Sync ERROR: Order #%d sync failed | message=%s | order_uuid=%s',
                            $order->get_id(),
                            $sync_result['message'],
                            $order_uuid
                        ),
                        ['source' => 'bwdk_auto_sync']
                    );
                }
            }

        } catch (\Exception $e) {
            // Log exception but allow cancellation to proceed
            $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
            if ($logger) {
                $logger->error(
                    sprintf(
                        'BWDK Auto-Sync EXCEPTION: Order #%d | error=%s | order_uuid=%s',
                        $order->get_id(),
                        $e->getMessage(),
                        $order_uuid
                    ),
                    ['source' => 'bwdk_auto_sync']
                );
            }
            
            $order->add_order_note(
                sprintf('BWDK Sync ERROR: %s', $e->getMessage()),
                false
            );
        } finally {
            // Remove sync lock
            $order->delete_meta_data(self::META_SYNC_LOCK);
            $order->save();
        }
    }

    /**
     * Handle stock consistency when order is moved from cancelled to processing
     * WooCommerce may have already restocked items when order was cancelled
     * 
     * @param WC_Order $order Order object
     */
    private function handleStockConsistency(WC_Order $order): void
    {
        // Check if stock was already restocked
        // WooCommerce sets _order_stock_reduced meta to false when restocking
        $stock_reduced = $order->get_meta('_order_stock_reduced');
        
        // If stock was not reduced (or was reduced then restocked), we need to reduce it again
        if ($stock_reduced !== 'yes') {
            // Use WooCommerce core function to reduce stock
            if (function_exists('wc_reduce_stock_levels')) {
                wc_reduce_stock_levels($order);
                
                $logger = function_exists('wc_get_logger') ? wc_get_logger() : null;
                if ($logger) {
                    $logger->info(
                        sprintf(
                            'BWDK Auto-Sync: Stock reduced for order #%d (was restocked due to cancellation)',
                            $order->get_id()
                        ),
                        ['source' => 'bwdk_auto_sync']
                    );
                }
            }
        }
    }
}
