<?php

namespace BWDK\Woo;

use BWDK\Support\Constant;
use BWDK\Support\OrderNoteHelper;
use BWDK\Support\ReturnUrlHelper;
use BWDK\Integrations\Digify\Client;
use WC_Order_Item_Product;
use WC_Order;
use Exception;
use WC_Product;
use WC_Product_Variation;

class SingleBuyEndpoint
{
    use OrderNoteHelper;
    public function register(): void
    {
        // Add rewrite rule for the endpoint
        add_rewrite_rule(
            '^bwdk-single-buy/?$',
            'index.php?__bwdk_single_buy=1',
            'top'
        );

        // Add query vars
        add_filter('query_vars', function($vars) {
            $vars[] = '__bwdk_single_buy';
            return $vars;
        });

        // Handle the request
        add_action('template_redirect', function() {
            if (get_query_var('__bwdk_single_buy')) {
                $this->handle();
                exit;
            }
        });
    }

    public function handle(): void
    {
        $logger = wc_get_logger();
        
        // Debug: Log POST data
        $logger->info('BWDK Single Buy - POST data: ' . print_r($_POST, true), ['source' => 'bwdk-single-buy-debug']);
        
        // Security check
        if (!isset($_POST['bwdk_single_buy_nonce']) || !wp_verify_nonce($_POST['bwdk_single_buy_nonce'], 'bwdk_single_buy')) {
            $logger->error('BWDK Single Buy - Nonce verification failed', ['source' => 'bwdk-single-buy-debug']);
            wc_add_notice(__('لطفاً صفحه را دوباره بارگذاری کنید.', 'bwdk'), 'error');
            wp_safe_redirect(wp_get_referer() ?: home_url());
            exit;
        }

        try {
            // STEP 0: Cleanup abandoned BWDK orders BEFORE order creation
            // This prevents out-of-stock errors when user returns from Digikala without completing payment
            $this->cleanupAbandonedBwdkOrders();
            
            // Get product data from POST
            $product_id = isset($_POST['product_id']) ? absint($_POST['product_id']) : 0;
            $variation_id = isset($_POST['variation_id']) ? absint($_POST['variation_id']) : 0;
            $quantity = isset($_POST['quantity']) ? absint($_POST['quantity']) : 1;

            if (!$product_id || $quantity <= 0) {
                throw new Exception(__('اطلاعات محصول ناقص است.', 'bwdk'));
            }

            // Get the parent product
            $parent_product = wc_get_product($product_id);
            
            if (!$parent_product || !$parent_product->is_purchasable()) {
                throw new Exception(__('این محصول در دسترس نیست.', 'bwdk'));
            }

            // Handle variable products
            if ($parent_product->is_type('variable')) {
                // Collect attributes from request
                $attrs = [];
                foreach ($_POST as $k => $v) {
                    if (strpos($k, 'attribute_') === 0) {
                        $attrs[$k] = wc_clean(wp_unslash($v));
                    }
                }

                // Normalize empty values to empty strings
                foreach ($attrs as $k => $v) {
                    if ($v === null) {
                        $attrs[$k] = '';
                    }
                }

                // Use WooCommerce data store to find matching variation
                $matched_id = null;
                
                // First, try WooCommerce's native method if available
                if (class_exists('WC_Data_Store')) {
                    $data_store = \WC_Data_Store::load('product');
                    if (method_exists($data_store, 'find_matching_product_variation')) {
                        $matched_id = $data_store->find_matching_product_variation($parent_product, $attrs);
                    }
                }

                // Fallback: use helper function if available
                if (!$matched_id && function_exists('wc_get_matching_product_variation')) {
                    $matched_id = wc_get_matching_product_variation($parent_product, $attrs);
                }

                // If user posted an explicit variation_id, trust but verify
                if ($variation_id && $matched_id !== $variation_id) {
                    $valid_children = $parent_product->get_children();
                    if (in_array($variation_id, $valid_children, true)) {
                        $matched_id = $variation_id;
                    }
                }

                // If still no match and user explicitly sent variation_id, try to use it
                if (!$matched_id && $variation_id) {
                    $variation_check = wc_get_product($variation_id);
                    if ($variation_check && $variation_check->get_parent_id() == $product_id) {
                        $matched_id = $variation_id;
                    }
                }

                if (!$matched_id) {
                    $logger->error('BWDK Single Buy - No matching variation found', [
                        'source' => 'bwdk-single-buy-debug',
                        'attributes' => $attrs,
                        'product_id' => $product_id
                    ]);
                    wc_add_notice(__('لطفاً یک گزینه را انتخاب کنید.', 'bwdk'), 'error');
                    wp_safe_redirect(get_permalink($product_id));
                    exit;
                }

                $variation = wc_get_product($matched_id);
                if (!$variation || !$variation->exists() || !$variation->is_purchasable()) {
                    $logger->error('BWDK Single Buy - Variation invalid or not purchasable', ['source' => 'bwdk-single-buy-debug']);
                    wc_add_notice(__('این ترکیب نامعتبر است یا قابل خرید نیست.', 'bwdk'), 'error');
                    wp_safe_redirect(get_permalink($product_id));
                    exit;
                }

                $product = $variation;
                $variation_id = $matched_id;
            } else {
                // Simple product
                $product = $parent_product;
            }

            // Create WooCommerce order
            $order = $this->createOrder($product, $variation_id, $quantity);

            if (!$order) {
                throw new Exception(__('خطا در ایجاد سفارش.', 'bwdk'));
            }

            // Mark this as single flow before remote call so payload builders can read it
            $order->update_meta_data(Constant::META_BWDK_SINGLE_FLOW, '1');

            // Store product ID for later use (return/cancel URLs etc.)
            $single_product_id = $product->is_type('variation') ? $product->get_parent_id() : $product->get_id();
            if ($single_product_id) {
                $order->update_meta_data('_bwdk_single_product_id', $single_product_id);
                // Remember product page for cancel redirect
                ReturnUrlHelper::remember_product($single_product_id);
            }

        // Persist metadata before calling remote API
        $order->save();

        $initiator = '';
        $target_id = $single_product_id ?: $product_id;
        if ($target_id) {
            $initiator = get_permalink($target_id);
        }
        if (!$initiator) {
            $initiator = home_url('/');
        }
        $order->update_meta_data('_bwdk_initiator_url', esc_url_raw($initiator));
        $order->save();

        // ثبت نوت شروع فرایند خرید
        $this->bwdk_note_started($order, ['flow' => 'single', 'source' => 'single']);

            // Call Digify API to create remote order and get assign URL
            $client = new Client();
            $result = $client->createRemoteOrder($order);

            if (!$result['ok'] || !isset($result['order_start_url'])) {
                $order->delete();
                throw new Exception(__('خطا در اتصال به دیجی‌کالا. لطفاً دوباره تلاش کنید.', 'bwdk'));
            }

            // Save metadata
            if (!empty($result['order_uuid'])) {
                $order->update_meta_data(Constant::META_BWDK_UUID, $result['order_uuid']);
            }
            
            if (!empty($result['order_start_url'])) {
                $order->update_meta_data(Constant::META_BWDK_ASSIGN_URL, $result['order_start_url']);
            }

            // Store product ID in session for browser back support
            if (WC()->session) {
                WC()->session->set('bwdk_last_single_pid', (int) $product_id);
            }
            
            // Save callback URL
            $callback_url = $order->get_checkout_order_received_url();
            $order->update_meta_data(Constant::META_BWDK_CB_URL, $callback_url);

            $order->save();

            // Log for debugging
            $logger->info('Single buy order created: #' . $order->get_id(), ['source' => 'bwdk-single-buy']);
            $logger->info('Redirect URL: ' . $result['order_start_url'], ['source' => 'bwdk-single-buy-debug']);

            // Redirect to Digikala
            wp_redirect($result['order_start_url']);
            exit;

        } catch (Exception $e) {
            $logger->error('BWDK Single Buy Error: ' . $e->getMessage(), ['source' => 'bwdk-single-buy']);
            $logger->error('BWDK Single Buy Stack trace: ' . $e->getTraceAsString(), ['source' => 'bwdk-single-buy-debug']);
            
            wc_add_notice($e->getMessage(), 'error');
            
            // Try to redirect back to product page
            $redirect_url = wp_get_referer();
            if (!$redirect_url || strpos($redirect_url, '/wp-admin/') !== false) {
                // If referer is admin or doesn't exist, redirect to home
                $redirect_url = home_url();
            }
            
            $logger->info('BWDK Single Buy - Redirecting to: ' . $redirect_url, ['source' => 'bwdk-single-buy-debug']);
            wp_safe_redirect($redirect_url);
            exit;
        }
    }

    protected function createOrder(WC_Product $product, int $variation_id, int $quantity): WC_Order
    {
        // Create new order
        $order = new WC_Order();
        
        // Set basic order data
        $order->set_created_via('single-buy');
        $order->set_customer_id(get_current_user_id());
        $order->set_currency(get_woocommerce_currency());
        $order->set_prices_include_tax('yes' === get_option('woocommerce_prices_include_tax'));
        $order->set_customer_ip_address(\WC_Geolocation::get_ip_address());
        $order->set_customer_user_agent(wc_get_user_agent());
        $order->set_payment_method_title('پرداخت امن دیجیکالا');
        
        // Create order meta UUID
        $order->update_meta_data(Constant::META_BWDK_WOO_ORDER_UUID, wp_generate_uuid4());

        // Calculate totals
        $line_subtotal = (float) $product->get_price('edit') * $quantity;
        $line_total = $line_subtotal;
        
        // Handle tax
        $tax_class = $product->get_tax_class();
        $tax_rates = \WC_Tax::find_rates(['country' => '', 'state' => '', 'postcode' => '', 'city' => '', 'tax_class' => $tax_class]);
        
        $tax_totals = \WC_Tax::calc_tax($line_subtotal, $tax_rates, 'yes' === get_option('woocommerce_prices_include_tax'));
        $line_tax = array_sum($tax_totals);
        
        // Add tax to total if prices don't include tax
        if ('no' === get_option('woocommerce_prices_include_tax')) {
            $line_total += $line_tax;
        }

        // Create line item
        $item = new WC_Order_Item_Product();
        $item->set_props([
            'name' => $product->get_name(),
            'tax_class' => $tax_class,
            'product_id' => $product->is_type('variation') ? $product->get_parent_id() : $product->get_id(),
            'variation_id' => $variation_id,
            'quantity' => $quantity,
            'subtotal' => $line_subtotal,
            'total' => $line_total,
            'subtotal_tax' => $line_tax,
            'total_tax' => $line_tax,
        ]);

        // Add variation attributes as meta
        if ($variation_id && $product->is_type('variation')) {
            $attributes = $product->get_variation_attributes();
            foreach ($attributes as $attribute_name => $attribute_value) {
                $item->add_meta_data($attribute_name, $attribute_value, true);
            }
        }

        $order->add_item($item);

        // Calculate totals
        $order->set_discount_total(0);
        $order->set_discount_tax(0);
        $order->set_shipping_total(0);
        $order->set_shipping_tax(0);
        $order->set_cart_tax($line_tax);
        $order->set_total($line_total);

        // Fire actions for compatibility
        do_action('woocommerce_checkout_create_order', $order, []);
        do_action('woocommerce_checkout_create_order_line_item', $item, '', [], $order);

        return $order;
    }

    /**
     * Cleanup abandoned BWDK orders (pending/failed/on-hold that are not paid)
     * This releases stock before order creation to prevent out-of-stock errors
     * when user returns from Digikala without completing payment
     * 
     * @return void
     */
    private function cleanupAbandonedBwdkOrders(): void
    {
        $logger = wc_get_logger();
        
        // 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' => 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
            $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(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();
            
            $logger->info(
                sprintf(
                    'BWDK CLEANUP (Single Buy): 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);
            
            $logger->info(
                sprintf(
                    'BWDK CLEANUP (Single Buy): Abandoned order trashed - order_id=%d',
                    $order_id
                ),
                ['source' => 'bwdk_cleanup']
            );
        }
    }
}

