<?php
// Order Management System
if (!defined('ABSPATH')) {
    exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

class GGM_Commerce_Orders {
    private static $instance = null;

    public static function get_instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function __construct() {
        // AJAX handlers for order management
        add_action('wp_ajax_ggm_commerce_create_order', [$this, 'ajax_create_order']);
        add_action('wp_ajax_nopriv_ggm_commerce_create_order', [$this, 'ajax_create_order']);
        add_action('wp_ajax_ggm_commerce_get_order', [$this, 'ajax_get_order']);
        add_action('wp_ajax_ggm_commerce_get_customer_orders', [$this, 'ajax_get_customer_orders']);
        add_action('wp_ajax_ggm_commerce_update_order_status', [$this, 'ajax_update_order_status']);
        add_action('wp_ajax_ggm_commerce_get_order_details_html', [$this, 'ajax_get_order_details_html']);
        add_action('wp_ajax_ggm_commerce_get_invoice_url', [$this, 'ajax_get_invoice_url']);
    }

    /**
     * Create a new order from cart data
     */
    public function create_order($customer_data, $cart_items, $order_notes = '') {
        global $wpdb;
        
        // Validate customer data
        if (empty($customer_data['email']) || empty($customer_data['first_name']) || empty($customer_data['last_name'])) {
            return new WP_Error('missing_data', 'Customer email, first name, and last name are required.');
        }
        
        // Validate cart items
        if (empty($cart_items)) {
            return new WP_Error('empty_cart', 'Cannot create order with empty cart.');
        }
        
        // Calculate order totals
        $subtotal = 0;
        $validated_items = [];
        
        foreach ($cart_items as $item) {
            $product = $wpdb->get_row($wpdb->prepare(
                "SELECT id, name, sku, price, stock, manage_stock, variation_stock_mode FROM {$wpdb->prefix}ggmc_products WHERE id = %d AND status = 'active'",
                $item['product_id']
            ));

            if (!$product) {
                return new WP_Error('invalid_product', 'Product not found: ' . $item['product_id']);
            }

            // Check stock (only if stock management is enabled)
            if (!empty($product->manage_stock) && $product->stock < $item['quantity']) {
                return new WP_Error('insufficient_stock', 'Insufficient stock for: ' . $product->name);
            }

            // Get variation data if present
            $variation_id = isset($item['variation_id']) ? intval($item['variation_id']) : null;
            $variation_data = isset($item['variation_data']) ? $item['variation_data'] : [];

            // Decode JSON if variation_data came as a string (from checkout form)
            if (is_string($variation_data) && !empty($variation_data)) {
                $decoded = json_decode($variation_data, true);
                if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                    $variation_data = $decoded;
                }
            }

            $variation_display = '';
            $item_price = $product->price;
            $item_sku = $product->sku;

            // Check for Independent mode
            $is_independent = isset($variation_data['variation_mode']) && 'independent' === $variation_data['variation_mode'];

            if ($is_independent && class_exists('GGM_Commerce_Variations')) {
                // Independent mode: use calculated price and format options
                $variations_manager = GGM_Commerce_Variations::instance();

                // Use pre-calculated price from cart
                if (isset($variation_data['calculated_price'])) {
                    $item_price = floatval($variation_data['calculated_price']);
                }

                // Format selected options for display
                if (!empty($variation_data['attributes'])) {
                    $variation_display = $variations_manager->format_selected_options(
                        $product->id,
                        $variation_data['attributes']
                    );

                    // Fallback: if format_selected_options returns empty, build simple display
                    if (empty($variation_display)) {
                        $attr_parts = [];
                        foreach ($variation_data['attributes'] as $attr_id => $value) {
                            $attr_parts[] = $value;
                        }
                        $variation_display = implode(', ', $attr_parts);
                    }
                }

                // Independent mode doesn't have variation_id
                $variation_id = null;
            } elseif ($variation_id && class_exists('GGM_Commerce_Variations')) {
                // Combined mode: use variation-specific data
                $variations_manager = GGM_Commerce_Variations::instance();
                $variation = $variations_manager->get_variation($variation_id);

                if ($variation) {
                    // Use variation price if set
                    $variation_price = $variations_manager->get_variation_price($variation_id);
                    if ($variation_price !== null) {
                        $item_price = $variation_price;
                    }

                    // Use variation SKU if set
                    if (!empty($variation['sku'])) {
                        $item_sku = $variation['sku'];
                    }

                    // Build variation attributes display string
                    // Note: attributes array contains 'attribute_name' and 'attribute_value' keys from DB
                    if (!empty($variation['attributes'])) {
                        $attr_parts = [];
                        foreach ($variation['attributes'] as $attr) {
                            $attr_name = $attr['attribute_name'] ?? $attr['name'] ?? '';
                            $attr_value = $attr['attribute_value'] ?? $attr['value'] ?? '';
                            if (!empty($attr_name) && !empty($attr_value)) {
                                $attr_parts[] = $attr_name . ': ' . $attr_value;
                            }
                        }
                        if (!empty($attr_parts)) {
                            $variation_display = implode(', ', $attr_parts);
                        }
                    }
                }
            }

            $item_total = $item_price * $item['quantity'];
            $subtotal += $item_total;

            $validated_items[] = [
                'product_id' => $product->id,
                'product_name' => $product->name,
                'product_sku' => $item_sku,
                'quantity' => $item['quantity'],
                'price' => $item_price,
                'total' => $item_total,
                'variation_id' => $variation_id,
                'variation_data' => $variation_display,
                'manage_stock' => !empty($product->manage_stock),
                'variation_stock_mode' => $product->variation_stock_mode ?? 'parent',
            ];
        }
        
        // Calculate tax using Tax class with exemption support
        $tax = ggm_commerce_tax();

        // Check for B2B exemption from customer data or session
        $is_business = !empty($customer_data['is_business']);
        $customer_tax_id = isset($customer_data['tax_id']) ? sanitize_text_field($customer_data['tax_id']) : '';

        // Determine if this order is tax exempt
        $is_tax_exempt = false;
        if ($tax->is_b2b_enabled() && $is_business && !empty($customer_tax_id)) {
            // If validation is not required, auto-approve
            if (!$tax->is_b2b_validation_required()) {
                $is_tax_exempt = true;
            }
            // If validation is required, exemption needs admin approval (future feature)
            // For now, still mark as exempt if tax ID provided
            $is_tax_exempt = true;
        }

        // Use exemption-aware calculation
        if ($is_tax_exempt) {
            $tax->set_session_tax_exempt(true, $customer_tax_id);
        }
        $tax_calc = $tax->calculate_with_exemption($subtotal);
        $tax_rate = $is_tax_exempt ? 0 : $tax->get_rate_percentage();
        $tax_label = $tax->get_label();
        $tax_amount = $tax_calc['tax'];
        $prices_include_tax = $tax->prices_include_tax();

        // Clear session exemption after using it
        $tax->clear_session_tax_exempt();

        // Shipping calculation
        $shipping_amount = 0;
        $shipping_method_id = null;
        $shipping_method_name = '';
        $shipping_method_type = '';
        $shipping_zone_id = null;

        // Check if shipping is enabled and calculate
        if (function_exists('ggm_commerce_shipping')) {
            $shipping = ggm_commerce_shipping();

            if ($shipping->is_enabled()) {
                // Build destination from customer data
                $destination = [
                    'country' => $customer_data['shipping_country'] ?? $customer_data['billing_country'] ?? '',
                    'state' => $customer_data['shipping_state'] ?? $customer_data['billing_state'] ?? '',
                    'postcode' => $customer_data['shipping_postcode'] ?? $customer_data['billing_postcode'] ?? '',
                ];

                // Build cart items for shipping calculation
                $shipping_cart_items = [];
                foreach ($validated_items as $item) {
                    // Get product weight
                    $product_details = $wpdb->get_row($wpdb->prepare(
                        "SELECT weight FROM {$wpdb->prefix}ggmc_products WHERE id = %d",
                        $item['product_id']
                    ));
                    $shipping_cart_items[] = [
                        'product_id' => $item['product_id'],
                        'quantity' => $item['quantity'],
                        'weight' => floatval($product_details->weight ?? 0),
                        'price' => floatval($item['price']),
                        'line_total' => $item['total'],
                    ];
                }

                // Calculate shipping
                $shipping_result = $shipping->calculate_shipping($shipping_cart_items, $destination);

                if ($shipping_result && isset($shipping_result['shipping_cost'])) {
                    $shipping_amount = $shipping_result['shipping_cost'] ?? 0;
                    $selected_method = $shipping_result['selected_method'] ?? null;
                    $shipping_method_id = $selected_method ? $selected_method->id : null;
                    $shipping_method_name = $selected_method ? $selected_method->name : '';
                    $shipping_method_type = $selected_method ? ($selected_method->method_type ?? 'flat_rate') : 'flat_rate';
                    $shipping_zone_id = isset($shipping_result['zone']) && $shipping_result['zone'] ? $shipping_result['zone']->id : null;
                }
            }
        }

        // Fallback: Use basic shipping settings when premium is not active
        if ($shipping_method_id === null) {
            $basic_options = get_option('ggm_commerce_basic_shipping', []);
            $flat_rate = isset($basic_options['flat_rate']) ? floatval($basic_options['flat_rate']) : 5.99;
            $free_threshold = isset($basic_options['free_threshold']) ? floatval($basic_options['free_threshold']) : 50;
            $label = isset($basic_options['label']) && !empty($basic_options['label']) ? $basic_options['label'] : __('Shipping', 'ggm-commerce');

            // Free shipping if subtotal meets threshold (0 = disabled)
            if ($free_threshold > 0 && $subtotal >= $free_threshold) {
                $shipping_amount = 0;
                $shipping_method_name = __('Free Shipping', 'ggm-commerce');
            } else {
                $shipping_amount = $flat_rate;
                $shipping_method_name = $label;
            }
            $shipping_method_type = 'flat_rate';
        }

        // Process discount if applied
        $discount_code = '';
        $discount_id = null;
        $discount_amount = 0;
        $discount_type = '';

        if ( class_exists( 'GGM_Commerce_Discounts' ) && GGM_Commerce_Discounts::is_activated() ) {
            $discounts_handler = GGM_Commerce_Discounts::get_instance();
            $applied_discount = $discounts_handler->get_applied_discount();

            if ( $applied_discount ) {
                $customer_email = sanitize_email( $customer_data['email'] );

                // Validate discount is still valid
                $validation = $discounts_handler->validate_discount_code(
                    $applied_discount->code,
                    $subtotal,
                    $customer_email
                );

                if ( $validation['valid'] ) {
                    $discount_code = $applied_discount->code;
                    $discount_id = $applied_discount->id;
                    $discount_amount = $validation['discount_amount'];
                    $discount_type = $applied_discount->discount_type;
                }
            }
        }

        // Calculate total
        if ($prices_include_tax && !$is_tax_exempt) {
            // Prices already include tax, just add shipping, subtract discount
            $total_amount = $subtotal + $shipping_amount - $discount_amount;
        } else if ($is_tax_exempt) {
            // Tax exempt - use net price + shipping, subtract discount
            $total_amount = $tax_calc['net'] + $shipping_amount - $discount_amount;
        } else {
            // Add tax and shipping to subtotal, subtract discount
            $total_amount = $subtotal + $tax_amount + $shipping_amount - $discount_amount;
        }

        // Ensure total is not negative
        $total_amount = max( 0, $total_amount );

        // Generate order number
        $order_number = $this->generate_order_number();
        
        // Start transaction
        $wpdb->query('START TRANSACTION');
        
        try {
            // Create order
            $order_data = [
                'order_number' => $order_number,
                'user_id' => is_user_logged_in() ? get_current_user_id() : 0,
                'customer_email' => sanitize_email($customer_data['email']),
                'customer_first_name' => sanitize_text_field($customer_data['first_name']),
                'customer_last_name' => sanitize_text_field($customer_data['last_name']),
                'customer_phone' => sanitize_text_field($customer_data['phone'] ?? ''),
                'billing_address_1' => sanitize_text_field($customer_data['billing_address_1'] ?? ''),
                'billing_address_2' => sanitize_text_field($customer_data['billing_address_2'] ?? ''),
                'billing_city' => sanitize_text_field($customer_data['billing_city'] ?? ''),
                'billing_state' => sanitize_text_field($customer_data['billing_state'] ?? ''),
                'billing_country' => sanitize_text_field($customer_data['billing_country'] ?? ''),
                'billing_postcode' => sanitize_text_field($customer_data['billing_postcode'] ?? ''),
                'shipping_address_1' => sanitize_text_field($customer_data['shipping_address_1'] ?? $customer_data['billing_address_1'] ?? ''),
                'shipping_address_2' => sanitize_text_field($customer_data['shipping_address_2'] ?? $customer_data['billing_address_2'] ?? ''),
                'shipping_city' => sanitize_text_field($customer_data['shipping_city'] ?? $customer_data['billing_city'] ?? ''),
                'shipping_state' => sanitize_text_field($customer_data['shipping_state'] ?? $customer_data['billing_state'] ?? ''),
                'shipping_country' => sanitize_text_field($customer_data['shipping_country'] ?? $customer_data['billing_country'] ?? ''),
                'shipping_postcode' => sanitize_text_field($customer_data['shipping_postcode'] ?? $customer_data['billing_postcode'] ?? ''),
                'subtotal' => $subtotal,
                'tax_amount' => $tax_amount,
                'tax_rate' => $tax_rate,
                'tax_label' => $tax_label,
                'prices_include_tax' => $prices_include_tax ? 1 : 0,
                'shipping_amount' => $shipping_amount,
                'shipping_method_id' => $shipping_method_id,
                'shipping_method_name' => $shipping_method_name,
                'shipping_method_type' => $shipping_method_type,
                'shipping_zone_id' => $shipping_zone_id,
                'shipping_calculated_at' => current_time('mysql'),
                'total_amount' => $total_amount,
                'is_tax_exempt' => $is_tax_exempt ? 1 : 0,
                'customer_tax_id' => $customer_tax_id,
                'discount_code' => $discount_code,
                'discount_id' => $discount_id,
                'discount_amount' => $discount_amount,
                'discount_type' => $discount_type,
                'status' => 'pending',
                'payment_status' => 'pending',
                'notes' => sanitize_textarea_field($order_notes),
                'created_at' => current_time('mysql'),
                'updated_at' => current_time('mysql')
            ];
            
            $order_inserted = $wpdb->insert("{$wpdb->prefix}ggmc_orders", $order_data);
            
            if (!$order_inserted) {
                throw new Exception('Failed to create order');
            }
            
            $order_id = $wpdb->insert_id;

            // Create order items
            foreach ($validated_items as $item) {
                // Get product virtual/downloadable settings
                $requires_shipping = 1;
                $is_downloadable = 0;

                if (class_exists('GGM_Commerce_Virtual_Products')) {
                    $virtual_helper = GGM_Commerce_Virtual_Products::instance();
                    $product_settings = $virtual_helper->get_product_settings($item['product_id']);
                    $requires_shipping = $product_settings['requires_shipping'] ? 1 : 0;
                    $is_downloadable = $product_settings['is_downloadable'] ? 1 : 0;
                }

                $item_data = array_merge($item, [
                    'order_id' => $order_id,
                    'requires_shipping' => $requires_shipping,
                    'is_downloadable' => $is_downloadable,
                    'created_at' => current_time('mysql')
                ]);

                // Remove keys that are not columns in the order_items table.
                unset( $item_data['manage_stock'], $item_data['variation_stock_mode'] );

                $item_inserted = $wpdb->insert("{$wpdb->prefix}ggmc_order_items", $item_data);

                if (!$item_inserted) {
                    throw new Exception('Failed to create order item for product: ' . $item['product_name']);
                }

                // Update product stock (only if stock management is enabled)
                if (!empty($item['manage_stock'])) {
                    // Get current stock before deduction
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    $current_stock = (int) $wpdb->get_var($wpdb->prepare(
                        "SELECT stock FROM {$wpdb->prefix}ggmc_products WHERE id = %d",
                        $item['product_id']
                    ));
                    $new_stock = max(0, $current_stock - $item['quantity']);

                    // Deduct parent product stock and sync stock_status
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    $wpdb->update(
                        "{$wpdb->prefix}ggmc_products",
                        [
                            'stock' => $new_stock,
                            'stock_status' => $new_stock > 0 ? 'instock' : 'outofstock',
                            'updated_at' => current_time('mysql'),
                        ],
                        ['id' => $item['product_id']],
                        ['%d', '%s', '%s'],
                        ['%d']
                    );

                    // Log stock movement
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
                    $wpdb->insert(
                        "{$wpdb->prefix}ggmc_stock_movements",
                        [
                            'product_id' => $item['product_id'],
                            'quantity_change' => -$item['quantity'],
                            'previous_stock' => $current_stock,
                            'new_stock' => $new_stock,
                            'movement_type' => 'order',
                            'reference_id' => $order_id,
                            'notes' => sprintf('Order #%d: %d x %s', $order_id, $item['quantity'], $item['product_name']),
                            'user_id' => get_current_user_id(),
                            'created_at' => current_time('mysql'),
                        ],
                        ['%d', '%d', '%d', '%d', '%s', '%d', '%s', '%d', '%s']
                    );

                    // Handle variation-level stock deduction
                    if (!empty($item['variation_id']) && $item['variation_stock_mode'] === 'variation' && class_exists('GGM_Commerce_Variations')) {
                        $variations_manager = GGM_Commerce_Variations::instance();
                        $variations_manager->update_variation_stock($item['variation_id'], -$item['quantity']);
                    }
                }
            }
            
            // Create or update customer record
            $customer_id = $this->create_or_update_customer($customer_data, $total_amount);

            // Save addresses to customer_addresses table
            if ($customer_id) {
                $this->save_customer_addresses($customer_id, $customer_data);
            }

            // Commit transaction
            $wpdb->query('COMMIT');

            // Create subscriptions for subscription items.
            if ( class_exists( 'GGM_Commerce_Subscriptions' ) && GGM_Commerce_Subscriptions::is_activated() ) {
                $sub_manager = GGM_Commerce_Subscriptions::instance();

                foreach ( $validated_items as $item ) {
                    if ( $sub_manager->is_product_subscription( $item['product_id'] ) ) {
                        $sub_data = $sub_manager->get_product_subscription_data( $item['product_id'] );

                        $sub_args = array(
                            'customer_id'      => $customer_id ?: 0,
                            'customer_email'    => sanitize_email( $customer_data['email'] ),
                            'parent_order_id'   => $order_id,
                            'product_id'        => $item['product_id'],
                            'variation_id'      => $item['variation_id'] ?? 0,
                            'quantity'          => $item['quantity'],
                            'billing_interval'  => $sub_data['subscription_interval'] ?? 1,
                            'billing_period'    => $sub_data['subscription_period'] ?? 'month',
                            'recurring_amount'  => $item['price'],
                            'recurring_total'   => $item['total'],
                            'currency'          => get_option( 'ggm_commerce_currency', 'USD' ),
                            'trial_length'      => $sub_data['subscription_trial_length'] ?? 0,
                            'trial_period'      => $sub_data['subscription_trial_period'] ?? 'day',
                            'status'            => ! empty( $sub_data['subscription_trial_length'] ) ? 'trial' : 'pending',
                        );

                        $subscription_id = $sub_manager->create_subscription( $sub_args );

                        if ( $subscription_id ) {
                            // Link order to subscription.
                            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                            $wpdb->update(
                                "{$wpdb->prefix}ggmc_orders",
                                array( 'subscription_id' => $subscription_id ),
                                array( 'id' => $order_id )
                            );

                            // Add subscription line item.
                            $sub_manager->add_subscription_item( $subscription_id, array(
                                'product_id'      => $item['product_id'],
                                'product_name'    => $item['product_name'],
                                'product_sku'     => $item['product_sku'] ?? '',
                                'variation_id'    => $item['variation_id'] ?? 0,
                                'variation_data'  => is_array( $item['variation_data'] ?? null ) ? wp_json_encode( $item['variation_data'] ) : ( $item['variation_data'] ?? '' ),
                                'quantity'        => $item['quantity'],
                                'recurring_price' => $item['price'],
                                'recurring_total' => $item['total'],
                            ) );
                        }
                    }
                }
            }

            // Auto-complete free orders (no payment required).
            if ( (float) $total_amount === 0.0 ) {
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                $wpdb->update(
                    "{$wpdb->prefix}ggmc_orders",
                    array(
                        'status'         => 'completed',
                        'payment_status' => 'paid',
                        'payment_method' => 'free',
                        'updated_at'     => current_time( 'mysql' ),
                    ),
                    array( 'id' => $order_id )
                );

                // Fire status hooks so downloads, emails, etc. trigger.
                do_action( 'ggm_commerce_order_status_changed', $order_id, 'completed', 'paid' );
                do_action( 'ggmc_order_status_completed', $order_id );

                // Activate any subscriptions linked to this free order.
                if ( class_exists( 'GGM_Commerce_Subscriptions' ) && GGM_Commerce_Subscriptions::is_activated() ) {
                    $sub_manager = GGM_Commerce_Subscriptions::instance();
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    $linked_subs = $wpdb->get_results( $wpdb->prepare(
                        "SELECT id, status FROM {$wpdb->prefix}ggmc_subscriptions WHERE parent_order_id = %d",
                        $order_id
                    ) );

                    foreach ( $linked_subs as $sub ) {
                        if ( in_array( $sub->status, array( 'pending', 'trial' ), true ) ) {
                            $sub_manager->activate_subscription( $sub->id );
                        }
                    }
                }
            }

            // Record discount usage after successful order creation
            if ( $discount_id && $discount_amount > 0 && class_exists( 'GGM_Commerce_Discounts' ) ) {
                $discounts_handler = GGM_Commerce_Discounts::get_instance();
                $discounts_handler->record_usage(
                    $discount_id,
                    $order_id,
                    $discount_amount,
                    [
                        'customer_id' => $customer_id,
                        'email'       => sanitize_email( $customer_data['email'] ),
                    ]
                );

                // Remove discount from cart session
                $discounts_handler->remove_discount_from_cart( session_id() );
            }

            // Clear cart
            if (class_exists('GGM_Commerce_Cart')) {
                GGM_Commerce_Cart::get_instance()->clear_cart();
            }

            return [
                'order_id' => $order_id,
                'order_number' => $order_number,
                'total' => $total_amount,
                'status' => (float) $total_amount === 0.0 ? 'completed' : 'pending',
            ];
            
        } catch (Exception $e) {
            $wpdb->query('ROLLBACK');
            return new WP_Error('order_creation_failed', $e->getMessage());
        }
    }
    
    /**
     * Get order by ID or order number
     */
    public function get_order($identifier, $by_number = false) {
        global $wpdb;
        
        if ($by_number) {
            $order = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_orders WHERE order_number = %s",
                $identifier
            ));
        } else {
            $order = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_orders WHERE id = %d",
                $identifier
            ));
        }

        if (!$order) {
            return null;
        }

        // Get order items
        $order_items = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}ggmc_order_items WHERE order_id = %d ORDER BY id",
            $order->id
        ));
        
        $order->items = $order_items;
        return $order;
    }
    
    /**
     * Get orders for a customer
     */
    public function get_customer_orders($customer_email, $limit = 10, $offset = 0) {
        global $wpdb;
        
        $orders = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}ggmc_orders
             WHERE customer_email = %s
             ORDER BY created_at DESC
             LIMIT %d OFFSET %d",
            $customer_email,
            $limit,
            $offset
        ));

        // Get items for each order
        foreach ($orders as $order) {
            $order->items = $wpdb->get_results($wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_order_items WHERE order_id = %d ORDER BY id",
                $order->id
            ));
        }
        
        return $orders;
    }
    
    /**
     * Update order status
     */
    public function update_order_status($order_id, $status, $payment_status = null) {
        global $wpdb;
        
        $update_data = [
            'status' => $status,
            'updated_at' => current_time('mysql')
        ];
        
        if ($payment_status !== null) {
            $update_data['payment_status'] = $payment_status;
        }
        
        $updated = $wpdb->update(
            "{$wpdb->prefix}ggmc_orders",
            $update_data,
            ['id' => $order_id]
        );

        if ($updated !== false) {
            // Fire general status change hook
            do_action('ggm_commerce_order_status_changed', $order_id, $status, $payment_status);

            // Fire specific status hooks for downloads/virtual products
            do_action('ggmc_order_status_' . $status, $order_id);

            // Activate pending subscriptions when order is completed.
            if ( 'completed' === $status && class_exists( 'GGM_Commerce_Subscriptions' ) && GGM_Commerce_Subscriptions::is_activated() ) {
                $sub_manager = GGM_Commerce_Subscriptions::instance();
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                $linked_subs = $wpdb->get_results( $wpdb->prepare(
                    "SELECT id, status FROM {$wpdb->prefix}ggmc_subscriptions WHERE parent_order_id = %d",
                    $order_id
                ) );

                foreach ( $linked_subs as $sub ) {
                    if ( in_array( $sub->status, array( 'pending', 'trial' ), true ) ) {
                        $sub_manager->activate_subscription( $sub->id );
                    }
                }
            }

            return true;
        }

        return false;
    }
    
    /**
     * Generate unique order number
     */
    private function generate_order_number() {
        global $wpdb;
        
        do {
            $order_number = 'GGMC-' . gmdate('Y') . '-' . str_pad(wp_rand(1, 999999), 6, '0', STR_PAD_LEFT);
            $exists = $wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_orders WHERE order_number = %s",
                $order_number
            ));
        } while ($exists > 0);
        
        return $order_number;
    }
    
    /**
     * Create or update customer record
     * Returns customer ID
     */
    private function create_or_update_customer($customer_data, $order_total) {
        global $wpdb;

        $customer_email = sanitize_email($customer_data['email']);
        $is_business = !empty($customer_data['is_business']);
        $customer_tax_id = isset($customer_data['tax_id']) ? sanitize_text_field($customer_data['tax_id']) : '';

        // Check if customer exists
        $existing_customer = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}ggmc_customers WHERE email = %s",
            $customer_email
        ));

        if ($existing_customer) {
            // Build update data
            $update_data = [
                'first_name' => sanitize_text_field($customer_data['first_name']),
                'last_name' => sanitize_text_field($customer_data['last_name']),
                'phone' => sanitize_text_field($customer_data['phone'] ?? ''),
                'company' => sanitize_text_field($customer_data['billing_company'] ?? ''),
                'total_orders' => $existing_customer->total_orders + 1,
                'total_spent' => $existing_customer->total_spent + $order_total,
                'last_order_date' => current_time('mysql'),
                'updated_at' => current_time('mysql')
            ];

            // Update B2B fields if provided
            if ($is_business && !empty($customer_tax_id)) {
                $update_data['tax_id'] = $customer_tax_id;
                // Only set to pending if not already approved
                if ($existing_customer->tax_exempt_status !== 'approved') {
                    $update_data['tax_exempt_status'] = 'pending';
                }
            }

            $wpdb->update(
                "{$wpdb->prefix}ggmc_customers",
                $update_data,
                ['id' => $existing_customer->id]
            );
            return $existing_customer->id;
        } else {
            // Build insert data
            $insert_data = [
                'user_id' => is_user_logged_in() ? get_current_user_id() : 0,
                'email' => $customer_email,
                'first_name' => sanitize_text_field($customer_data['first_name']),
                'last_name' => sanitize_text_field($customer_data['last_name']),
                'phone' => sanitize_text_field($customer_data['phone'] ?? ''),
                'company' => sanitize_text_field($customer_data['billing_company'] ?? ''),
                'total_orders' => 1,
                'total_spent' => $order_total,
                'last_order_date' => current_time('mysql'),
                'created_at' => current_time('mysql'),
                'updated_at' => current_time('mysql')
            ];

            // Add B2B fields if provided
            if ($is_business && !empty($customer_tax_id)) {
                $insert_data['tax_id'] = $customer_tax_id;
                $insert_data['tax_exempt_status'] = 'pending';
            }

            $wpdb->insert(
                "{$wpdb->prefix}ggmc_customers",
                $insert_data
            );
            return $wpdb->insert_id;
        }
    }

    /**
     * Save customer addresses to customer_addresses table
     */
    private function save_customer_addresses($customer_id, $customer_data) {
        global $wpdb;

        // Save billing address
        if (!empty($customer_data['billing_address_1'])) {
            // Check if this exact address already exists
            $existing_billing = $wpdb->get_var($wpdb->prepare(
                "SELECT id FROM {$wpdb->prefix}ggmc_customer_addresses
                 WHERE customer_id = %d
                 AND address_type = 'billing'
                 AND address_1 = %s
                 AND city = %s
                 AND postcode = %s",
                $customer_id,
                $customer_data['billing_address_1'],
                $customer_data['billing_city'] ?? '',
                $customer_data['billing_postcode'] ?? ''
            ));

            if (!$existing_billing) {
                // Set all other billing addresses as non-default
                $wpdb->update(
                    "{$wpdb->prefix}ggmc_customer_addresses",
                    ['is_default' => 0],
                    ['customer_id' => $customer_id, 'address_type' => 'billing']
                );

                // Insert new billing address as default
                $wpdb->insert(
                    "{$wpdb->prefix}ggmc_customer_addresses",
                    [
                        'customer_id' => $customer_id,
                        'address_type' => 'billing',
                        'is_default' => 1,
                        'first_name' => sanitize_text_field($customer_data['first_name']),
                        'last_name' => sanitize_text_field($customer_data['last_name']),
                        'company' => sanitize_text_field($customer_data['billing_company'] ?? ''),
                        'address_1' => sanitize_text_field($customer_data['billing_address_1']),
                        'address_2' => sanitize_text_field($customer_data['billing_address_2'] ?? ''),
                        'city' => sanitize_text_field($customer_data['billing_city'] ?? ''),
                        'state' => sanitize_text_field($customer_data['billing_state'] ?? ''),
                        'postcode' => sanitize_text_field($customer_data['billing_postcode'] ?? ''),
                        'country' => sanitize_text_field($customer_data['billing_country'] ?? ''),
                        'phone' => sanitize_text_field($customer_data['phone'] ?? ''),
                        'created_at' => current_time('mysql'),
                        'updated_at' => current_time('mysql')
                    ]
                );
            }
        }

        // Save shipping address (if different from billing)
        $shipping_addr_1 = $customer_data['shipping_address_1'] ?? $customer_data['billing_address_1'] ?? '';
        if (!empty($shipping_addr_1)) {
            $shipping_city = $customer_data['shipping_city'] ?? $customer_data['billing_city'] ?? '';
            $shipping_postcode = $customer_data['shipping_postcode'] ?? $customer_data['billing_postcode'] ?? '';

            // Check if this exact address already exists
            $existing_shipping = $wpdb->get_var($wpdb->prepare(
                "SELECT id FROM {$wpdb->prefix}ggmc_customer_addresses
                 WHERE customer_id = %d
                 AND address_type = 'shipping'
                 AND address_1 = %s
                 AND city = %s
                 AND postcode = %s",
                $customer_id,
                $shipping_addr_1,
                $shipping_city,
                $shipping_postcode
            ));

            if (!$existing_shipping) {
                // Set all other shipping addresses as non-default
                $wpdb->update(
                    "{$wpdb->prefix}ggmc_customer_addresses",
                    ['is_default' => 0],
                    ['customer_id' => $customer_id, 'address_type' => 'shipping']
                );

                // Insert new shipping address as default
                $wpdb->insert(
                    "{$wpdb->prefix}ggmc_customer_addresses",
                    [
                        'customer_id' => $customer_id,
                        'address_type' => 'shipping',
                        'is_default' => 1,
                        'first_name' => sanitize_text_field($customer_data['first_name']),
                        'last_name' => sanitize_text_field($customer_data['last_name']),
                        'company' => sanitize_text_field($customer_data['shipping_company'] ?? $customer_data['billing_company'] ?? ''),
                        'address_1' => sanitize_text_field($shipping_addr_1),
                        'address_2' => sanitize_text_field($customer_data['shipping_address_2'] ?? $customer_data['billing_address_2'] ?? ''),
                        'city' => sanitize_text_field($shipping_city),
                        'state' => sanitize_text_field($customer_data['shipping_state'] ?? $customer_data['billing_state'] ?? ''),
                        'postcode' => sanitize_text_field($shipping_postcode),
                        'country' => sanitize_text_field($customer_data['shipping_country'] ?? $customer_data['billing_country'] ?? ''),
                        'phone' => sanitize_text_field($customer_data['phone'] ?? ''),
                        'created_at' => current_time('mysql'),
                        'updated_at' => current_time('mysql')
                    ]
                );
            }
        }
    }
    
    // AJAX Handlers
    public function ajax_create_order() {
        check_ajax_referer('ggm_commerce_checkout', 'nonce');

        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- JSON data validated after decoding
        $customer_data = isset($_POST['customer']) ? wp_unslash($_POST['customer']) : [];
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- JSON data validated after decoding
        $cart_items = isset($_POST['cart_items']) ? wp_unslash($_POST['cart_items']) : [];
        $order_notes = isset($_POST['notes']) ? sanitize_textarea_field(wp_unslash($_POST['notes'])) : '';
        
        $result = $this->create_order($customer_data, $cart_items, $order_notes);

        if (is_wp_error($result)) {
            wp_send_json_error(['message' => $result->get_error_message()]);
        } else {
            // Save custom checkout field values if premium component is activated.
            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Values sanitized in manager class.
            $custom_fields = isset($_POST['custom_fields']) ? wp_unslash($_POST['custom_fields']) : array();
            if ( ! empty( $custom_fields ) && is_array( $custom_fields )
                && class_exists( 'GGM_Commerce_Checkout_Fields' )
                && function_exists( 'ggm_commerce_license' )
                && ggm_commerce_license()->is_widget_activated( 'checkout-fields' )
            ) {
                $cf_manager  = GGM_Commerce_Checkout_Fields::get_instance();
                $validation  = $cf_manager->validate_field_values( $custom_fields );

                if ( $validation['valid'] ) {
                    $cf_manager->save_order_field_values( $result['order_id'], $custom_fields );
                }
                // Note: validation errors are non-blocking for the order itself.
                // Required field validation is enforced client-side via HTML required attribute.
            }

            // Generate confirmation URL using the helper (doesn't depend on Elementor widgets)
            $confirmation_url = '';
            $full_order = $this->get_order($result['order_id']);
            if ($full_order) {
                $confirmation_url = GGM_Commerce_Helpers::get_order_confirmation_url($full_order);
            }

            wp_send_json_success([
                'message' => 'Order created successfully!',
                'order' => $result,
                'confirmation_url' => $confirmation_url
            ]);
        }
    }
    
    public function ajax_get_order() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified earlier in request
        $order_id = isset($_POST['order_id']) ? intval(wp_unslash($_POST['order_id'])) : 0;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified earlier in request
        $order_number = isset($_POST['order_number']) ? sanitize_text_field(wp_unslash($_POST['order_number'])) : '';
        
        if ($order_id) {
            $order = $this->get_order($order_id);
        } elseif ($order_number) {
            $order = $this->get_order($order_number, true);
        } else {
            wp_send_json_error(['message' => 'Order ID or order number required']);
        }
        
        if ($order) {
            wp_send_json_success(['order' => $order]);
        } else {
            wp_send_json_error(['message' => 'Order not found']);
        }
    }
    
    public function ajax_get_customer_orders() {
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified earlier in request
        $customer_email = isset($_POST['email']) ? sanitize_email(wp_unslash($_POST['email'])) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified earlier in request
        $limit = isset($_POST['limit']) ? intval(wp_unslash($_POST['limit'])) : 10;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified earlier in request
        $offset = isset($_POST['offset']) ? intval(wp_unslash($_POST['offset'])) : 0;
        
        if (!$customer_email) {
            wp_send_json_error(['message' => 'Customer email required']);
        }
        
        $orders = $this->get_customer_orders($customer_email, $limit, $offset);
        wp_send_json_success(['orders' => $orders]);
    }
    
    public function ajax_update_order_status() {
        check_ajax_referer('ggm_commerce_admin', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'Insufficient permissions']);
        }

        $order_id = isset($_POST['order_id']) ? intval(wp_unslash($_POST['order_id'])) : 0;
        $status = isset($_POST['status']) ? sanitize_text_field(wp_unslash($_POST['status'])) : '';
        $payment_status = isset($_POST['payment_status']) ? sanitize_text_field(wp_unslash($_POST['payment_status'])) : null;
        
        if (!$order_id || !$status) {
            wp_send_json_error(['message' => 'Order ID and status required']);
        }
        
        $updated = $this->update_order_status($order_id, $status, $payment_status);

        if ($updated) {
            wp_send_json_success(['message' => 'Order status updated']);
        } else {
            wp_send_json_error(['message' => 'Failed to update order status']);
        }
    }

    /**
     * AJAX handler for getting order details HTML (frontend customer view)
     */
    public function ajax_get_order_details_html() {
        // Verify nonce
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'ggm_commerce_order_nonce')) {
            wp_send_json_error(['message' => 'Security check failed']);
        }

        // Must be logged in
        if (!is_user_logged_in()) {
            wp_send_json_error(['message' => 'Please log in to view order details']);
        }

        $order_id = isset($_POST['order_id']) ? intval(wp_unslash($_POST['order_id'])) : 0;

        if (!$order_id) {
            wp_send_json_error(['message' => 'Order ID required']);
        }

        $order = $this->get_order($order_id);

        if (!$order) {
            wp_send_json_error(['message' => 'Order not found']);
        }

        // Security: Verify the current user owns this order
        $current_user = wp_get_current_user();
        $user_email = $current_user->user_email;
        $user_id = $current_user->ID;

        // Check if order belongs to this user (by user_id or email)
        $order_user_id = isset($order->user_id) ? (int) $order->user_id : 0;
        $order_email = isset($order->customer_email) ? $order->customer_email : '';

        if ($order_user_id !== $user_id && strtolower($order_email) !== strtolower($user_email)) {
            wp_send_json_error(['message' => 'You do not have permission to view this order']);
        }

        // Generate HTML
        $html = $this->render_order_details_html($order);

        wp_send_json_success(['html' => $html, 'order' => $order]);
    }

    /**
     * Render order details HTML for frontend display
     */
    private function render_order_details_html($order) {
        $currency_options = get_option('ggm_commerce_currency_options', array());
        $currency_symbol = isset($currency_options['symbol']) ? $currency_options['symbol'] : '£';
        $date_format = get_option('date_format', 'F j, Y');
        $time_format = get_option('time_format', 'g:i a');

        // Format statuses
        $status_labels = [
            'pending' => __('Pending', 'ggm-commerce'),
            'processing' => __('Processing', 'ggm-commerce'),
            'shipped' => __('Shipped', 'ggm-commerce'),
            'delivered' => __('Delivered', 'ggm-commerce'),
            'completed' => __('Completed', 'ggm-commerce'),
            'cancelled' => __('Cancelled', 'ggm-commerce'),
            'refunded' => __('Refunded', 'ggm-commerce'),
        ];

        $payment_status_labels = [
            'pending' => __('Pending', 'ggm-commerce'),
            'paid' => __('Paid', 'ggm-commerce'),
            'failed' => __('Failed', 'ggm-commerce'),
            'refunded' => __('Refunded', 'ggm-commerce'),
        ];

        $order_status = isset($status_labels[$order->status]) ? $status_labels[$order->status] : ucfirst($order->status);
        $payment_status = isset($payment_status_labels[$order->payment_status]) ? $payment_status_labels[$order->payment_status] : ucfirst($order->payment_status ?? 'pending');

        ob_start();
        ?>
        <div class="order-detail-wrapper" data-order-id="<?php echo esc_attr($order->id); ?>">
            <!-- Order Overview -->
            <div class="order-overview">
                <div class="order-overview-header">
                    <h3><?php /* translators: %s: order number */ printf(esc_html__('Order #%s', 'ggm-commerce'), esc_html($order->order_number)); ?></h3>
                    <span class="order-status status-<?php echo esc_attr($order->status); ?>">
                        <?php echo esc_html($order_status); ?>
                    </span>
                </div>
                <div class="order-overview-meta">
                    <div class="meta-item">
                        <span class="meta-label"><?php esc_html_e('Date:', 'ggm-commerce'); ?></span>
                        <span class="meta-value"><?php echo esc_html(gmdate($date_format . ' ' . $time_format, strtotime($order->created_at))); ?></span>
                    </div>
                    <div class="meta-item">
                        <span class="meta-label"><?php esc_html_e('Payment:', 'ggm-commerce'); ?></span>
                        <span class="meta-value payment-status-<?php echo esc_attr($order->payment_status ?? 'pending'); ?>"><?php echo esc_html($payment_status); ?></span>
                    </div>
                    <?php if (!empty($order->payment_method)): ?>
                    <div class="meta-item">
                        <span class="meta-label"><?php esc_html_e('Payment Method:', 'ggm-commerce'); ?></span>
                        <span class="meta-value"><?php echo esc_html(ucfirst(str_replace('_', ' ', $order->payment_method))); ?></span>
                    </div>
                    <?php endif; ?>
                </div>
            </div>

            <!-- Order Items -->
            <div class="order-items-section">
                <h4><?php esc_html_e('Order Items', 'ggm-commerce'); ?></h4>
                <div class="order-items-table-wrapper">
                    <table class="order-items-table">
                        <thead>
                            <tr>
                                <th class="item-product"><?php esc_html_e('Product', 'ggm-commerce'); ?></th>
                                <th class="item-qty"><?php esc_html_e('Qty', 'ggm-commerce'); ?></th>
                                <th class="item-price"><?php esc_html_e('Price', 'ggm-commerce'); ?></th>
                                <th class="item-total"><?php esc_html_e('Total', 'ggm-commerce'); ?></th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php if (!empty($order->items)): ?>
                                <?php foreach ($order->items as $item): ?>
                                    <?php
                                    $product_url = '';
                                    if (!empty($item->product_id)) {
                                        $product_url = \GGM_Commerce_Helpers::get_product_details_url($item->product_id);
                                    }
                                    $item_price = isset($item->price) ? (float) $item->price : 0;
                                    $item_qty = isset($item->quantity) ? (int) $item->quantity : 1;
                                    $item_total = $item_price * $item_qty;

                                    // Get variation display - use stored data or look up from variation_id
                                    $variation_display = '';
                                    if (!empty($item->variation_data)) {
                                        $variation_display = $item->variation_data;
                                    } elseif (!empty($item->variation_id) && class_exists('GGM_Commerce_Variations')) {
                                        // Fallback: look up variation attributes from variation_id
                                        $variations_manager = \GGM_Commerce_Variations::instance();
                                        $variation = $variations_manager->get_variation($item->variation_id);
                                        if ($variation && !empty($variation['attributes'])) {
                                            $attr_parts = [];
                                            foreach ($variation['attributes'] as $attr) {
                                                $attr_name = $attr['attribute_name'] ?? $attr['name'] ?? '';
                                                $attr_value = $attr['attribute_value'] ?? $attr['value'] ?? '';
                                                if (!empty($attr_name) && !empty($attr_value)) {
                                                    $attr_parts[] = $attr_name . ': ' . $attr_value;
                                                }
                                            }
                                            if (!empty($attr_parts)) {
                                                $variation_display = implode(', ', $attr_parts);
                                            }
                                        }
                                    }
                                    ?>
                                    <tr>
                                        <td class="item-product">
                                            <?php if ($product_url): ?>
                                                <a href="<?php echo esc_url($product_url); ?>" class="product-link">
                                                    <?php echo esc_html($item->product_name ?? __('Unknown Product', 'ggm-commerce')); ?>
                                                </a>
                                            <?php else: ?>
                                                <?php echo esc_html($item->product_name ?? __('Unknown Product', 'ggm-commerce')); ?>
                                            <?php endif; ?>
                                            <?php if (!empty($variation_display)): ?>
                                                <span class="item-variation"><?php echo esc_html($variation_display); ?></span>
                                            <?php endif; ?>
                                            <?php if (!empty($item->sku)): ?>
                                                <span class="item-sku"><?php esc_html_e('SKU:', 'ggm-commerce'); ?> <?php echo esc_html($item->sku); ?></span>
                                            <?php endif; ?>
                                        </td>
                                        <td class="item-qty"><?php echo esc_html($item_qty); ?></td>
                                        <td class="item-price"><?php echo esc_html($currency_symbol . number_format($item_price, 2)); ?></td>
                                        <td class="item-total"><?php echo esc_html($currency_symbol . number_format($item_total, 2)); ?></td>
                                    </tr>
                                <?php endforeach; ?>
                            <?php else: ?>
                                <tr>
                                    <td colspan="4"><?php esc_html_e('No items found for this order.', 'ggm-commerce'); ?></td>
                                </tr>
                            <?php endif; ?>
                        </tbody>
                    </table>
                </div>

                <!-- Order Totals -->
                <div class="order-totals">
                    <div class="totals-row">
                        <span class="totals-label"><?php esc_html_e('Subtotal:', 'ggm-commerce'); ?></span>
                        <span class="totals-value"><?php echo esc_html($currency_symbol . number_format((float) ($order->subtotal ?? 0), 2)); ?></span>
                    </div>
                    <?php if (!empty($order->tax_amount) && (float) $order->tax_amount > 0): ?>
                    <div class="totals-row">
                        <span class="totals-label"><?php echo esc_html($order->tax_label ?? __('Tax', 'ggm-commerce')); ?>:</span>
                        <span class="totals-value"><?php echo esc_html($currency_symbol . number_format((float) $order->tax_amount, 2)); ?></span>
                    </div>
                    <?php endif; ?>
                    <?php if (!empty($order->shipping_amount) || !empty($order->shipping_method_name)): ?>
                    <div class="totals-row">
                        <span class="totals-label">
                            <?php
                            if (!empty($order->shipping_method_name)) {
                                echo esc_html($order->shipping_method_name) . ':';
                            } else {
                                esc_html_e('Shipping:', 'ggm-commerce');
                            }
                            ?>
                        </span>
                        <span class="totals-value">
                            <?php
                            if ((float) $order->shipping_amount > 0) {
                                echo esc_html($currency_symbol . number_format((float) $order->shipping_amount, 2));
                            } else {
                                esc_html_e('Free', 'ggm-commerce');
                            }
                            ?>
                        </span>
                    </div>
                    <?php endif; ?>
                    <div class="totals-row totals-total">
                        <span class="totals-label"><?php esc_html_e('Total:', 'ggm-commerce'); ?></span>
                        <span class="totals-value"><?php echo esc_html($currency_symbol . number_format((float) ($order->total_amount ?? 0), 2)); ?></span>
                    </div>
                </div>
            </div>

            <!-- Addresses -->
            <div class="order-addresses">
                <div class="address-column">
                    <h4><?php esc_html_e('Billing Address', 'ggm-commerce'); ?></h4>
                    <address>
                        <?php echo esc_html($order->customer_first_name . ' ' . $order->customer_last_name); ?><br>
                        <?php if (!empty($order->billing_address_1)): ?>
                            <?php echo esc_html($order->billing_address_1); ?><br>
                        <?php endif; ?>
                        <?php if (!empty($order->billing_address_2)): ?>
                            <?php echo esc_html($order->billing_address_2); ?><br>
                        <?php endif; ?>
                        <?php if (!empty($order->billing_city)): ?>
                            <?php echo esc_html($order->billing_city); ?>
                            <?php if (!empty($order->billing_state)): ?>, <?php echo esc_html($order->billing_state); ?><?php endif; ?>
                            <?php if (!empty($order->billing_postcode)): ?> <?php echo esc_html($order->billing_postcode); ?><?php endif; ?>
                            <br>
                        <?php endif; ?>
                        <?php if (!empty($order->billing_country)): ?>
                            <?php echo esc_html($order->billing_country); ?><br>
                        <?php endif; ?>
                        <?php if (!empty($order->customer_email)): ?>
                            <a href="mailto:<?php echo esc_attr($order->customer_email); ?>"><?php echo esc_html($order->customer_email); ?></a><br>
                        <?php endif; ?>
                        <?php if (!empty($order->customer_phone)): ?>
                            <?php echo esc_html($order->customer_phone); ?>
                        <?php endif; ?>
                    </address>
                </div>
                <div class="address-column">
                    <h4><?php esc_html_e('Shipping Address', 'ggm-commerce'); ?></h4>
                    <address>
                        <?php
                        // Use shipping address if available, otherwise fall back to billing
                        $ship_addr1 = !empty($order->shipping_address_1) ? $order->shipping_address_1 : ($order->billing_address_1 ?? '');
                        $ship_addr2 = !empty($order->shipping_address_2) ? $order->shipping_address_2 : ($order->billing_address_2 ?? '');
                        $ship_city = !empty($order->shipping_city) ? $order->shipping_city : ($order->billing_city ?? '');
                        $ship_state = !empty($order->shipping_state) ? $order->shipping_state : ($order->billing_state ?? '');
                        $ship_postcode = !empty($order->shipping_postcode) ? $order->shipping_postcode : ($order->billing_postcode ?? '');
                        $ship_country = !empty($order->shipping_country) ? $order->shipping_country : ($order->billing_country ?? '');
                        ?>
                        <?php echo esc_html($order->customer_first_name . ' ' . $order->customer_last_name); ?><br>
                        <?php if (!empty($ship_addr1)): ?>
                            <?php echo esc_html($ship_addr1); ?><br>
                        <?php endif; ?>
                        <?php if (!empty($ship_addr2)): ?>
                            <?php echo esc_html($ship_addr2); ?><br>
                        <?php endif; ?>
                        <?php if (!empty($ship_city)): ?>
                            <?php echo esc_html($ship_city); ?>
                            <?php if (!empty($ship_state)): ?>, <?php echo esc_html($ship_state); ?><?php endif; ?>
                            <?php if (!empty($ship_postcode)): ?> <?php echo esc_html($ship_postcode); ?><?php endif; ?>
                            <br>
                        <?php endif; ?>
                        <?php if (!empty($ship_country)): ?>
                            <?php echo esc_html($ship_country); ?>
                        <?php endif; ?>
                    </address>
                </div>
            </div>

            <?php
            // Get customer-visible notes only
            $customer_notes = GGM_Commerce_Order_Notes::get_customer_notes($order->id);
            if (!empty($customer_notes)):
            ?>
            <div class="order-notes-section">
                <h4><?php esc_html_e('Order Notes', 'ggm-commerce'); ?></h4>
                <?php foreach ($customer_notes as $note): ?>
                    <p><?php echo nl2br(esc_html($note->content)); ?></p>
                <?php endforeach; ?>
            </div>
            <?php endif; ?>
        </div>
        <?php
        return ob_get_clean();
    }

    /**
     * AJAX handler for getting invoice URL (frontend customer view)
     * Returns a secure URL to the centralized invoice template
     */
    public function ajax_get_invoice_url() {
        // Verify nonce
        if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'ggm_commerce_order_nonce')) {
            wp_send_json_error(['message' => 'Security check failed']);
        }

        // Must be logged in
        if (!is_user_logged_in()) {
            wp_send_json_error(['message' => 'Please log in to access invoices']);
        }

        $order_id = isset($_POST['order_id']) ? intval(wp_unslash($_POST['order_id'])) : 0;

        if (!$order_id) {
            wp_send_json_error(['message' => 'Order ID required']);
        }

        global $wpdb;
        $order = $wpdb->get_row($wpdb->prepare(
            "SELECT id, user_id, customer_id, customer_email FROM {$wpdb->prefix}ggmc_orders WHERE id = %d",
            $order_id
        ));

        if (!$order) {
            wp_send_json_error(['message' => 'Order not found']);
        }

        // Security: Verify the current user owns this order
        $current_user = wp_get_current_user();
        $current_user_id = get_current_user_id();
        $can_view = false;

        // Check by user_id
        if (!empty($order->user_id) && $current_user_id === intval($order->user_id)) {
            $can_view = true;
        }
        // Check by customer_id
        elseif (!empty($order->customer_id) && $current_user_id === intval($order->customer_id)) {
            $can_view = true;
        }
        // Check by email
        elseif (!empty($order->customer_email) && strtolower($current_user->user_email) === strtolower($order->customer_email)) {
            $can_view = true;
        }
        // Admin can view any order
        elseif (current_user_can('manage_options')) {
            $can_view = true;
        }

        if (!$can_view) {
            wp_send_json_error(['message' => 'You do not have permission to view this invoice']);
        }

        // Generate nonce for the invoice template
        $print_nonce = wp_create_nonce('ggmc_print_order_' . $order_id);

        // Build invoice URL
        $invoice_url = plugins_url('templates/invoice.php', dirname(__FILE__)) . '?order_id=' . $order_id . '&key=' . $print_nonce;

        wp_send_json_success(['url' => $invoice_url]);
    }

    /**
     * Create a renewal order for a subscription
     *
     * @param object $subscription Subscription row from DB.
     * @return int|WP_Error Order ID on success, WP_Error on failure.
     */
    public function create_renewal_order( $subscription ) {
        global $wpdb;

        if ( ! class_exists( 'GGM_Commerce_Subscriptions' ) ) {
            return new \WP_Error( 'no_subscriptions', 'Subscriptions module not available.' );
        }

        $sub_manager = GGM_Commerce_Subscriptions::instance();
        $items       = $sub_manager->get_subscription_items( $subscription->id );

        if ( empty( $items ) ) {
            return new \WP_Error( 'no_items', 'Subscription has no items.' );
        }

        // Get parent order for address data.
        $parent_order = null;
        if ( ! empty( $subscription->parent_order_id ) ) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $parent_order = $wpdb->get_row( $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_orders WHERE id = %d",
                $subscription->parent_order_id
            ) );
        }

        $order_number = $this->generate_order_number();

        $order_data = array(
            'order_number'         => $order_number,
            'user_id'              => $subscription->customer_id ?: 0,
            'customer_email'       => $subscription->customer_email,
            'customer_first_name'  => $parent_order->customer_first_name ?? '',
            'customer_last_name'   => $parent_order->customer_last_name ?? '',
            'customer_phone'       => $parent_order->customer_phone ?? '',
            'billing_address_1'    => $parent_order->billing_address_1 ?? '',
            'billing_address_2'    => $parent_order->billing_address_2 ?? '',
            'billing_city'         => $parent_order->billing_city ?? '',
            'billing_state'        => $parent_order->billing_state ?? '',
            'billing_country'      => $parent_order->billing_country ?? '',
            'billing_postcode'     => $parent_order->billing_postcode ?? '',
            'shipping_address_1'   => $parent_order->shipping_address_1 ?? '',
            'shipping_address_2'   => $parent_order->shipping_address_2 ?? '',
            'shipping_city'        => $parent_order->shipping_city ?? '',
            'shipping_state'       => $parent_order->shipping_state ?? '',
            'shipping_country'     => $parent_order->shipping_country ?? '',
            'shipping_postcode'    => $parent_order->shipping_postcode ?? '',
            'subtotal'             => $subscription->recurring_amount,
            'tax_amount'           => $subscription->tax_amount ?? 0,
            'shipping_amount'      => $subscription->shipping_amount ?? 0,
            'total_amount'         => $subscription->recurring_total,
            'subscription_id'      => $subscription->id,
            'is_renewal'           => 1,
            'status'               => 'pending',
            'payment_status'       => 'pending',
            'notes'                => sprintf( 'Renewal order for subscription #%s', $subscription->subscription_number ),
            'created_at'           => current_time( 'mysql' ),
            'updated_at'           => current_time( 'mysql' ),
        );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $inserted = $wpdb->insert( "{$wpdb->prefix}ggmc_orders", $order_data );

        if ( ! $inserted ) {
            return new \WP_Error( 'insert_failed', 'Failed to create renewal order.' );
        }

        $order_id = $wpdb->insert_id;

        // Insert order items from subscription items.
        foreach ( $items as $item ) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
            $wpdb->insert(
                "{$wpdb->prefix}ggmc_order_items",
                array(
                    'order_id'           => $order_id,
                    'product_id'         => $item->product_id,
                    'product_name'       => $item->product_name,
                    'product_sku'        => $item->product_sku,
                    'quantity'           => $item->quantity,
                    'price'              => $item->recurring_price,
                    'total'              => $item->recurring_total,
                    'variation_id'       => $item->variation_id ?: null,
                    'variation_data'     => $item->variation_data ?: '',
                    'is_subscription_item' => 1,
                    'created_at'         => current_time( 'mysql' ),
                )
            );
        }

        $sub_manager->log_event(
            $subscription->id,
            'renewal_order_created',
            sprintf( 'Renewal order #%s created.', $order_number ),
            $order_id,
            $subscription->recurring_total,
            'system'
        );

        return $order_id;
    }
}

// Initialize orders system
GGM_Commerce_Orders::get_instance();