<?php
if (!defined('ABSPATH'))
    exit;

class SVLD_Ajax
{

    public function __construct()
    {
        // Save layout
        add_action('wp_ajax_svld_save_layout', [$this, 'handle_save_layout']);

        // Print label (single product → PDF download)
        add_action('wp_ajax_svld_print_label', [$this, 'handle_print_label']);

        // Test print (uses current layout without requiring save)
        add_action('wp_ajax_svld_test_print', [$this, 'handle_test_print']);

        // Bulk print (array of product IDs → PDF download)
        add_action('wp_ajax_svld_bulk_print', [$this, 'handle_bulk_print']);

        // Print labels for all products in an order
        add_action('wp_ajax_svld_print_order_labels', [$this, 'handle_print_order_labels']);

        // Search products (for test print in designer)
        add_action('wp_ajax_svld_search_products', [$this, 'handle_search_products']);

        // Reset layout to default
        add_action('wp_ajax_svld_reset_layout', [$this, 'handle_reset_layout']);

        // Template management
        add_action('wp_ajax_svld_save_template', [$this, 'handle_save_template']);
        add_action('wp_ajax_svld_load_template', [$this, 'handle_load_template']);
        add_action('wp_ajax_svld_delete_template', [$this, 'handle_delete_template']);
        add_action('wp_ajax_svld_duplicate_template', [$this, 'handle_duplicate_template']);
        add_action('wp_ajax_svld_list_templates', [$this, 'handle_list_templates']);
        add_action('wp_ajax_svld_set_default_template', [$this, 'handle_set_default_template']);

        // Order bulk print
        add_action('wp_ajax_svld_get_order_products', [$this, 'handle_get_order_products']);
        add_action('wp_ajax_svld_bulk_print_order_labels', [$this, 'handle_bulk_print_order_labels']);

        // Preset layouts
        add_action('wp_ajax_svld_get_preset_layout', [$this, 'handle_get_preset_layout']);
    }

    // -----------------------------------------------------------------------

    /**
     * Validate and sanitize image URL against allowed hosts
     */
    private function sanitize_image_url(string $url): string
    {
        $url = esc_url_raw($url);
        if (empty($url)) {
            return '';
        }

        // Parse URL to get host
        $parsed = wp_parse_url($url);
        if (!isset($parsed['host'])) {
            return '';
        }

        $host = $parsed['host'];

        // Allowed hosts: current site and WordPress.com CDN (for uploaded images)
        $allowed_hosts = [
            wp_parse_url(home_url(), PHP_URL_HOST),
            'i0.wp.com',
            'i1.wp.com',
            'i2.wp.com',
            'i3.wp.com', // WordPress.com CDN
        ];

        // Check if host is in allowed list or is a subdomain of current site
        $current_host = wp_parse_url(home_url(), PHP_URL_HOST);
        $is_allowed = false;

        foreach ($allowed_hosts as $allowed) {
            if ($host === $allowed || $host === 'www.' . $allowed || 'www.' . $host === $allowed) {
                $is_allowed = true;
                break;
            }
        }

        // Also allow subdomains of current site
        if (strpos($host, '.' . $current_host) !== false || strpos($current_host, '.' . $host) !== false) {
            $is_allowed = true;
        }

        return $is_allowed ? $url : '';
    }

    // -----------------------------------------------------------------------

    /**
     * Sanitize layout array elements.
     *
     * @param mixed $layout Raw decoded layout array.
     * @return array Sanitized layout.
     */
    private function svld_sanitize_layout($layout)
    {
        if (!is_array($layout)) {
            return array();
        }
        $allowed_types = array('text', 'barcode', 'qr', 'image');
        $sanitized = array();
        foreach ($layout as $element) {
            if (!is_array($element))
                continue;
            $clean = array();
            if (isset($element['type']))
                $clean['type'] = in_array($element['type'], $allowed_types, true) ? $element['type'] : 'text';
            if (isset($element['x']))
                $clean['x'] = floatval($element['x']);
            if (isset($element['y']))
                $clean['y'] = floatval($element['y']);
            if (isset($element['width']))
                $clean['width'] = floatval($element['width']);
            if (isset($element['height']))
                $clean['height'] = floatval($element['height']);
            if (isset($element['fontSize']))
                $clean['fontSize'] = absint($element['fontSize']);
            if (isset($element['text']))
                $clean['text'] = sanitize_text_field($element['text']);
            if (isset($element['dataSource']))
                $clean['dataSource'] = sanitize_key($element['dataSource']);
            if (isset($element['imageUrl']))
                $clean['imageUrl'] = esc_url_raw($element['imageUrl']);
            if (isset($element['imageDataSource'])) {
                $valid_sources = ['custom', 'product_image', 'shop_logo'];
                $clean['imageDataSource'] = in_array($element['imageDataSource'], $valid_sources, true)
                    ? $element['imageDataSource'] : 'custom';
            }
            if (isset($element['bold']))
                $clean['bold'] = (bool) $element['bold'];
            if (isset($element['align']))
                $clean['align'] = sanitize_key($element['align']);
            if (isset($element['id']))
                $clean['id'] = sanitize_key($element['id']);
            if (isset($element['color']))
                $clean['color'] = sanitize_hex_color($element['color']) ?? '#000000';
            if (isset($element['visible']))
                $clean['visible'] = (bool) $element['visible'];
            $sanitized[] = $clean;
        }
        return $sanitized;
    }

    // -----------------------------------------------------------------------

    /**
     * Rate limiting for PDF generation (20 PDFs per minute per user)
     */
    private function check_rate_limit(): bool
    {
        $user_id = get_current_user_id();
        $option_key = 'svld_rate_limit_' . $user_id;
        $data = get_option($option_key, ['count' => 0, 'time' => time()]);
        $window = 60; // 1 minute window
        $limit = 20; // 20 PDFs per minute

        // Reset if window expired
        if (time() - $data['time'] > $window) {
            $data = ['count' => 0, 'time' => time()];
        }

        // Check limit
        if ($data['count'] >= $limit) {
            return false;
        }

        // Increment counter
        $data['count']++;
        update_option($option_key, $data);

        return true;
    }

    // -----------------------------------------------------------------------

    public function handle_save_layout(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $layout_raw = sanitize_textarea_field(wp_unslash($_POST['layout'] ?? ''));

        if (empty($layout_raw)) {
            wp_send_json_error(['message' => __('No layout data received.', 'scanvault-label-designer')]);
        }

        $layout = $this->svld_sanitize_layout(json_decode($layout_raw, true));
        if (!is_array($layout)) {
            wp_send_json_error(['message' => __('Invalid layout data.', 'scanvault-label-designer')]);
        }

        // Sanitize each element with support for dynamic data sources
        $sanitized = [];
        foreach ($layout as $el) {
            if (!isset($el['id'], $el['type']))
                continue;

            $sanitized_el = [
                'id' => sanitize_key($el['id']),
                'type' => sanitize_key($el['type']),
                'label' => sanitize_text_field($el['label'] ?? ''),
                'x' => (float) ($el['x'] ?? 0),
                'y' => (float) ($el['y'] ?? 0),
                'width' => (float) ($el['width'] ?? 30),
                'height' => (float) ($el['height'] ?? 10),
                'fontSize' => max(6, min(48, (int) ($el['fontSize'] ?? 10))),
                'bold' => (bool) ($el['bold'] ?? false),
                'align' => in_array($el['align'] ?? 'left', ['left', 'center', 'right'], true) ? $el['align'] : 'left',
                'visible' => (bool) ($el['visible'] ?? true),
                'showText' => (bool) ($el['showText'] ?? true),
                'fitWidth' => (bool) ($el['fitWidth'] ?? false),
                'multiLine' => (bool) ($el['multiLine'] ?? false),
                'proportional' => (bool) ($el['proportional'] ?? false),
                // Invoice table properties - preserve all checkbox states
                'italic' => (bool) ($el['italic'] ?? false),
                'underline' => (bool) ($el['underline'] ?? false),
                'barcodeType' => sanitize_text_field($el['barcodeType'] ?? 'C128'),
                'qrType' => sanitize_text_field($el['qrType'] ?? 'QRCODE,H'),
                'showItemQty' => isset($el['showItemQty']) ? (bool) $el['showItemQty'] : true,
                'showItemPrice' => isset($el['showItemPrice']) ? (bool) $el['showItemPrice'] : true,
                'showItemImage' => isset($el['showItemImage']) ? (bool) $el['showItemImage'] : false,
                'showSubtotal' => isset($el['showSubtotal']) ? (bool) $el['showSubtotal'] : true,
                'showTax' => isset($el['showTax']) ? (bool) $el['showTax'] : true,
                'showShipping' => isset($el['showShipping']) ? (bool) $el['showShipping'] : true,
                'showDiscount' => isset($el['showDiscount']) ? (bool) $el['showDiscount'] : false,
                'showTotal' => isset($el['showTotal']) ? (bool) $el['showTotal'] : true,
                'showPayment' => isset($el['showPayment']) ? (bool) $el['showPayment'] : false,
                'showShippingVia' => isset($el['showShippingVia']) ? (bool) $el['showShippingVia'] : false,
                'textDirection' => in_array($el['textDirection'] ?? 'ltr', ['ltr', 'rtl']) ? $el['textDirection'] : 'ltr',
            ];

            // Add data source for dynamic elements
            if (isset($el['dataSource'])) {
                $sanitized_el['dataSource'] = sanitize_text_field($el['dataSource']);
            }
            if (isset($el['customText'])) {
                $sanitized_el['customText'] = sanitize_text_field($el['customText']);
            }
            if (isset($el['imageDataSource'])) {
                $valid_image_sources = ['custom', 'product_image', 'shop_logo'];
                $sanitized_el['imageDataSource'] = in_array($el['imageDataSource'], $valid_image_sources, true)
                    ? $el['imageDataSource']
                    : 'custom';
            }
            if ($el['type'] === 'image' && !isset($sanitized_el['imageDataSource'])) {
                $sanitized_el['imageDataSource'] = 'custom';
            }
            if (isset($el['imageUrl'])) {
                if (($sanitized_el['imageDataSource'] ?? 'custom') === 'custom') {
                    $sanitized_el['imageUrl'] = $this->sanitize_image_url($el['imageUrl']);
                } else {
                    $sanitized_el['imageUrl'] = '';
                }
            }

            $sanitized[] = $sanitized_el;
        }

        update_option('svld_layout', $sanitized);

        // Also save label dimensions if provided
        $label_width = 100;
        $label_height = 50;
        if (isset($_POST['label_width'])) {
            $label_width = max(20, min(300, absint( wp_unslash( $_POST['label_width'] ) )));
            update_option('svld_label_width', $label_width);
        }
        if (isset($_POST['label_height'])) {
            $label_height = max(10, min(200, absint( wp_unslash( $_POST['label_height'] ) )));
            update_option('svld_label_height', $label_height);
        }

        // Also update the current template if one is being edited
        $template_id = sanitize_key(wp_unslash($_POST['template_id'] ?? ''));
        if ($template_id && $template_id !== 'current') {
            $templates = get_option('svld_templates', []);
            if (isset($templates[$template_id])) {
                $templates[$template_id]['layout'] = $sanitized;
                $templates[$template_id]['label_width'] = $label_width;
                $templates[$template_id]['label_height'] = $label_height;
                $templates[$template_id]['modified'] = current_time('mysql');
                update_option('svld_templates', $templates);
            }
        }

        wp_send_json_success(['message' => __('Layout saved.', 'scanvault-label-designer')]);
    }

    // -----------------------------------------------------------------------

    public function handle_print_label(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        // Rate limiting: 20 PDFs per minute per user
        if (!$this->check_rate_limit()) {
            wp_send_json_error(['message' => __('Rate limit exceeded. Please wait before generating more PDFs.', 'scanvault-label-designer')]);
        }

        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        if (!$product_id) {
            wp_send_json_error(['message' => __('No product ID provided.', 'scanvault-label-designer')]);
        }

        $product = wc_get_product($product_id);
        if (!$product) {
            wp_send_json_error(['message' => __('Product not found.', 'scanvault-label-designer')]);
        }

        $quantity = max(1, absint( wp_unslash( $_POST['quantity'] ?? 1 ) ));

        // Get the template for product edit page
        $template_id = get_option('svld_product_page_template', '');
        $renderer = new SVLD_Renderer($template_id);
        $pdf_url = $renderer->generate_label_pdf([$product_id => $quantity]);

        if ($pdf_url) {
            wp_send_json_success(['pdf_url' => $pdf_url]);
        } else {
            $error_msg = $renderer->get_last_error();
            if (empty($error_msg)) {
                $error_msg = __('PDF generation failed.', 'scanvault-label-designer');
            }
            wp_send_json_error(['message' => $error_msg]);
        }
    }

    // -----------------------------------------------------------------------

    public function handle_bulk_print(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        // Rate limiting: 20 PDFs per minute per user
        if (!$this->check_rate_limit()) {
            wp_send_json_error(['message' => __('Rate limit exceeded. Please wait before generating more PDFs.', 'scanvault-label-designer')]);
        }

        $ids_raw = sanitize_text_field( wp_unslash( $_POST['product_ids'] ?? '' ) );
        $ids = array_filter(array_map('intval', explode(',', $ids_raw)));

        if (empty($ids)) {
            wp_send_json_error(['message' => __('No products selected.', 'scanvault-label-designer')]);
        }

        // Build product_id => quantity map (1 label each by default)
        $product_map = array_fill_keys($ids, 1);

        // Get the template for bulk action
        $template_id = get_option('svld_bulk_action_template', '');
        $renderer = new SVLD_Renderer($template_id);
        $pdf_url = $renderer->generate_label_pdf($product_map);

        if ($pdf_url) {
            wp_send_json_success(['pdf_url' => $pdf_url]);
        } else {
            $error_msg = $renderer->get_last_error();
            if (empty($error_msg)) {
                $error_msg = __('PDF generation failed.', 'scanvault-label-designer');
            }
            wp_send_json_error(['message' => $error_msg]);
        }
    }

    // -----------------------------------------------------------------------

    public function handle_print_order_labels(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        // Rate limiting: 20 PDFs per minute per user
        if (!$this->check_rate_limit()) {
            wp_send_json_error(['message' => __('Rate limit exceeded. Please wait before generating more PDFs.', 'scanvault-label-designer')]);
        }

        $order_id = absint( wp_unslash( $_POST['order_id'] ?? 0 ) );
        if (!$order_id) {
            wp_send_json_error(['message' => __('No order ID provided.', 'scanvault-label-designer')]);
        }

        $order = wc_get_order($order_id);
        if (!$order) {
            wp_send_json_error(['message' => __('Order not found.', 'scanvault-label-designer')]);
        }

        $product_map = [];
        foreach ($order->get_items() as $item) {
            $product_id = $item->get_product_id();
            $qty = max(1, (int) $item->get_quantity());
            if ($product_id) {
                $product_map[$product_id] = ($product_map[$product_id] ?? 0) + $qty;
            }
        }

        if (empty($product_map)) {
            wp_send_json_error(['message' => __('No products found in this order.', 'scanvault-label-designer')]);
        }

        // Get the template for order metabox
        $template_id = get_option('svld_order_metabox_template', '');
        $renderer = new SVLD_Renderer($template_id);
        $pdf_url = $renderer->generate_label_pdf($product_map, $order);

        if ($pdf_url) {
            wp_send_json_success(['pdf_url' => $pdf_url]);
        } else {
            wp_send_json_error(['message' => __('PDF generation failed.', 'scanvault-label-designer')]);
        }
    }

    // -----------------------------------------------------------------------

    public function handle_search_products(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $term = sanitize_text_field(wp_unslash($_POST['term'] ?? ''));

        // Allow empty search for test print, but require 2 chars for user searches
        $args = [
            'limit' => 10,
            'status' => 'publish',
            'return' => 'ids',
        ];

        if (strlen($term) >= 2) {
            $args['s'] = $term;
        }

        $results = wc_get_products($args);

        $products = [];
        foreach ($results as $id) {
            $p = wc_get_product($id);
            if ($p) {
                $products[] = [
                    'id' => $id,
                    'name' => $p->get_name(),
                    'sku' => $p->get_sku(),
                    'price' => $p->get_price(),
                ];
            }
        }

        wp_send_json_success($products);
    }

    // -----------------------------------------------------------------------

    public function handle_reset_layout(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        update_option('svld_layout', svld_default_layout());
        wp_send_json_success(['layout' => svld_default_layout()]);
    }

    // -----------------------------------------------------------------------
    // Template Management
    // -----------------------------------------------------------------------

    public function handle_save_template(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $template_name = sanitize_text_field(wp_unslash($_POST['template_name'] ?? ''));
        if (empty($template_name)) {
            wp_send_json_error(['message' => __('Template name is required.', 'scanvault-label-designer')]);
        }

        $layout_raw = sanitize_textarea_field(wp_unslash($_POST['layout'] ?? ''));
        if (empty($layout_raw)) {
            wp_send_json_error(['message' => __('No layout data received.', 'scanvault-label-designer')]);
        }

        $layout = $this->svld_sanitize_layout(json_decode($layout_raw, true));
        if (!is_array($layout)) {
            wp_send_json_error(['message' => __('Invalid layout data.', 'scanvault-label-designer')]);
        }

        // Sanitize layout elements (including image URL validation)
        $sanitized_layout = [];
        foreach ($layout as $el) {
            if (!isset($el['id'], $el['type']))
                continue;

            $sanitized_el = [
                'id' => sanitize_key($el['id']),
                'type' => sanitize_key($el['type']),
                'label' => sanitize_text_field($el['label'] ?? ''),
                'x' => (float) ($el['x'] ?? 0),
                'y' => (float) ($el['y'] ?? 0),
                'width' => (float) ($el['width'] ?? 30),
                'height' => (float) ($el['height'] ?? 10),
                'fontSize' => max(6, min(48, (int) ($el['fontSize'] ?? 10))),
                'bold' => (bool) ($el['bold'] ?? false),
                'align' => in_array($el['align'] ?? 'left', ['left', 'center', 'right'], true) ? $el['align'] : 'left',
                'visible' => (bool) ($el['visible'] ?? true),
                'showText' => (bool) ($el['showText'] ?? true),
                'fitWidth' => (bool) ($el['fitWidth'] ?? false),
                'multiLine' => (bool) ($el['multiLine'] ?? false),
                'proportional' => (bool) ($el['proportional'] ?? false),
                // Invoice table properties - preserve all checkbox states
                'italic' => (bool) ($el['italic'] ?? false),
                'underline' => (bool) ($el['underline'] ?? false),
                'barcodeType' => sanitize_text_field($el['barcodeType'] ?? 'C128'),
                'qrType' => sanitize_text_field($el['qrType'] ?? 'QRCODE,H'),
                'showItemQty' => isset($el['showItemQty']) ? (bool) $el['showItemQty'] : true,
                'showItemPrice' => isset($el['showItemPrice']) ? (bool) $el['showItemPrice'] : true,
                'showItemImage' => isset($el['showItemImage']) ? (bool) $el['showItemImage'] : false,
                'showSubtotal' => isset($el['showSubtotal']) ? (bool) $el['showSubtotal'] : true,
                'showTax' => isset($el['showTax']) ? (bool) $el['showTax'] : true,
                'showShipping' => isset($el['showShipping']) ? (bool) $el['showShipping'] : true,
                'showDiscount' => isset($el['showDiscount']) ? (bool) $el['showDiscount'] : false,
                'showTotal' => isset($el['showTotal']) ? (bool) $el['showTotal'] : true,
                'showPayment' => isset($el['showPayment']) ? (bool) $el['showPayment'] : false,
                'showShippingVia' => isset($el['showShippingVia']) ? (bool) $el['showShippingVia'] : false,
                'textDirection' => in_array($el['textDirection'] ?? 'ltr', ['ltr', 'rtl']) ? $el['textDirection'] : 'ltr',
            ];

            if (isset($el['dataSource'])) {
                $sanitized_el['dataSource'] = sanitize_text_field($el['dataSource']);
            }
            if (isset($el['customText'])) {
                $sanitized_el['customText'] = sanitize_text_field($el['customText']);
            }
            if (isset($el['imageDataSource'])) {
                $valid_image_sources = ['custom', 'product_image', 'shop_logo'];
                $sanitized_el['imageDataSource'] = in_array($el['imageDataSource'], $valid_image_sources, true)
                    ? $el['imageDataSource']
                    : 'custom';
            }
            if ($el['type'] === 'image' && !isset($sanitized_el['imageDataSource'])) {
                $sanitized_el['imageDataSource'] = 'custom';
            }
            if (isset($el['imageUrl'])) {
                if (($sanitized_el['imageDataSource'] ?? 'custom') === 'custom') {
                    $sanitized_el['imageUrl'] = $this->sanitize_image_url($el['imageUrl']);
                } else {
                    $sanitized_el['imageUrl'] = '';
                }
            }

            $sanitized_layout[] = $sanitized_el;
        }

        // Get existing templates
        $templates = get_option('svld_templates', []);

        // Check if updating existing or creating new
        $template_id = sanitize_key(wp_unslash($_POST['template_id'] ?? ''));
        if ($template_id && isset($templates[$template_id])) {
            // Update existing
            $templates[$template_id]['name'] = $template_name;
            $templates[$template_id]['layout'] = $sanitized_layout;
            $templates[$template_id]['label_width'] = absint( wp_unslash( $_POST['label_width'] ?? 100 ) );
            $templates[$template_id]['label_height'] = absint( wp_unslash( $_POST['label_height'] ?? 50 ) );
            $templates[$template_id]['modified'] = current_time('mysql');
        } else {
            // Create new
            $template_id = 'tpl_' . time();
            $allowed_types = ['product', 'shipping', 'invoice', 'return', ''];
            $label_type = in_array(wp_unslash($_POST['label_type'] ?? ''), $allowed_types, true)
                ? sanitize_key(wp_unslash($_POST['label_type'] ?? ''))
                : '';

            $templates[$template_id] = [
                'id' => $template_id,
                'name' => $template_name,
                'label_type' => $label_type,
                'layout' => $sanitized_layout,
                'label_width' => absint( wp_unslash( $_POST['label_width'] ?? 100 ) ),
                'label_height' => absint( wp_unslash( $_POST['label_height'] ?? 50 ) ),
                'created' => current_time('mysql'),
                'modified' => current_time('mysql'),
            ];
        }

        update_option('svld_templates', $templates);
        wp_send_json_success([
            'message' => __('Template saved.', 'scanvault-label-designer'),
            'template_id' => $template_id,
        ]);
    }

    public function handle_load_template(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $template_id = sanitize_key(wp_unslash($_POST['template_id'] ?? ''));
        if (empty($template_id)) {
            wp_send_json_error(['message' => __('Template ID is required.', 'scanvault-label-designer')]);
        }

        $templates = get_option('svld_templates', []);
        if (!isset($templates[$template_id])) {
            wp_send_json_error(['message' => __('Template not found.', 'scanvault-label-designer')]);
        }

        $template = $templates[$template_id];
        wp_send_json_success([
            'template' => $template,
        ]);
    }

    public function handle_delete_template(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $template_id = sanitize_key(wp_unslash($_POST['template_id'] ?? ''));
        if (empty($template_id)) {
            wp_send_json_error(['message' => __('Template ID is required.', 'scanvault-label-designer')]);
        }

        $templates = get_option('svld_templates', []);
        if (!isset($templates[$template_id])) {
            wp_send_json_error(['message' => __('Template not found.', 'scanvault-label-designer')]);
        }

        // Check if it's the default template
        $default_template = get_option('svld_default_template', '');
        if ($default_template === $template_id) {
            update_option('svld_default_template', '');
        }

        unset($templates[$template_id]);
        update_option('svld_templates', $templates);
        wp_send_json_success(['message' => __('Template deleted.', 'scanvault-label-designer')]);
    }

    public function handle_duplicate_template(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $template_id = sanitize_key(wp_unslash($_POST['template_id'] ?? ''));
        if (empty($template_id)) {
            wp_send_json_error(['message' => __('Template ID is required.', 'scanvault-label-designer')]);
        }

        $templates = get_option('svld_templates', []);
        if (!isset($templates[$template_id])) {
            wp_send_json_error(['message' => __('Template not found.', 'scanvault-label-designer')]);
        }

        $original = $templates[$template_id];
        $new_id = 'tpl_' . time();
        $templates[$new_id] = [
            'id' => $new_id,
            'name' => $original['name'] . ' ' . __('(Copy)', 'scanvault-label-designer'),
            'label_type' => $original['label_type'] ?? '',
            'layout' => $original['layout'],
            'label_width' => $original['label_width'],
            'label_height' => $original['label_height'],
            'created' => current_time('mysql'),
            'modified' => current_time('mysql'),
        ];

        update_option('svld_templates', $templates);
        wp_send_json_success(['message' => __('Template duplicated.', 'scanvault-label-designer')]);
    }

    public function handle_list_templates(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $templates = get_option('svld_templates', []);
        $default_template = get_option('svld_default_template', '');

        $template_list = [];
        foreach ($templates as $id => $template) {
            $template_list[] = [
                'id' => $id,
                'name' => $template['name'],
                'label_type' => $template['label_type'] ?? '',
                'is_default' => ($id === $default_template),
                'created' => $template['created'] ?? '',
                'modified' => $template['modified'] ?? '',
            ];
        }

        wp_send_json_success(['templates' => $template_list]);
    }

    public function handle_set_default_template(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $template_id = sanitize_key(wp_unslash($_POST['template_id'] ?? ''));
        if (empty($template_id)) {
            wp_send_json_error(['message' => __('Template ID is required.', 'scanvault-label-designer')]);
        }

        $templates = get_option('svld_templates', []);
        if (!isset($templates[$template_id])) {
            wp_send_json_error(['message' => __('Template not found.', 'scanvault-label-designer')]);
        }

        // Set as default template
        update_option('svld_default_template', $template_id);

        // Also set this template for all positions in settings
        update_option('svld_product_page_template', $template_id);
        update_option('svld_order_metabox_template', $template_id);
        update_option('svld_bulk_action_template', $template_id);
        update_option('svld_invoice_tab_template', $template_id);

        wp_send_json_success(['message' => __('Default template updated and applied to all positions.', 'scanvault-label-designer')]);
    }

    // -----------------------------------------------------------------------
    // Order Bulk Print
    // -----------------------------------------------------------------------

    public function handle_get_order_products(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $order_ids_raw = sanitize_text_field( wp_unslash( $_POST['order_ids'] ?? '' ) );
        $order_ids = array_filter(array_map('intval', explode(',', $order_ids_raw)));

        if (empty($order_ids)) {
            wp_send_json_error(['message' => __('No orders provided.', 'scanvault-label-designer')]);
        }

        $product_map = [];
        foreach ($order_ids as $order_id) {
            $order = wc_get_order($order_id);
            if (!$order) {
                continue;
            }

            foreach ($order->get_items() as $item) {
                $product_id = $item->get_product_id();
                $qty = max(1, (int) $item->get_quantity());
                if ($product_id) {
                    $product_map[$product_id] = ($product_map[$product_id] ?? 0) + $qty;
                }
            }
        }

        if (empty($product_map)) {
            wp_send_json_error(['message' => __('No products found in orders.', 'scanvault-label-designer')]);
        }

        wp_send_json_success(['product_map' => $product_map]);
    }

    public function handle_bulk_print_order_labels(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        // Rate limiting: 20 PDFs per minute per user
        if (!$this->check_rate_limit()) {
            wp_send_json_error(['message' => __('Rate limit exceeded. Please wait before generating more PDFs.', 'scanvault-label-designer')]);
        }

        // Accept order_ids directly (comma-separated string or array)
        $order_ids_raw = sanitize_text_field( wp_unslash( $_POST['order_ids'] ?? '' ) );
        $order_ids = array_filter(array_map(
            'intval',
            is_array($order_ids_raw)
            ? $order_ids_raw
            : explode(',', $order_ids_raw)
        ));

        if (empty($order_ids)) {
            wp_send_json_error(['message' => __('No orders provided.', 'scanvault-label-designer')]);
        }

        // Build product map and capture order context
        $product_map = [];
        $orders = [];
        foreach ($order_ids as $order_id) {
            $order = wc_get_order($order_id);
            if (!$order)
                continue;
            $orders[] = $order;
            foreach ($order->get_items() as $item) {
                $product_id = $item->get_product_id();
                $qty = max(1, (int) $item->get_quantity());
                if ($product_id) {
                    $product_map[$product_id] = ($product_map[$product_id] ?? 0) + $qty;
                }
            }
        }

        if (empty($product_map)) {
            wp_send_json_error(['message' => __('No products found in the selected orders.', 'scanvault-label-designer')]);
        }

        // Get the template for order bulk action (falls back to order metabox template)
        $template_id = get_option('svld_order_bulk_action_template', '');
        if (empty($template_id)) {
            $template_id = get_option('svld_order_metabox_template', '');
        }
        $renderer = new SVLD_Renderer($template_id);

        // For order-level templates (shipping label, invoice, etc.) generate one page per order
        // so each label has the correct customer name, address, and order data.
        // For product templates, merge products from all orders into one PDF.
        if ($renderer->is_order_level_layout()) {
            $pdf_url = $renderer->generate_bulk_orders_pdf($orders);
        } else {
            $order_context = count($orders) === 1 ? $orders[0] : null;
            $pdf_url = $renderer->generate_label_pdf($product_map, $order_context);
        }

        if ($pdf_url) {
            wp_send_json_success(['pdf_url' => $pdf_url]);
        } else {
            $error_msg = $renderer->get_last_error();
            if (empty($error_msg)) {
                $error_msg = __('PDF generation failed.', 'scanvault-label-designer');
            }
            wp_send_json_error(['message' => $error_msg]);
        }
    }

    // -----------------------------------------------------------------------

    public function handle_get_preset_layout(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        $preset_key = sanitize_key(wp_unslash($_POST['preset'] ?? ''));
        $presets = svld_get_preset_layouts();

        if (!isset($presets[$preset_key])) {
            wp_send_json_error(['message' => __('Preset not found.', 'scanvault-label-designer')]);
        }

        wp_send_json_success($presets[$preset_key]);
    }

    public function handle_test_print(): void
    {
        check_ajax_referer('svld_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(['message' => __('Unauthorized', 'scanvault-label-designer')]);
        }

        // Rate limiting: 20 PDFs per minute per user
        if (!$this->check_rate_limit()) {
            wp_send_json_error(['message' => __('Rate limit exceeded. Please wait before generating more PDFs.', 'scanvault-label-designer')]);
        }

        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        if (!$product_id) {
            wp_send_json_error(['message' => __('No product ID provided.', 'scanvault-label-designer')]);
        }

        $product = wc_get_product($product_id);
        if (!$product) {
            wp_send_json_error(['message' => __('Product not found.', 'scanvault-label-designer')]);
        }

        // Get current layout from POST data
        $layout_raw = sanitize_textarea_field(wp_unslash($_POST['layout'] ?? ''));
        if (empty($layout_raw)) {
            wp_send_json_error(['message' => __('No layout data provided.', 'scanvault-label-designer')]);
        }

        $layout = $this->svld_sanitize_layout(json_decode($layout_raw, true));
        if (!is_array($layout)) {
            wp_send_json_error(['message' => __('Invalid layout data.', 'scanvault-label-designer')]);
        }

        // Sanitize layout elements
        $sanitized = [];
        foreach ($layout as $el) {
            if (!isset($el['id'], $el['type']))
                continue;

            $sanitized_el = [
                'id' => sanitize_key($el['id']),
                'type' => sanitize_key($el['type']),
                'label' => sanitize_text_field($el['label'] ?? ''),
                'x' => (float) ($el['x'] ?? 0),
                'y' => (float) ($el['y'] ?? 0),
                'width' => (float) ($el['width'] ?? 30),
                'height' => (float) ($el['height'] ?? 10),
                'fontSize' => max(6, min(48, (int) ($el['fontSize'] ?? 10))),
                'bold' => (bool) ($el['bold'] ?? false),
                'align' => in_array($el['align'] ?? 'left', ['left', 'center', 'right'], true) ? $el['align'] : 'left',
                'visible' => (bool) ($el['visible'] ?? true),
                'showText' => (bool) ($el['showText'] ?? true),
                'fitWidth' => (bool) ($el['fitWidth'] ?? false),
                'multiLine' => (bool) ($el['multiLine'] ?? false),
                'proportional' => (bool) ($el['proportional'] ?? false),
                'italic' => (bool) ($el['italic'] ?? false),
                'underline' => (bool) ($el['underline'] ?? false),
                'barcodeType' => sanitize_text_field($el['barcodeType'] ?? 'C128'),
                'qrType' => sanitize_text_field($el['qrType'] ?? 'QRCODE,H'),
                'showItemQty' => isset($el['showItemQty']) ? (bool) $el['showItemQty'] : true,
                'showItemPrice' => isset($el['showItemPrice']) ? (bool) $el['showItemPrice'] : true,
                'showItemImage' => isset($el['showItemImage']) ? (bool) $el['showItemImage'] : false,
                'showSubtotal' => isset($el['showSubtotal']) ? (bool) $el['showSubtotal'] : true,
                'showTax' => isset($el['showTax']) ? (bool) $el['showTax'] : true,
                'showShipping' => isset($el['showShipping']) ? (bool) $el['showShipping'] : true,
                'showDiscount' => isset($el['showDiscount']) ? (bool) $el['showDiscount'] : false,
                'showTotal' => isset($el['showTotal']) ? (bool) $el['showTotal'] : true,
                'showPayment' => isset($el['showPayment']) ? (bool) $el['showPayment'] : false,
                'showShippingVia' => isset($el['showShippingVia']) ? (bool) $el['showShippingVia'] : false,
                'textDirection' => in_array($el['textDirection'] ?? 'ltr', ['ltr', 'rtl']) ? $el['textDirection'] : 'ltr',
            ];

            if (isset($el['dataSource'])) {
                $sanitized_el['dataSource'] = sanitize_text_field($el['dataSource']);
            }
            if (isset($el['customText'])) {
                $sanitized_el['customText'] = sanitize_text_field($el['customText']);
            }
            if (isset($el['imageUrl'])) {
                $sanitized_el['imageUrl'] = $this->sanitize_image_url($el['imageUrl']);
            }
            if (isset($el['imageDataSource'])) {
                $valid_image_sources = ['custom', 'product_image', 'shop_logo'];
                $sanitized_el['imageDataSource'] = in_array($el['imageDataSource'], $valid_image_sources, true)
                    ? $el['imageDataSource']
                    : 'custom';
            }

            if ($el['type'] === 'image' && !isset($sanitized_el['imageDataSource'])) {
                $sanitized_el['imageDataSource'] = 'custom';
            }

            $sanitized[] = $sanitized_el;
        }
        $layout = $sanitized;

        // Get label dimensions
        $label_width = absint( wp_unslash( $_POST['label_width'] ?? 100 ) );
        $label_height = absint( wp_unslash( $_POST['label_height'] ?? 50 ) );

        // Create renderer with current layout
        $renderer = new SVLD_Renderer();
        $renderer->set_custom_layout($layout, $label_width, $label_height);
        $pdf_url = $renderer->generate_label_pdf([$product_id => 1]);

        if ($pdf_url) {
            wp_send_json_success(['pdf_url' => $pdf_url]);
        } else {
            $error_msg = $renderer->get_last_error();
            if (empty($error_msg)) {
                $error_msg = __('PDF generation failed.', 'scanvault-label-designer');
            }
            wp_send_json_error(['message' => $error_msg]);
        }
    }
}
