<?php

/**
 * Handle all AJAX requests for the plugin.
 *
 * @since      1.0.0
 * @package     DevNajmusOneClickOrderPopup
 * @subpackage  DevNajmusOneClickOrderPopup/includes
 */

if (!defined('WPINC')) {
    die;
}

/**
 * Handle all AJAX requests for the plugin.
 */
class DOPW_Ajax
{
    /**
     * Initialize the class.
     *
     * @return void
     */
    public function init()
    {
        add_action('wp_ajax_DOPW_process_order', array($this, 'process_order'));
        add_action('wp_ajax_nopriv_DOPW_process_order', array($this, 'process_order'));
        add_action('wp_ajax_DOPW_get_variations', array($this, 'get_variations'));
        add_action('wp_ajax_nopriv_DOPW_get_variations', array($this, 'get_variations'));
        add_action('wp_ajax_DOPW_get_gateway_fields', array($this, 'get_gateway_fields'));
        add_action('wp_ajax_nopriv_DOPW_get_gateway_fields', array($this, 'get_gateway_fields'));
    }

    /**
     * Return variation data for a variable product.
     *
     * @return void
     */
    public function get_variations()
    {
        // Verify nonce
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!$nonce || !wp_verify_nonce(wp_unslash($nonce), 'DOPW_nonce')) {
            wp_send_json_error(array('message' => __('Security check failed', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        $product_id = filter_input(INPUT_POST, 'product_id', FILTER_VALIDATE_INT, array('options' => array('default' => 0)));
        if (!$product_id) {
            wp_send_json_error(array('message' => __('Invalid product ID', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        $product = wc_get_product($product_id);
        if (!$product || !$product->is_type('variable')) {
            wp_send_json_error(array('message' => __('Not a variable product', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        /** @var WC_Product_Variable $product */
        $variations = $product->get_available_variations();
        $raw_attributes = $product->get_variation_attributes();

        // Normalize attributes for dropdowns
        $attributes = array();
        foreach ($raw_attributes as $attr_key => $opts) {
            $normalized = array();
            foreach ($opts as $opt) {
                if (empty($opt)) {
                    continue;
                }

                $slug = '';
                $label = $opt;

                // Handle taxonomy-based attributes (pa_)
                if (strpos($attr_key, 'pa_') === 0) {
                    $taxonomy = $attr_key;
                    $term = get_term_by('slug', $opt, $taxonomy);
                    if (!$term || is_wp_error($term)) {
                        $term = get_term_by('name', $opt, $taxonomy);
                    }
                    if ($term && !is_wp_error($term)) {
                        $slug = $term->slug;
                        $label = $term->name;
                    } else {
                        $slug = sanitize_title($opt);
                        $label = $opt;
                    }
                } else {
                    // Custom attributes
                    $slug = sanitize_title($opt);
                    $label = $opt;
                }

                $normalized[] = array('slug' => $slug, 'label' => $label);
            }

            // Remove duplicates based on slug
            $attributes[$attr_key] = array_values(array_unique($normalized, SORT_REGULAR));
        }

        // Prepare variations with consistent attribute structure
        $data_variations = array();
        foreach ($variations as $v) {
            $variation_id = isset($v['variation_id']) ? intval($v['variation_id']) : 0;
            if (!$variation_id) {
                continue;
            }

            $variation_obj = wc_get_product($variation_id);
            if (!$variation_obj) {
                continue;
            }

            // Build variation attributes ensuring consistent slugs
            $variation_attributes = array();

            foreach ($raw_attributes as $attr_key => $possible_values) {
                // Get the attribute value for this variation
                $value = '';

                // Try to get from variation's attributes first
                if (isset($v['attributes']) && isset($v['attributes']['attribute_' . $attr_key])) {
                    $value = $v['attributes']['attribute_' . $attr_key];
                } else {
                    // Fallback to getting from variation object
                    $value = $variation_obj->get_attribute($attr_key);
                }

                // Normalize the value to match dropdown options
                if ($value !== '') {
                    if (strpos($attr_key, 'pa_') === 0) {
                        // Taxonomy attribute - ensure we use slug
                        $term = get_term_by('slug', $value, $attr_key);
                        if (!$term || is_wp_error($term)) {
                            $term = get_term_by('name', $value, $attr_key);
                        }
                        if ($term && !is_wp_error($term)) {
                            $value = $term->slug;
                        } else {
                            $value = sanitize_title($value);
                        }
                    } else {
                        // Custom attribute - sanitize consistently
                        $value = sanitize_title($value);
                    }
                }

                // Store with 'attribute_' prefix to match WooCommerce standard
                $variation_attributes['attribute_' . $attr_key] = $value;
            }

            // Get prices
            $price = $variation_obj->get_price();
            $regular_price = $variation_obj->get_regular_price();
            $sale_price = $variation_obj->get_sale_price();
            $display_price = !empty($sale_price) ? $sale_price : ($regular_price ?: $price);

            // Get image
            $image_src = '';
            if ($variation_obj->get_image_id()) {
                $image_src = wp_get_attachment_image_url($variation_obj->get_image_id(), 'woocommerce_thumbnail');
            } elseif ($product->get_image_id()) {
                $image_src = wp_get_attachment_image_url($product->get_image_id(), 'woocommerce_thumbnail');
            }

            $data_variations[] = array(
                'variation_id'   => $variation_id,
                'attributes'     => $variation_attributes,
                'price'          => floatval($price),
                'display_price'  => floatval($display_price),
                'regular_price'  => floatval($regular_price ?: 0),
                'sale_price'     => floatval($sale_price ?: 0),
                'price_html'     => $variation_obj->get_price_html(),
                'is_in_stock'    => $variation_obj->is_in_stock(),
                'is_purchasable' => $variation_obj->is_purchasable(),
                'title'          => $variation_obj->get_name(),
                'image'          => array('src' => $image_src),
                'sku'            => $variation_obj->get_sku(),
            );
        }

        wp_send_json_success(array(
            'attributes' => $attributes,
            'variations' => $data_variations,
            'product_title' => $product->get_name(),
            'product_id' => $product_id,
        ));
    }

    /**
     * Process the quick order.
     *
     * @return void
     */
    public function process_order()
    {
        // Verify nonce
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!$nonce || !wp_verify_nonce(wp_unslash($nonce), 'DOPW_nonce')) {
            wp_send_json_error(array('message' => __('Security check failed', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        // Sanitize customer data
        $customer = array();
        $raw_customer = filter_input(INPUT_POST, 'customer', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
        if (is_array($raw_customer)) {
            $customer = array_map('sanitize_text_field', wp_unslash($raw_customer));
        }

        // Sanitize order data
        $order_data = array();
        $raw_order_data = filter_input(INPUT_POST, 'order', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
        if (is_array($raw_order_data)) {
            $order_data = $this->sanitize_recursive(wp_unslash($raw_order_data));
        }

        // Sanitize order items array
        if (!empty($order_data['items']) && is_array($order_data['items'])) {
            foreach ($order_data['items'] as &$item) {
                $item['id'] = isset($item['id']) ? intval($item['id']) : 0;
                $item['quantity'] = isset($item['quantity']) ? intval($item['quantity']) : 1;
                $item['variation_id'] = isset($item['variation_id']) ? intval($item['variation_id']) : 0;
                $item['price'] = isset($item['price']) ? floatval($item['price']) : 0;
                if (isset($item['variation_attributes']) && is_array($item['variation_attributes'])) {
                    $item['variation_attributes'] = array_map('sanitize_text_field', $item['variation_attributes']);
                }
                if (isset($item['product_type'])) {
                    $item['product_type'] = sanitize_text_field($item['product_type']);
                }
            }
            unset($item);
        }

        // Sanitize other order fields
        $order_data['shipping_method'] = isset($order_data['shipping_method']) ? sanitize_text_field($order_data['shipping_method']) : '';
        $order_data['payment_method'] = isset($order_data['payment_method']) ? sanitize_text_field($order_data['payment_method']) : '';
        $order_data['subtotal'] = isset($order_data['subtotal']) ? floatval($order_data['subtotal']) : 0;
        $order_data['shipping'] = isset($order_data['shipping']) ? floatval($order_data['shipping']) : 0;
        $order_data['total'] = isset($order_data['total']) ? floatval($order_data['total']) : 0;

        // Validate input
        if (empty($customer['name']) || empty($customer['phone']) || empty($customer['address']) || empty($order_data['items']) || !is_array($order_data['items'])) {
            wp_send_json_error(array('message' => __('Missing required customer or order data', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        // Validate email if provided
        if (!empty($customer['email']) && !is_email($customer['email'])) {
            wp_send_json_error(array('message' => __('Invalid email address', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        // Validate items
        foreach ($order_data['items'] as $item) {
            if ($item['id'] <= 0) {
                wp_send_json_error(array('message' => sprintf(
                    /* translators: %d: Product ID */
                    __('Invalid product ID: %d', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                    $item['id']
                )));
            }
            if ($item['product_type'] === 'variable' && $item['variation_id'] <= 0) {
                wp_send_json_error(array('message' => __('Missing variation ID for variable product', 'devnajmus-oneclick-order-popup-for-woocommerce')));
            }
        }

        // Prepare and set necessary WooCommerce session and customer data so gateways work
        try {
            // If Stripe client-side created a payment method, capture it from POST so gateways can use it.
            $client_pm_id = isset($_POST['payment_method_id']) ? sanitize_text_field(wp_unslash($_POST['payment_method_id'])) : '';
            $client_save_pm = filter_input(INPUT_POST, 'save_payment_method', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
            if ($client_pm_id) {
                // Store common keys many gateway plugins look for
                if (function_exists('WC') && WC()->session) {
                    WC()->session->set('stripe_payment_method_id', $client_pm_id);
                    WC()->session->set('stripe_payment_method', $client_pm_id);
                    WC()->session->set('dopw_stripe_payment_method_id', $client_pm_id);
                }
                // Also populate superglobal so some gateways reading $_POST find it
                $_POST['payment_method_id'] = $client_pm_id;
                $_POST['stripe_payment_method_id'] = $client_pm_id;
            }
            if ($client_save_pm !== null) {
                if (function_exists('WC') && WC()->session) {
                    WC()->session->set('stripe_save_payment_method', (bool)$client_save_pm);
                    WC()->session->set('dopw_save_payment_method', (bool)$client_save_pm);
                }
                $_POST['save_payment_method'] = $client_save_pm ? '1' : '0';
            }
            // Defaults for missing billing/shipping fields
            $billing_first_name = $customer['name'];
            $billing_phone = $customer['phone'];
            $billing_email = !empty($customer['email']) ? $customer['email'] : '';
            $billing_address_1 = $customer['address'];
            // Do NOT hard-code country/city/postcode — use provided values or store defaults
            $billing_city = !empty($customer['city']) ? $customer['city'] : '';
            $billing_postcode = !empty($customer['postcode']) ? $customer['postcode'] : '';
            $billing_country = !empty($customer['country']) ? $customer['country'] : (function_exists('WC') && isset(WC()->countries) ? WC()->countries->get_base_country() : '');

            // Ensure WC session and customer objects are present
            if ( function_exists('WC') && WC()->session ) {
                // Set chosen payment and shipping in session
                if (!empty($order_data['payment_method'])) {
                    WC()->session->set('chosen_payment_method', $order_data['payment_method']);
                }
                if (!empty($order_data['shipping_method'])) {
                    WC()->session->set('chosen_shipping_methods', array($order_data['shipping_method']));
                }
            }

            if ( function_exists('WC') && WC()->customer ) {
                // Populate the WC_Customer object so gateways that read customer data from it will work
                WC()->customer->set_billing_first_name($billing_first_name);
                WC()->customer->set_billing_email($billing_email);
                WC()->customer->set_billing_phone($billing_phone);
                WC()->customer->set_billing_address_1($billing_address_1);
                WC()->customer->set_billing_city($billing_city);
                WC()->customer->set_billing_postcode($billing_postcode);
                WC()->customer->set_billing_country($billing_country);
                // For shipping we mirror billing (popup has only one address field)
                WC()->customer->set_shipping_address_1($billing_address_1);
                WC()->customer->set_shipping_city($billing_city);
                WC()->customer->set_shipping_postcode($billing_postcode);
                WC()->customer->set_shipping_country($billing_country);
                // Save customer to ensure meta/session persistence
                WC()->customer->save();
            }

            // Populate `$_POST` with billing/payment fields so WooCommerce validations/hooks behave as they would on regular checkout
            try {
                $_POST['billing_first_name'] = isset($_POST['billing_first_name']) ? sanitize_text_field(wp_unslash($_POST['billing_first_name'])) : $billing_first_name;
                $_POST['billing_phone'] = isset($_POST['billing_phone']) ? sanitize_text_field(wp_unslash($_POST['billing_phone'])) : $billing_phone;
                $_POST['billing_email'] = isset($_POST['billing_email']) ? sanitize_text_field(wp_unslash($_POST['billing_email'])) : $billing_email;
                $_POST['billing_address_1'] = isset($_POST['billing_address_1']) ? sanitize_text_field(wp_unslash($_POST['billing_address_1'])) : $billing_address_1;
                $_POST['billing_city'] = isset($_POST['billing_city']) ? sanitize_text_field(wp_unslash($_POST['billing_city'])) : $billing_city;
                $_POST['billing_postcode'] = isset($_POST['billing_postcode']) ? sanitize_text_field(wp_unslash($_POST['billing_postcode'])) : $billing_postcode;
                $_POST['billing_country'] = isset($_POST['billing_country']) ? sanitize_text_field(wp_unslash($_POST['billing_country'])) : $billing_country;
                $_POST['payment_method'] = isset($_POST['payment_method']) ? sanitize_text_field(wp_unslash($_POST['payment_method'])) : (isset($order_data['payment_method']) ? $order_data['payment_method'] : '');
                // If the popup UI supplies a terms/agreement flag, map it to the expected POST value so WC validation works
                if (isset($order_data['terms']) && $order_data['terms']) {
                    $_POST['terms'] = '1';
                }
            } catch (Exception $e) {
                // ignore population errors; validation will still run against whatever $_POST contains
            }

            // Run the standard WooCommerce checkout validation hooks so plugins (terms, custom validators) run
            try {
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- calling core WC hook intentionally
                do_action('woocommerce_checkout_process');
            } catch (Exception $e) {
                // ignore
            }

            // If validation produced any errors, return them to the client and stop
            if (function_exists('wc_get_notices')) {
                $errs = wc_get_notices('error');
                if (!empty($errs) && is_array($errs)) {
                    // Clear so notices don't leak into other requests
                    if (function_exists('wc_clear_notices')) wc_clear_notices();
                    $messages = array();
                    foreach ($errs as $er) {
                        if (is_array($er) && isset($er['notice'])) $messages[] = $er['notice']; else $messages[] = (string)$er;
                    }
                    wp_send_json_error(array('message' => implode(' ', $messages)));
                }
            }

            // Create WooCommerce order
            $order = wc_create_order();
            if (is_wp_error($order)) {
                wp_send_json_error(array('message' => sprintf(
                    /* translators: %s: Error message */
                    __('Failed to create order: %s', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                    $order->get_error_message()
                )));
            }

            // Add customer details to order
            // Link order to logged-in user if present so it appears in My Account
            if (is_user_logged_in() && method_exists($order, 'set_customer_id')) {
                $order->set_customer_id(get_current_user_id());
            }

            $order->set_billing_first_name($billing_first_name);
            $order->set_billing_phone($billing_phone);
            $order->set_billing_email($billing_email);
            $order->set_billing_address_1($billing_address_1);
            $order->set_billing_city($billing_city);
            $order->set_billing_postcode($billing_postcode);
            $order->set_billing_country($billing_country);

            $order->set_shipping_address_1($billing_address_1);
            $order->set_shipping_city($billing_city);
            $order->set_shipping_postcode($billing_postcode);
            $order->set_shipping_country($billing_country);

            // Add products to order
            foreach ($order_data['items'] as $item) {
                $product = wc_get_product($item['id']);
                if (!$product) {
                    wp_send_json_error(array('message' => sprintf(
                        /* translators: %d: Product ID */
                        __('Invalid product: %d', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                        $item['id']
                    )));
                }

                if ($item['product_type'] === 'variable') {
                    $variation_id = $item['variation_id'];
                    $variation = wc_get_product($variation_id);
                    if (!$variation || !$variation->is_in_stock() || !$variation->is_purchasable()) {
                        wp_send_json_error(array('message' => sprintf(
                            /* translators: %d: Variation ID */
                            __('Invalid or out-of-stock variation: %d', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                            $variation_id
                        )));
                    }
                    $order->add_product($variation, $item['quantity'], array(
                        'variation' => isset($item['variation_attributes']) ? $item['variation_attributes'] : array(),
                        'subtotal' => $item['price'] * $item['quantity'],
                        'total' => $item['price'] * $item['quantity'],
                    ));
                } else {
                    if (!$product->is_in_stock() || !$product->is_purchasable()) {
                        wp_send_json_error(array('message' => sprintf(
                            /* translators: %d: Product ID */
                            __('Product out of stock or not purchasable: %d', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                            $item['id']
                        )));
                    }
                    $order->add_product($product, $item['quantity'], array(
                        'subtotal' => $item['price'] * $item['quantity'],
                        'total' => $item['price'] * $item['quantity'],
                    ));
                }
            }

            // Set shipping (as an order item) if provided
            if (!empty($order_data['shipping_method'])) {
                $shipping_item = new WC_Order_Item_Shipping();
                $shipping_item->set_method_id($order_data['shipping_method']);
                $shipping_item->set_total($order_data['shipping']);
                $order->add_item($shipping_item);
            }

            // Set payment method on order
            if (!empty($order_data['payment_method'])) {
                $order->set_payment_method($order_data['payment_method']);
            }
            // Default status
            $order->set_status('pending');

            // Allow other plugins to modify the order object before it's saved (mimic checkout)
            try {
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- calling core WC hook intentionally
                do_action('woocommerce_checkout_create_order', $order, $order_data);
            } catch (Exception $e) {
                // ignore
            }

            $order->calculate_totals();


            // Save order and get ID
            $order_id = $order->save();
            if (!$order_id) {
                wp_send_json_error(array('message' => __('Failed to save order', 'devnajmus-oneclick-order-popup-for-woocommerce')));
            }

            // Call update_order_meta so plugins that save custom fields using this hook will work
            try {
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- calling core WC hook intentionally
                do_action('woocommerce_checkout_update_order_meta', $order_id, $order_data);
            } catch (Exception $e) {
                // ignore
            }

            // As a safety-net, save some common popup custom fields directly so they are available
            try {
                $o_safety = wc_get_order($order_id);
                if ($o_safety) {
                    if (!empty($order_data['delivery_date'])) {
                        $o_safety->update_meta_data('delivery_date', sanitize_text_field($order_data['delivery_date']));
                    }
                    if (!empty($order_data['gift_message'])) {
                        $o_safety->update_meta_data('gift_message', sanitize_text_field($order_data['gift_message']));
                    }
                    // Also map customer-level custom fields if provided
                    if (!empty($customer['delivery_date'])) {
                        $o_safety->update_meta_data('delivery_date', sanitize_text_field($customer['delivery_date']));
                    }
                    if (!empty($customer['gift_message'])) {
                        $o_safety->update_meta_data('gift_message', sanitize_text_field($customer['gift_message']));
                    }
                    $o_safety->save();
                }
            } catch (Exception $e) {
                // ignore
            }

            // Trigger standard checkout hooks so other plugins can attach data (mimic WC_Checkout behavior)
            try {
                // Pass the WC_Order object first to match WooCommerce internal listeners
                do_action('woocommerce_checkout_order_created', $order, $order_data, $order_id); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- calling core WC hook intentionally
            } catch (Exception $e) {
                // Non-fatal
            }

            // Set session flag so WooCommerce knows an order is awaiting payment (helps reuse/hold-stock behavior)
            if (function_exists('WC') && WC()->session) {
                WC()->session->set('order_awaiting_payment', $order_id);
            }

            // Fire checkout processed hook (WC_Checkout normally triggers this before calling gateway processing)
            try {
                // Pass the WC_Order object first to match WooCommerce internal listeners
                do_action('woocommerce_checkout_order_processed', $order, $order_data, $order_id); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- calling core WC hook intentionally
            } catch (Exception $e) {
                // ignore
            }

            // Ensure payment method meta/title is saved on the order so it appears on the "order received" page
            $payment_method_id = !empty($order_data['payment_method']) ? $order_data['payment_method'] : '';
            if (!empty($payment_method_id)) {
                $payment_method_title = '';
                if (class_exists('WC_Payment_Gateways')) {
                    $all_gateways = WC()->payment_gateways()->get_available_payment_gateways();
                    if (isset($all_gateways[$payment_method_id])) {
                        $gw = $all_gateways[$payment_method_id];
                        if (method_exists($gw, 'get_title')) {
                            $payment_method_title = $gw->get_title();
                        } elseif (!empty($gw->title)) {
                            $payment_method_title = $gw->title;
                        }
                    }
                }

                if (empty($payment_method_title)) {
                    // Fallback: prettify the payment method id
                    $payment_method_title = ucwords(str_replace(array('_', '-'), ' ', $payment_method_id));
                }

                // Store payment method using WC_Order setters to avoid internal-meta warnings
                if (method_exists($order, 'set_payment_method')) {
                    $order->set_payment_method($payment_method_id);
                } else {
                    $order->update_meta_data('_payment_method', $payment_method_id);
                }

                if (method_exists($order, 'set_payment_method_title')) {
                    $order->set_payment_method_title($payment_method_title);
                } else {
                    $order->update_meta_data('_payment_method_title', $payment_method_title);
                }

                $order->save();
            }

            // If a payment gateway was chosen, attempt to process payment using that gateway
            $gateway_result = null;
            if (!empty($order_data['payment_method']) && class_exists('WC_Payment_Gateways')) {
                $available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
                $gateway_id = $order_data['payment_method'];
                $gateway = isset($available_gateways[$gateway_id]) ? $available_gateways[$gateway_id] : null;

                if ($gateway && method_exists($gateway, 'process_payment')) {
                    // Some gateways expect the cart/session to be set; we already populated customer/session above.
                    $gateway_result = $gateway->process_payment($order_id);
                }
            }

            // Normalize gateway result
            if (is_array($gateway_result)) {
                // If gateway explicitly returned a failure result, report error to client
                if (!empty($gateway_result['result']) && $gateway_result['result'] === 'failure') {
                    // Try to gather any WooCommerce notices for a helpful message
                    $errors = array();
                    if (function_exists('wc_get_notices')) {
                        $notices = wc_get_notices('error');
                        if (!empty($notices) && is_array($notices)) {
                            foreach ($notices as $n) {
                                if (is_array($n) && isset($n['notice'])) $errors[] = $n['notice']; else $errors[] = (string)$n;
                            }
                        }
                        // Clear notices so they don't leak to other requests
                        if (function_exists('wc_clear_notices')) wc_clear_notices();
                    }
                    $message = !empty($errors) ? implode(' ', $errors) : (isset($gateway_result['message']) ? $gateway_result['message'] : __('Payment failed', 'devnajmus-oneclick-order-popup-for-woocommerce'));
                    // Mark order as failed so it is not left in pending state
                    try {
                        $o = wc_get_order($order_id);
                        if ($o) {
                            /* translators: %s: Error message returned by payment gateway or validator */
                            $o->update_status('failed', sprintf(__('Payment failed: %s', 'devnajmus-oneclick-order-popup-for-woocommerce'), $message));
                            /* translators: %s: Error message returned by payment gateway or validator */
                            $o->add_order_note(sprintf(__('Payment failure recorded by popup checkout: %s', 'devnajmus-oneclick-order-popup-for-woocommerce'), $message));
                        }
                    } catch (Exception $e) {
                        // ignore
                    }
                    wp_send_json_error(array('message' => $message, 'gateway_result' => $gateway_result, 'order_id' => $order_id));
                }

                // If gateway returned a redirect (Stripe / PayPal checkout etc.), forward it to the JS
                if (!empty($gateway_result['result']) && $gateway_result['result'] === 'success' && !empty($gateway_result['redirect'])) {
                    // For off-site redirects we keep the session order_awaiting_payment so the core can handle return/retries
                    wp_send_json_success(array(
                        'order_id' => $order_id,
                        'message' => __('Payment gateway returned a redirect', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                        'redirect' => esc_url_raw($gateway_result['redirect']),
                        'gateway_result' => $gateway_result,
                    ));
                }

                // Some gateways may return other structured responses (e.g., Stripe PaymentIntent client_secret)
                // If the gateway indicates success without redirect, assume on-site payment flow — clear cart and session
                if (!empty($gateway_result['result']) && $gateway_result['result'] === 'success') {
                    // On-site success: mark payment complete (if still pending) and return a redirect to order-received
                    try {
                        $o = wc_get_order($order_id);
                        if ($o && in_array($o->get_status(), array('pending', 'on-hold'))) {
                            // This will set status to processing/completed as appropriate and trigger WC hooks
                            $o->payment_complete();
                        }
                        $received = $o ? $o->get_checkout_order_received_url() : '';
                    } catch (Exception $e) {
                        $received = '';
                    }

                    if (function_exists('WC') && WC()->cart) {
                        WC()->cart->empty_cart();
                    }
                    if (function_exists('WC') && WC()->session) {
                        WC()->session->set('order_awaiting_payment', '');
                        // clear any temporary stripe keys we set
                        WC()->session->set('stripe_payment_method_id', '');
                        WC()->session->set('stripe_save_payment_method', '');
                        WC()->session->set('dopw_stripe_payment_method_id', '');
                        WC()->session->set('dopw_save_payment_method', '');
                    }

                    wp_send_json_success(array(
                        'order_id' => $order_id,
                        'message' => __('Payment processed (gateway response available)', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                        'gateway_result' => $gateway_result,
                        'redirect' => $received ? esc_url_raw($received) : '',
                    ));
                }

                // Otherwise forward whatever gateway_result exists for client-side handling
                wp_send_json_success(array(
                    'order_id' => $order_id,
                    'message' => __('Payment processed (gateway response available)', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                    'gateway_result' => $gateway_result,
                ));
            }

            // If no gateway result or gateway didn't return redirect, return success and the order-received URL
            $order_obj = wc_get_order($order_id);
            $received_url = $order_obj ? $order_obj->get_checkout_order_received_url() : home_url('/');

            // Clean up cart/session for non-redirect flows (order created locally)
            if (function_exists('WC') && WC()->cart) {
                WC()->cart->empty_cart();
            }
            if (function_exists('WC') && WC()->session) {
                // Clear awaiting payment flag and any temporary stripe data
                WC()->session->set('order_awaiting_payment', '');
                WC()->session->set('stripe_payment_method_id', '');
                WC()->session->set('stripe_save_payment_method', '');
                WC()->session->set('dopw_stripe_payment_method_id', '');
                WC()->session->set('dopw_save_payment_method', '');
            }

            wp_send_json_success(array(
                'order_id' => $order_id,
                'message' => __('Order created successfully', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                'redirect' => esc_url_raw($received_url),
            ));
        } catch (Exception $e) {
            // Collect WooCommerce notices if available (helpful for debugging)
            $notices = array();
            if (function_exists('wc_get_notices')) {
                $n = wc_get_notices('error');
                if (!empty($n) && is_array($n)) {
                    foreach ($n as $x) {
                        if (is_array($x) && isset($x['notice'])) $notices[] = $x['notice']; else $notices[] = (string)$x;
                    }
                    if (function_exists('wc_clear_notices')) wc_clear_notices();
                }
            }

            $message = sprintf(
                /* translators: %s: Error message */
                __('Error processing order: %s', 'devnajmus-oneclick-order-popup-for-woocommerce'),
                $e->getMessage()
            );

            $response = array('message' => $message);

            // Only expose detailed internals when WP_DEBUG is enabled
            if (defined('WP_DEBUG') && WP_DEBUG) {
                $response['exception'] = array(
                    'message' => $e->getMessage(),
                    'code'    => $e->getCode(),
                    'file'    => $e->getFile(),
                    'line'    => $e->getLine(),
                    'trace'   => $e->getTraceAsString(),
                );
                if (!empty($notices)) $response['notices'] = $notices;
                // Include a sanitized snapshot of order input to help debug (WP_DEBUG only)
                if (isset($order_data)) $response['debug_order'] = $order_data;
            }

            // Log full details to PHP error log for server-side investigation
            $log = 'DOPW process_order exception: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine();
                    if (defined('WP_DEBUG') && WP_DEBUG) {
                $log .= "\nTrace:\n" . $e->getTraceAsString();
                if (!empty($notices)) $log .= "\nNotices: " . wp_json_encode($notices);
                if (isset($order_data)) $log .= "\nOrder data: " . wp_json_encode($order_data);
                // Temporarily include the full POST payload and raw input to help debugging
                $post_snapshot = isset($_POST) ? wp_unslash($_POST) : array();
                $log .= "\n\n--- POST payload snapshot ---\n" . wp_json_encode($post_snapshot);
                $raw = @file_get_contents('php://input');
                if ($raw) {
                    $log .= "\n--- Raw request body ---\n" . $raw;
                }
            }
            // Use WooCommerce logger if available (preferred over error_log for production)
            if (function_exists('wc_get_logger')) {
                $logger = wc_get_logger();
                $logger->error($log, array('source' => 'devnajmus-oneclick-order-popup-for-woocommerce'));
            }

            wp_send_json_error($response);
        }
    }

    /**
     * Return gateway-specific payment fields HTML (if available).
     *
     * @return void
     */
    public function get_gateway_fields()
    {
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!$nonce || !wp_verify_nonce(wp_unslash($nonce), 'DOPW_nonce')) {
            wp_send_json_error(array('message' => __('Security check failed', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        $gateway_id = isset($_POST['gateway_id']) ? sanitize_text_field(wp_unslash($_POST['gateway_id'])) : '';
        if (empty($gateway_id) || !class_exists('WC_Payment_Gateways')) {
            wp_send_json_error(array('message' => __('Invalid gateway', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        $available = WC()->payment_gateways()->get_available_payment_gateways();
        $gateway = isset($available[$gateway_id]) ? $available[$gateway_id] : null;
        if (!$gateway) {
            // try loading all
            $all = WC()->payment_gateways()->payment_gateways();
            $gateway = isset($all[$gateway_id]) ? $all[$gateway_id] : null;
        }

        if (!$gateway) {
            wp_send_json_error(array('message' => __('Payment gateway not found', 'devnajmus-oneclick-order-popup-for-woocommerce')));
        }

        // Capture payment fields output
        ob_start();
        try {
            if (method_exists($gateway, 'payment_fields')) {
                $gateway->payment_fields();
            } else {
                // Fallback: try to call a render method if exists
                if (method_exists($gateway, 'render_payment_fields')) {
                    $gateway->render_payment_fields();
                }
            }
        } catch (Exception $e) {
            // ignore errors, return what we have
        }
        $html = (string) ob_get_clean();

        // Extract external scripts/styles and inline scripts so client can load them reliably
        $external_scripts = array();
        $inline_scripts = array();
        $external_styles = array();

        // Extract <script src="..."> tags
        if (preg_match_all("/<script[^>]+src=[\"']([^\"']+)[\"'][^>]*><\/script>/i", $html, $m_scripts)) {
            foreach ($m_scripts[1] as $src) {
                $external_scripts[] = esc_url_raw($src);
            }
            // remove external script tags from html
            $html = preg_replace("/<script[^>]+src=[\"'][^\"']+[\"'][^>]*><\/script>/i", '', $html);
        }

        // Extract inline <script>...</script>
        if (preg_match_all('/<script[^>]*>(.*?)<\/script>/is', $html, $m_inline)) {
            foreach ($m_inline[1] as $code) {
                $trimmed = trim($code);
                if ($trimmed !== '') $inline_scripts[] = $trimmed;
            }
            // remove inline scripts from html
            $html = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $html);
        }

        // Extract link rel=stylesheet
        if (preg_match_all("/<link[^>]+href=[\"']([^\"']+)[\"'][^>]*rel=[\"']?stylesheet[\"']?[^>]*>/i", $html, $m_links)) {
            foreach ($m_links[1] as $href) {
                $external_styles[] = esc_url_raw($href);
            }
            $html = preg_replace("/<link[^>]+rel=[\"']?stylesheet[\"']?[^>]*>/i", '', $html);
        }

        wp_send_json_success(array('html' => $html, 'external_scripts' => array_values(array_unique($external_scripts)), 'external_styles' => array_values(array_unique($external_styles)), 'inline_scripts' => $inline_scripts));
    }

    /**
     * Recursively sanitize arrays and strings.
     *
     * @param mixed $data The data to sanitize.
     * @return mixed The sanitized data.
     */
    private function sanitize_recursive($data)
    {
        if (is_array($data)) {
            return array_map(array($this, 'sanitize_recursive'), $data);
        }
        return is_string($data) ? sanitize_text_field($data) : $data;
    }
}
