<?php
/**
 * Main Plugin class
 *
 * @package Jeremias\WcLicensedProduct
 */

declare(strict_types=1);

namespace Jeremias\WcLicensedProduct;

use Jeremias\WcLicensedProduct\Admin\AdminController;
use Jeremias\WcLicensedProduct\Admin\DashboardWidgetController;
use Jeremias\WcLicensedProduct\Admin\DownloadWidgetController;
use Jeremias\WcLicensedProduct\Admin\OrderLicenseController;
use Jeremias\WcLicensedProduct\Admin\SettingsController;
use Jeremias\WcLicensedProduct\Admin\VersionAdminController;
use Jeremias\WcLicensedProduct\Api\ResponseSigner;
use Jeremias\WcLicensedProduct\Api\RestApiController;
use Jeremias\WcLicensedProduct\Checkout\CheckoutBlocksIntegration;
use Jeremias\WcLicensedProduct\Checkout\CheckoutController;
use Jeremias\WcLicensedProduct\Checkout\StoreApiExtension;
use Jeremias\WcLicensedProduct\Email\LicenseEmailController;
use Jeremias\WcLicensedProduct\Frontend\AccountController;
use Jeremias\WcLicensedProduct\Frontend\DownloadController;
use Jeremias\WcLicensedProduct\License\LicenseManager;
use Jeremias\WcLicensedProduct\License\PluginLicenseChecker;
use Jeremias\WcLicensedProduct\Product\LicensedProductType;
use Jeremias\WcLicensedProduct\Product\VersionManager;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

/**
 * Main plugin controller
 */
final class Plugin
{
    /**
     * Singleton instance
     */
    private static ?Plugin $instance = null;

    /**
     * Twig environment
     */
    private Environment $twig;

    /**
     * License manager
     */
    private LicenseManager $licenseManager;

    /**
     * Version manager
     */
    private VersionManager $versionManager;

    /**
     * Download controller
     */
    private DownloadController $downloadController;

    /**
     * Get singleton instance
     */
    public static function instance(): Plugin
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * Get singleton instance (alias for instance())
     */
    public static function getInstance(): Plugin
    {
        return self::instance();
    }

    /**
     * Private constructor for singleton
     */
    private function __construct()
    {
        $this->initTwig();
        $this->initComponents();
        $this->registerHooks();
    }

    /**
     * Initialize Twig environment
     */
    private function initTwig(): void
    {
        $loader = new FilesystemLoader(WC_LICENSED_PRODUCT_PLUGIN_DIR . 'templates');
        $this->twig = new Environment($loader, [
            'cache' => WP_CONTENT_DIR . '/cache/wc-licensed-product/twig',
            'auto_reload' => true, // Always check for template changes
            'autoescape' => 'html', // Explicitly enable HTML autoescape for XSS protection
        ]);

        // Add WordPress functions as Twig functions
        $this->twig->addFunction(new \Twig\TwigFunction('__', function (string $text, string $domain = 'wc-licensed-product'): string {
            return __($text, $domain);
        }));

        $this->twig->addFunction(new \Twig\TwigFunction('esc_html', 'esc_html'));
        $this->twig->addFunction(new \Twig\TwigFunction('esc_attr', 'esc_attr'));
        $this->twig->addFunction(new \Twig\TwigFunction('esc_url', 'esc_url'));
        $this->twig->addFunction(new \Twig\TwigFunction('wp_nonce_field', 'wp_nonce_field', ['is_safe' => ['html']]));
        $this->twig->addFunction(new \Twig\TwigFunction('admin_url', 'admin_url'));
        $this->twig->addFunction(new \Twig\TwigFunction('wc_get_endpoint_url', 'wc_get_endpoint_url'));
    }

    /**
     * Initialize plugin components
     */
    private function initComponents(): void
    {
        $this->licenseManager = new LicenseManager();
        $this->versionManager = new VersionManager();

        // Check plugin license
        $licenseChecker = PluginLicenseChecker::getInstance();
        $isLicensed = $licenseChecker->isLicenseValid();

        // Always initialize product type (needed for existing orders)
        new LicensedProductType();

        // Only initialize frontend components if licensed or on localhost
        if ($isLicensed) {
            new CheckoutController($this->licenseManager);
            new StoreApiExtension($this->licenseManager);
            $this->registerCheckoutBlocksIntegration();
            $this->downloadController = new DownloadController($this->licenseManager, $this->versionManager);
            new AccountController($this->twig, $this->licenseManager, $this->versionManager, $this->downloadController);
        }

        // Always initialize REST API and email controller
        new RestApiController($this->licenseManager);
        new LicenseEmailController($this->licenseManager);

        // Initialize response signing if server secret is configured
        if (defined('WC_LICENSE_SERVER_SECRET') && WC_LICENSE_SERVER_SECRET !== '') {
            (new ResponseSigner())->register();
        }

        // Admin always available
        if (is_admin()) {
            new AdminController($this->twig, $this->licenseManager);
            new VersionAdminController($this->versionManager);
            new OrderLicenseController($this->licenseManager);
            new SettingsController();
            new DashboardWidgetController($this->licenseManager);
            new DownloadWidgetController($this->versionManager);

            // Show admin notice if unlicensed and not on localhost
            if (!$isLicensed && !$licenseChecker->isLocalhost()) {
                add_action('admin_notices', [$this, 'showUnlicensedNotice']);
            }
        }
    }

    /**
     * Register WooCommerce Checkout Blocks integration
     */
    private function registerCheckoutBlocksIntegration(): void
    {
        add_action('woocommerce_blocks_loaded', function (): void {
            if (class_exists('Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry')) {
                add_action(
                    'woocommerce_blocks_checkout_block_registration',
                    function ($integration_registry): void {
                        $integration_registry->register(new CheckoutBlocksIntegration());
                    }
                );
            }
        });
    }

    /**
     * Register plugin hooks
     */
    private function registerHooks(): void
    {
        // Only register order hooks if licensed (license generation requires valid license)
        $licenseChecker = PluginLicenseChecker::getInstance();
        if ($licenseChecker->isLicenseValid()) {
            // Generate license on order completion (multiple hooks for compatibility)
            add_action('woocommerce_order_status_completed', [$this, 'onOrderCompleted']);
            add_action('woocommerce_order_status_processing', [$this, 'onOrderCompleted']);

            // Also hook into payment complete for immediate license generation
            add_action('woocommerce_payment_complete', [$this, 'onOrderCompleted']);
        }
    }

    /**
     * Handle order completion - generate licenses
     */
    public function onOrderCompleted(int $orderId): void
    {
        $order = wc_get_order($orderId);
        if (!$order) {
            return;
        }

        // Try new multi-domain format first
        $domainData = $order->get_meta('_licensed_product_domains');
        if (!empty($domainData) && is_array($domainData)) {
            $this->generateLicensesMultiDomain($order, $domainData);
            return;
        }

        // Fall back to legacy single domain format
        $this->generateLicensesSingleDomain($order);
    }

    /**
     * Generate licenses for new multi-domain format
     */
    private function generateLicensesMultiDomain(\WC_Order $order, array $domainData): void
    {
        $orderId = $order->get_id();
        $customerId = $order->get_customer_id();

        // Index domains by product ID (and variation ID for variable products)
        $domainsByProduct = [];
        foreach ($domainData as $item) {
            if (isset($item['product_id']) && isset($item['domains']) && is_array($item['domains'])) {
                $productId = (int) $item['product_id'];
                $variationId = isset($item['variation_id']) ? (int) $item['variation_id'] : 0;
                $key = $variationId > 0 ? "{$productId}_{$variationId}" : (string) $productId;
                $domainsByProduct[$key] = [
                    'domains' => $item['domains'],
                    'variation_id' => $variationId,
                ];
            }
        }

        // Generate licenses for each licensed product
        foreach ($order->get_items() as $item) {
            $product = $item->get_product();
            if (!$product || !$this->licenseManager->isLicensedProduct($product)) {
                continue;
            }

            // Get the parent product ID (for variations, this is the main product)
            $productId = $product->is_type('variation') ? $product->get_parent_id() : $product->get_id();
            $variationId = $item->get_variation_id();

            // Look up domains - first try with variation, then without
            $key = $variationId > 0 ? "{$productId}_{$variationId}" : (string) $productId;
            $domainInfo = $domainsByProduct[$key] ?? $domainsByProduct[(string) $productId] ?? null;
            $domains = $domainInfo['domains'] ?? [];

            // Generate a license for each domain
            foreach ($domains as $domain) {
                if (!empty($domain)) {
                    $this->licenseManager->generateLicense(
                        $orderId,
                        $productId,
                        $customerId,
                        $domain,
                        $variationId > 0 ? $variationId : null
                    );
                }
            }
        }
    }

    /**
     * Generate licenses for legacy single domain format
     */
    private function generateLicensesSingleDomain(\WC_Order $order): void
    {
        $domain = $order->get_meta('_licensed_product_domain');
        if (empty($domain)) {
            return;
        }

        foreach ($order->get_items() as $item) {
            $product = $item->get_product();
            if ($product && $this->licenseManager->isLicensedProduct($product)) {
                // Get the parent product ID (for variations, this is the main product)
                $productId = $product->is_type('variation') ? $product->get_parent_id() : $product->get_id();
                $variationId = $item->get_variation_id();

                $this->licenseManager->generateLicense(
                    $order->get_id(),
                    $productId,
                    $order->get_customer_id(),
                    $domain,
                    $variationId > 0 ? $variationId : null
                );
            }
        }
    }

    /**
     * Get Twig environment
     */
    public function getTwig(): Environment
    {
        return $this->twig;
    }

    /**
     * Get license manager
     */
    public function getLicenseManager(): LicenseManager
    {
        return $this->licenseManager;
    }

    /**
     * Render a Twig template
     */
    public function render(string $template, array $context = []): string
    {
        return $this->twig->render($template, $context);
    }

    /**
     * Show admin notice when plugin is unlicensed
     */
    public function showUnlicensedNotice(): void
    {
        $settingsUrl = admin_url('admin.php?page=wc-settings&tab=licensed_product');
        ?>
        <div class="notice notice-warning is-dismissible">
            <p>
                <strong><?php esc_html_e('WC Licensed Product', 'wc-licensed-product'); ?>:</strong>
                <?php esc_html_e('Plugin license is not configured or invalid. Frontend features are disabled.', 'wc-licensed-product'); ?>
                <a href="<?php echo esc_url($settingsUrl); ?>"><?php esc_html_e('Configure License', 'wc-licensed-product'); ?></a>
            </p>
        </div>
        <?php
    }

    /**
     * Get the plugin license checker instance
     */
    public function getLicenseChecker(): PluginLicenseChecker
    {
        return PluginLicenseChecker::getInstance();
    }
}
