<?php

namespace WPSN\Modules\Licensing;

use WPSN\Core\AbstractModule;
use WPSN\Core\Container;

defined('ABSPATH') || exit;

final class LicensingModule extends AbstractModule
{
    private const CRON_HOOK = 'wpsn_license_verify';
    private const BILLING_CRON_HOOK = 'wpsn_billing_center_sync';

    private LicenseService $service;
    private BillingSyncService $billingSync;

    public function __construct(Container $container)
    {
        parent::__construct($container);
        $this->service = new LicenseService($this->settings, $this->logger);
        $this->billingSync = new BillingSyncService($this->settings, $this->logger);
    }

    public function id(): string
    {
        return 'licensing';
    }

    public function name(): string
    {
        return __('Licensing', 'wp-seo-next');
    }

    public function description(): string
    {
        return __('License verification & entitlements (optional).', 'wp-seo-next');
    }

    public function defaultEnabled(): bool
    {
        // Keep the licensing UI available in every build so Free installs can
        // still expose a local plan state and upgrade path without reaching the
        // backend until a paid key is entered.
        return true;
    }

    public function register(): void
    {
        // Schedule verifier.
        add_action('init', [$this, 'ensureSchedule'], 5);
        add_action(self::CRON_HOOK, [$this, 'cronVerify']);
        add_action(self::BILLING_CRON_HOOK, [$this, 'cronBillingSync']);

        // Optional Pro update client (integrates with WP updater).
        (new UpdateClient($this->settings, $this->logger, $this->service))->register();

        // Module locking.
        add_filter('wpsn/module/is_enabled', [$this, 'filterModuleEnabled'], 20, 3);

        if (is_admin()) {
            (new Admin\LicensingAdmin($this->container, $this->service))->register();
        }
    }

    public function ensureSchedule(): void
    {
        if (!$this->settings->get('licensing.scheduled_verify', true)) {
            if (function_exists('wp_clear_scheduled_hook')) {
                wp_clear_scheduled_hook(self::CRON_HOOK);
            }
        } elseif (!wp_next_scheduled(self::CRON_HOOK)) {
            // Spread load.
            wp_schedule_event(time() + (2 * HOUR_IN_SECONDS), 'twicedaily', self::CRON_HOOK);
        }

        if (!$this->billingSync->isEnabled() || !$this->billingSync->scheduled()) {
            if (function_exists('wp_clear_scheduled_hook')) {
                wp_clear_scheduled_hook(self::BILLING_CRON_HOOK);
            }
            return;
        }

        if (!wp_next_scheduled(self::BILLING_CRON_HOOK)) {
            wp_schedule_event(time() + (3 * HOUR_IN_SECONDS), 'twicedaily', self::BILLING_CRON_HOOK);
        }
    }

    public function cronVerify(): void
    {
        // Only verify if we have a key + server.
        if (!$this->service->hasLicenseKey()) {
            return;
        }
        if ($this->service->serverUrl() === '') {
            return;
        }

        try {
            $this->service->verifyIfNeeded(true);
        } catch (\Throwable $e) {
            $this->logger->warning('License cron verify failed: ' . $e->getMessage());
        }
    }

    public function cronBillingSync(): void
    {
        if (!$this->billingSync->isEnabled()) {
            return;
        }
        if (!$this->billingSync->hasLicenseKey()) {
            return;
        }
        if ($this->billingSync->serverUrl() === '') {
            return;
        }

        try {
            $this->billingSync->syncIfNeeded(true);
        } catch (\Throwable $e) {
            $this->logger->warning('Billing sync cron failed: ' . $e->getMessage());
        }
    }

    /**
     * Lock premium modules when enforce_entitlements is enabled.
     */
    public function filterModuleEnabled(bool $enabled, string $moduleId, $module): bool
    {
        if (!$enabled) {
            return false;
        }

        if (!$this->service->enforceEntitlements()) {
            return $enabled;
        }

        $requiredTier = PlanMatrix::moduleTier($moduleId);
        if ($requiredTier === PlanMatrix::TIER_FREE) {
            return $enabled;
        }

        // Never lock Config Sync if settings are already locked, otherwise a site
        // can get trapped in a state where the unlocking UI disappears.
        if ($moduleId === 'config_sync' && (bool) $this->settings->get('config_sync.lock_settings', false)) {
            return $enabled;
        }

        if (!$this->service->isActive()) {
            return false;
        }

        if ($this->service->requireSigned() && !$this->service->isTrusted()) {
            return false;
        }

        $currentPlan = PlanMatrix::detectCurrentPlan(
            $this->service->getCache(),
            $this->billingSync->getCache(),
            $this->service->entitlements()
        );
        $access = PlanMatrix::moduleAccess($moduleId, $currentPlan, $this->service->entitlements());

        return !empty($access['allowed']);
    }
}
