<?php
/**
 * Checkout Controller
 *
 * @package Jeremias\WcLicensedProduct\Checkout
 */

declare(strict_types=1);

namespace Jeremias\WcLicensedProduct\Checkout;

use Jeremias\WcLicensedProduct\License\LicenseManager;
use Jeremias\WcLicensedProduct\Admin\SettingsController;
use Jeremias\WcLicensedProduct\Product\LicensedProductVariation;

/**
 * Handles checkout modifications for licensed products
 */
final class CheckoutController
{
    private LicenseManager $licenseManager;

    public function __construct(LicenseManager $licenseManager)
    {
        $this->licenseManager = $licenseManager;
        $this->registerHooks();
    }

    /**
     * Register WordPress hooks
     */
    private function registerHooks(): void
    {
        // Add domain field to checkout
        add_action('woocommerce_after_order_notes', [$this, 'addDomainField']);

        // Validate domain field
        add_action('woocommerce_checkout_process', [$this, 'validateDomainField']);

        // Save domain field to order meta
        add_action('woocommerce_checkout_update_order_meta', [$this, 'saveDomainField']);

        // Display domain in order details (admin)
        add_action('woocommerce_admin_order_data_after_billing_address', [$this, 'displayDomainInAdmin']);

        // Display domain in order email
        add_action('woocommerce_email_after_order_table', [$this, 'displayDomainInEmail'], 10, 3);
    }

    /**
     * Check if cart contains licensed products
     */
    private function cartHasLicensedProducts(): bool
    {
        return !empty($this->getLicensedProductsFromCart());
    }

    /**
     * Get licensed products from cart with quantities
     *
     * @return array<string, array{product_id: int, variation_id: int, name: string, quantity: int, duration_label: string}>
     */
    private function getLicensedProductsFromCart(): array
    {
        if (!WC()->cart) {
            return [];
        }

        $licensedProducts = [];
        foreach (WC()->cart->get_cart() as $cartItem) {
            $product = $cartItem['data'];
            if (!$product) {
                continue;
            }

            // Check for simple licensed products
            if ($product->is_type('licensed')) {
                $productId = $product->get_id();
                $licensedProducts[$productId] = [
                    'product_id' => $productId,
                    'variation_id' => 0,
                    'name' => $product->get_name(),
                    'quantity' => (int) $cartItem['quantity'],
                    'duration_label' => '',
                ];
                continue;
            }

            // Check for variations of licensed-variable products
            if ($product->is_type('variation')) {
                $parentId = $product->get_parent_id();
                $parent = wc_get_product($parentId);

                if ($parent && $parent->is_type('licensed-variable')) {
                    $variationId = $product->get_id();
                    // Use combination key to allow same product with different variations
                    $key = "{$parentId}_{$variationId}";

                    // Get duration label if it's a LicensedProductVariation
                    $durationLabel = '';
                    if ($product instanceof LicensedProductVariation) {
                        $durationLabel = $product->get_license_duration_label();
                    } else {
                        // Try to instantiate as LicensedProductVariation
                        $variation = new LicensedProductVariation($variationId);
                        $durationLabel = $variation->get_license_duration_label();
                    }

                    $licensedProducts[$key] = [
                        'product_id' => $parentId,
                        'variation_id' => $variationId,
                        'name' => $product->get_name(),
                        'quantity' => (int) $cartItem['quantity'],
                        'duration_label' => $durationLabel,
                    ];
                }
            }
        }

        return $licensedProducts;
    }

    /**
     * Add domain fields to checkout form
     * Shows multiple domain fields if multi-domain is enabled, otherwise single field
     */
    public function addDomainField(): void
    {
        $licensedProducts = $this->getLicensedProductsFromCart();
        if (empty($licensedProducts)) {
            return;
        }

        // Check if multi-domain licensing is enabled
        if (SettingsController::isMultiDomainEnabled()) {
            $this->renderMultiDomainFields($licensedProducts);
        } else {
            $this->renderSingleDomainField();
        }
    }

    /**
     * Render single domain field (legacy mode)
     */
    private function renderSingleDomainField(): void
    {
        $savedValue = '';

        // Check POST data first (validation failure case)
        if (isset($_POST['licensed_product_domain'])) {
            $savedValue = sanitize_text_field($_POST['licensed_product_domain']);
        } elseif (WC()->session) {
            $savedValue = WC()->session->get('licensed_product_domain', '');
        }

        ?>
        <div id="licensed-product-domain-field">
            <h3><?php esc_html_e('License Domain', 'wc-licensed-product'); ?></h3>
            <p class="form-row form-row-wide">
                <label for="licensed_product_domain">
                    <?php esc_html_e('Domain', 'wc-licensed-product'); ?>
                    <abbr class="required" title="<?php esc_attr_e('required', 'wc-licensed-product'); ?>">*</abbr>
                </label>
                <input
                    type="text"
                    class="input-text"
                    name="licensed_product_domain"
                    id="licensed_product_domain"
                    placeholder="<?php esc_attr_e('example.com', 'wc-licensed-product'); ?>"
                    value="<?php echo esc_attr($savedValue); ?>"
                />
                <span class="description">
                    <?php esc_html_e('Enter the domain where you will use the license (without http:// or www).', 'wc-licensed-product'); ?>
                </span>
            </p>
        </div>
        <?php
    }

    /**
     * Render multi-domain fields (one per quantity)
     */
    private function renderMultiDomainFields(array $licensedProducts): void
    {
        ?>
        <div id="licensed-product-domain-fields">
            <h3><?php esc_html_e('License Domains', 'wc-licensed-product'); ?></h3>
            <p class="wclp-domain-description">
                <?php esc_html_e('Enter a unique domain for each license (without http:// or www).', 'wc-licensed-product'); ?>
            </p>

            <?php foreach ($licensedProducts as $key => $productData): ?>
                <?php
                $productId = $productData['product_id'];
                $variationId = $productData['variation_id'] ?? 0;
                $durationLabel = $productData['duration_label'] ?? '';
                // Use key for field names to handle variations
                $fieldKey = $variationId > 0 ? "{$productId}_{$variationId}" : $productId;
                ?>
                <div class="wclp-product-domains" data-product-id="<?php echo esc_attr($productId); ?>" data-variation-id="<?php echo esc_attr($variationId); ?>">
                    <h4>
                        <?php
                        echo esc_html($productData['name']);
                        if (!empty($durationLabel)) {
                            echo ' <span class="wclp-duration-badge">(' . esc_html($durationLabel) . ')</span>';
                        }
                        if ($productData['quantity'] > 1) {
                            printf(' ×%d', $productData['quantity']);
                        }
                        ?>
                    </h4>

                    <?php for ($i = 0; $i < $productData['quantity']; $i++): ?>
                        <?php
                        $fieldName = sprintf('licensed_domains[%s][%d]', $fieldKey, $i);
                        $fieldId = sprintf('licensed_domain_%s_%d', str_replace('_', '-', $fieldKey), $i);
                        $savedValue = $this->getSavedDomainValue($productId, $i, $variationId);
                        ?>
                        <p class="form-row form-row-wide wclp-domain-row">
                            <label for="<?php echo esc_attr($fieldId); ?>">
                                <?php
                                printf(
                                    /* translators: %d: license number */
                                    esc_html__('License %d:', 'wc-licensed-product'),
                                    $i + 1
                                );
                                ?>
                                <abbr class="required" title="<?php esc_attr_e('required', 'wc-licensed-product'); ?>">*</abbr>
                            </label>
                            <input
                                type="text"
                                class="input-text wclp-domain-input"
                                name="<?php echo esc_attr($fieldName); ?>"
                                id="<?php echo esc_attr($fieldId); ?>"
                                placeholder="<?php esc_attr_e('example.com', 'wc-licensed-product'); ?>"
                                value="<?php echo esc_attr($savedValue); ?>"
                            />
                            <?php if ($variationId > 0): ?>
                                <input type="hidden" name="licensed_variation_ids[<?php echo esc_attr($fieldKey); ?>]" value="<?php echo esc_attr($variationId); ?>" />
                            <?php endif; ?>
                        </p>
                    <?php endfor; ?>
                </div>
            <?php endforeach; ?>
        </div>
        <style>
            #licensed-product-domain-fields { margin-bottom: 20px; }
            #licensed-product-domain-fields h3 { margin-bottom: 10px; }
            .wclp-domain-description { margin-bottom: 15px; color: #666; }
            .wclp-product-domains { margin-bottom: 20px; padding: 15px; background: #f8f8f8; border-radius: 4px; }
            .wclp-product-domains h4 { margin: 0 0 10px 0; font-size: 1em; }
            .wclp-duration-badge { color: #0073aa; font-weight: normal; }
            .wclp-domain-row { margin-bottom: 10px; }
            .wclp-domain-row:last-child { margin-bottom: 0; }
            .wclp-domain-row label { display: block; margin-bottom: 5px; }
        </style>
        <?php
    }

    /**
     * Get saved domain value from session/POST
     */
    private function getSavedDomainValue(int $productId, int $index, int $variationId = 0): string
    {
        // Build the field key (with or without variation)
        $fieldKey = $variationId > 0 ? "{$productId}_{$variationId}" : (string) $productId;

        // Check POST data first (validation failure case)
        if (isset($_POST['licensed_domains'][$fieldKey][$index])) {
            return sanitize_text_field($_POST['licensed_domains'][$fieldKey][$index]);
        }

        // Also try numeric key for backward compatibility
        if (isset($_POST['licensed_domains'][$productId][$index])) {
            return sanitize_text_field($_POST['licensed_domains'][$productId][$index]);
        }

        // Check session for blocks checkout
        if (WC()->session) {
            $sessionDomains = WC()->session->get('licensed_product_domains', []);
            foreach ($sessionDomains as $item) {
                $itemProductId = (int) ($item['product_id'] ?? 0);
                $itemVariationId = (int) ($item['variation_id'] ?? 0);

                // Match by product and variation
                if ($itemProductId === $productId && $itemVariationId === $variationId) {
                    if (isset($item['domains'][$index])) {
                        return $item['domains'][$index];
                    }
                }
            }
        }

        return '';
    }

    /**
     * Validate domain fields during checkout
     */
    public function validateDomainField(): void
    {
        $licensedProducts = $this->getLicensedProductsFromCart();
        if (empty($licensedProducts)) {
            return;
        }

        // Check if multi-domain licensing is enabled
        if (SettingsController::isMultiDomainEnabled()) {
            $this->validateMultiDomainFields($licensedProducts);
        } else {
            $this->validateSingleDomainField();
        }
    }

    /**
     * Validate single domain field
     */
    private function validateSingleDomainField(): void
    {
        $domain = isset($_POST['licensed_product_domain']) ? sanitize_text_field($_POST['licensed_product_domain']) : '';

        if (empty($domain)) {
            wc_add_notice(__('Please enter a domain for your license.', 'wc-licensed-product'), 'error');
            return;
        }

        $normalizedDomain = $this->licenseManager->normalizeDomain($domain);
        if (!$this->isValidDomain($normalizedDomain)) {
            wc_add_notice(__('Please enter a valid domain for your license.', 'wc-licensed-product'), 'error');
        }
    }

    /**
     * Validate multi-domain fields
     */
    private function validateMultiDomainFields(array $licensedProducts): void
    {
        $licensedDomains = $_POST['licensed_domains'] ?? [];

        foreach ($licensedProducts as $key => $productData) {
            $productId = $productData['product_id'];
            $variationId = $productData['variation_id'] ?? 0;
            $fieldKey = $variationId > 0 ? "{$productId}_{$variationId}" : (string) $productId;

            $productDomains = $licensedDomains[$fieldKey] ?? $licensedDomains[$productId] ?? [];
            $normalizedDomains = [];

            for ($i = 0; $i < $productData['quantity']; $i++) {
                $domain = isset($productDomains[$i]) ? sanitize_text_field($productDomains[$i]) : '';

                // Check if domain is empty
                if (empty($domain)) {
                    wc_add_notice(
                        sprintf(
                            /* translators: 1: product name, 2: license number */
                            __('Please enter a domain for %1$s (License %2$d).', 'wc-licensed-product'),
                            $productData['name'],
                            $i + 1
                        ),
                        'error'
                    );
                    continue;
                }

                // Validate domain format
                $normalizedDomain = $this->licenseManager->normalizeDomain($domain);
                if (!$this->isValidDomain($normalizedDomain)) {
                    wc_add_notice(
                        sprintf(
                            /* translators: 1: product name, 2: license number */
                            __('Please enter a valid domain for %1$s (License %2$d).', 'wc-licensed-product'),
                            $productData['name'],
                            $i + 1
                        ),
                        'error'
                    );
                    continue;
                }

                // Check for duplicate domains within same product/variation
                if (in_array($normalizedDomain, $normalizedDomains, true)) {
                    wc_add_notice(
                        sprintf(
                            /* translators: 1: domain name, 2: product name */
                            __('The domain "%1$s" is used multiple times for %2$s. Each license requires a unique domain.', 'wc-licensed-product'),
                            $normalizedDomain,
                            $productData['name']
                        ),
                        'error'
                    );
                } else {
                    $normalizedDomains[] = $normalizedDomain;
                }
            }
        }
    }

    /**
     * Save domain fields to order meta
     */
    public function saveDomainField(int $orderId): void
    {
        $licensedProducts = $this->getLicensedProductsFromCart();
        if (empty($licensedProducts)) {
            return;
        }

        $order = wc_get_order($orderId);
        if (!$order) {
            return;
        }

        // Check if multi-domain licensing is enabled
        if (SettingsController::isMultiDomainEnabled()) {
            $this->saveMultiDomainFields($order, $licensedProducts);
        } else {
            $this->saveSingleDomainField($order);
        }
    }

    /**
     * Save single domain field to order meta (legacy format)
     */
    private function saveSingleDomainField(\WC_Order $order): void
    {
        $domain = isset($_POST['licensed_product_domain']) ? sanitize_text_field($_POST['licensed_product_domain']) : '';

        if (!empty($domain)) {
            $normalizedDomain = $this->licenseManager->normalizeDomain($domain);
            $order->update_meta_data('_licensed_product_domain', $normalizedDomain);
            $order->save();
        }
    }

    /**
     * Save multi-domain fields to order meta
     */
    private function saveMultiDomainFields(\WC_Order $order, array $licensedProducts): void
    {
        $licensedDomains = $_POST['licensed_domains'] ?? [];
        $licensedVariationIds = $_POST['licensed_variation_ids'] ?? [];
        $domainData = [];

        foreach ($licensedProducts as $key => $productData) {
            $productId = $productData['product_id'];
            $variationId = $productData['variation_id'] ?? 0;
            $fieldKey = $variationId > 0 ? "{$productId}_{$variationId}" : (string) $productId;

            $productDomains = $licensedDomains[$fieldKey] ?? $licensedDomains[$productId] ?? [];
            $normalizedDomains = [];

            for ($i = 0; $i < $productData['quantity']; $i++) {
                $domain = isset($productDomains[$i]) ? sanitize_text_field($productDomains[$i]) : '';
                if (!empty($domain)) {
                    $normalizedDomains[] = $this->licenseManager->normalizeDomain($domain);
                }
            }

            if (!empty($normalizedDomains)) {
                $entry = [
                    'product_id' => $productId,
                    'domains' => $normalizedDomains,
                ];

                // Include variation_id if present
                if ($variationId > 0) {
                    $entry['variation_id'] = $variationId;
                }

                $domainData[] = $entry;
            }
        }

        if (!empty($domainData)) {
            $order->update_meta_data('_licensed_product_domains', $domainData);
            $order->save();
        }
    }

    /**
     * Display domains in admin order view
     */
    public function displayDomainInAdmin(\WC_Order $order): void
    {
        // Try new multi-domain format first
        $domainData = $order->get_meta('_licensed_product_domains');
        if (!empty($domainData) && is_array($domainData)) {
            $this->displayMultiDomainsInAdmin($domainData);
            return;
        }

        // Fall back to legacy single domain
        $domain = $order->get_meta('_licensed_product_domain');
        if (!$domain) {
            return;
        }

        ?>
        <p>
            <strong><?php esc_html_e('License Domain:', 'wc-licensed-product'); ?></strong>
            <?php echo esc_html($domain); ?>
        </p>
        <?php
    }

    /**
     * Display multi-domain data in admin
     */
    private function displayMultiDomainsInAdmin(array $domainData): void
    {
        ?>
        <div class="wclp-order-domains">
            <strong><?php esc_html_e('License Domains:', 'wc-licensed-product'); ?></strong>
            <?php foreach ($domainData as $item): ?>
                <?php
                $productId = $item['product_id'];
                $variationId = $item['variation_id'] ?? 0;

                // Get product name
                if ($variationId > 0) {
                    $variation = wc_get_product($variationId);
                    $productName = $variation ? $variation->get_name() : __('Unknown Variation', 'wc-licensed-product');

                    // Add duration label if available
                    if ($variation instanceof LicensedProductVariation) {
                        $productName .= ' (' . $variation->get_license_duration_label() . ')';
                    }
                } else {
                    $product = wc_get_product($productId);
                    $productName = $product ? $product->get_name() : __('Unknown Product', 'wc-licensed-product');
                }
                ?>
                <p style="margin: 5px 0 5px 15px;">
                    <em><?php echo esc_html($productName); ?>:</em><br>
                    <?php echo esc_html(implode(', ', $item['domains'])); ?>
                </p>
            <?php endforeach; ?>
        </div>
        <?php
    }

    /**
     * Display domains in order emails
     */
    public function displayDomainInEmail(\WC_Order $order, bool $sentToAdmin, bool $plainText): void
    {
        // Try new multi-domain format first
        $domainData = $order->get_meta('_licensed_product_domains');
        if (!empty($domainData) && is_array($domainData)) {
            $this->displayMultiDomainsInEmail($domainData, $plainText);
            return;
        }

        // Fall back to legacy single domain
        $domain = $order->get_meta('_licensed_product_domain');
        if (!$domain) {
            return;
        }

        if ($plainText) {
            echo "\n" . esc_html__('License Domain:', 'wc-licensed-product') . ' ' . esc_html($domain) . "\n";
        } else {
            ?>
            <p>
                <strong><?php esc_html_e('License Domain:', 'wc-licensed-product'); ?></strong>
                <?php echo esc_html($domain); ?>
            </p>
            <?php
        }
    }

    /**
     * Display multi-domain data in email
     */
    private function displayMultiDomainsInEmail(array $domainData, bool $plainText): void
    {
        if ($plainText) {
            echo "\n" . esc_html__('License Domains:', 'wc-licensed-product') . "\n";
            foreach ($domainData as $item) {
                $productId = $item['product_id'];
                $variationId = $item['variation_id'] ?? 0;

                if ($variationId > 0) {
                    $variation = wc_get_product($variationId);
                    $productName = $variation ? $variation->get_name() : __('Unknown Variation', 'wc-licensed-product');
                    if ($variation instanceof LicensedProductVariation) {
                        $productName .= ' (' . $variation->get_license_duration_label() . ')';
                    }
                } else {
                    $product = wc_get_product($productId);
                    $productName = $product ? $product->get_name() : __('Unknown Product', 'wc-licensed-product');
                }

                echo '  ' . esc_html($productName) . ': ' . esc_html(implode(', ', $item['domains'])) . "\n";
            }
        } else {
            ?>
            <div style="margin-bottom: 15px;">
                <strong><?php esc_html_e('License Domains:', 'wc-licensed-product'); ?></strong>
                <?php foreach ($domainData as $item): ?>
                    <?php
                    $productId = $item['product_id'];
                    $variationId = $item['variation_id'] ?? 0;

                    if ($variationId > 0) {
                        $variation = wc_get_product($variationId);
                        $productName = $variation ? $variation->get_name() : __('Unknown Variation', 'wc-licensed-product');
                        if ($variation instanceof LicensedProductVariation) {
                            $productName .= ' (' . $variation->get_license_duration_label() . ')';
                        }
                    } else {
                        $product = wc_get_product($productId);
                        $productName = $product ? $product->get_name() : __('Unknown Product', 'wc-licensed-product');
                    }
                    ?>
                    <p style="margin: 5px 0 5px 15px;">
                        <em><?php echo esc_html($productName); ?>:</em><br>
                        <?php echo esc_html(implode(', ', $item['domains'])); ?>
                    </p>
                <?php endforeach; ?>
            </div>
            <?php
        }
    }

    /**
     * Validate domain format
     */
    private function isValidDomain(string $domain): bool
    {
        // Basic domain validation
        if (strlen($domain) > 255) {
            return false;
        }

        // Check for valid domain pattern
        $pattern = '/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/';

        return (bool) preg_match($pattern, $domain);
    }
}
