<?php

declare(strict_types=1);

namespace ReallySimplePlugins\RSS\Core\Features\Vulnerability;

use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Controllers\PluginController;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Controllers\ThemeController;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Controllers\VulnerabilityDataController;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Controllers\VulnerabilityNoticeController;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Controllers\VulnerabilityNotificationController;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Services\VulnerabilitySyncService;
use ReallySimplePlugins\RSS\Core\Interfaces\FeatureInterface;
use ReallySimplePlugins\RSS\Core\Support\Helpers\Storages\EnvironmentConfig;
use ReallySimplePlugins\RSS\Core\Traits\HasScheduler;
use ReallySimplePlugins\RSS\Core\Traits\HasViews;

/**
 * Registers WordPress hooks and coordinates the vulnerability sync lifecycle.
 *
 * Lifecycle (high level):
 * - Schedule a sync when components change (plugin/theme/core updates/activation)
 *   and once per day as a safety net.
 * - Debounce multiple triggers into a single scheduled event.
 * - Run the scheduled job with a lock to avoid overlapping syncs.
 * - Fire a completion action after a successful run.
 *
 */
final class VulnerabilityController implements FeatureInterface
{
    use HasViews;
    use HasScheduler;

    /**
     * Action hook name used to trigger a scheduled vulnerability sync.
     *
     * This hook is scheduled via the VulnerabilityScheduleManager and ultimately
     * results in `scheduleSync()` being executed.
     */
    private const SYNC_EVENT = 'rsssl_vulnerability_run_scheduled_sync';

    /**
     * Action hook fired after a vulnerability sync has completed.
     *
     * Can be used by other parts of the system to react to a finished sync
     * (e.g. logging, notices, follow-up processing).
     */
    public const SYNC_COMPLETED_ACTION = 'rsssl_vulnerability_sync_completed';

    /**
     * Debounce window (in seconds) for scheduling vulnerability syncs.
     *
     * Multiple triggers within this time window will result in a single
     * scheduled sync execution.
     */
    private const SYNC_DEBOUNCE = (5 * MINUTE_IN_SECONDS);

    private VulnerabilitySyncService $vulnerabilitySyncService;
    private EnvironmentConfig $env;

    public function __construct(
        VulnerabilitySyncService $vulnerabilitySyncService,
        EnvironmentConfig $environmentConfig
    ) {
        $this->vulnerabilitySyncService = $vulnerabilitySyncService;
        $this->env = $environmentConfig;
    }

    /**
     * Registers WordPress hooks for the Vulnerability feature.
     *
     * Keeps the feature wiring in one place: enqueueing assets, registering
     * controllers, and scheduling/running vulnerability syncs on relevant events.
     */
    public function register(): void
    {
        add_action('admin_enqueue_scripts', [$this, 'enqueueStyles']);
        add_action(self::SYNC_EVENT, [$this, 'runSync'], 10, 0);
        add_filter('rss_core_controller_classes', [$this, 'registerControllers']);
        add_action('rss_core_activation', [$this, 'scheduleSync'], 10, 1);
        add_action('upgrader_process_complete', [$this, 'scheduleSync'], 10, 2);
        add_action('activate_plugin', [$this, 'scheduleSync'], 10, 2);
        add_action('after_switch_theme', [$this, 'scheduleSync'], 10, 0);
        add_action('_core_updated_successfully', [$this, 'scheduleSync'], 10, 1);
        add_action('rsssl_daily_cron', [$this, 'scheduleSync']);
    }

    /**
     * Registers the controllers related to vulnerability management. This
     * method is hooked into the 'rss_core_controller_classes' filter, that
     * is applied here {@see Plugin::registerControllers}, to make sure the
     * {@see ControllerManager} can register them in the plugin lifecycle.
     */
    public function registerControllers(array $existingControllers): array
    {
        $enablePluginAndThemeDisplay = rsssl_get_option('enable_feedback_in_plugin', false);
        $availableControllers = [
            VulnerabilityDataController::class,
            VulnerabilityNoticeController::class,
            VulnerabilityNotificationController::class,
        ];
        if ($enablePluginAndThemeDisplay) {
            $availableControllers[] = PluginController::class;
            $availableControllers[] = ThemeController::class;
        }
        return array_merge($existingControllers, $availableControllers);
    }

    /**
     * Enqueues shared vulnerability styling on plugins and themes overview pages.
     * we register this here because both the PluginController and ThemeController
     * needs the same styles.
     *
     * @param null|string $hook Current admin page hook suffix. Can be null in
     * non-default admin pages. For example when using a page builder plugin.
    */
    public function enqueueStyles(?string $hook = null): void
    {
        if (empty($hook) || !$this->isComponentOverviewScreen($hook)) {
            return;
        }

        $rtl = is_rtl() ? 'rtl/' : '';
        $assetsUrl  = trailingslashit($this->env->getString('plugin.assets_url'));
        $assetsPath = trailingslashit($this->env->getString('plugin.assets_path'));

        $url  = $assetsUrl . "css/{$rtl}rsssl-plugin.min.css";
        $path = $assetsPath . "css/{$rtl}rsssl-plugin.min.css";
        $version = $this->env->get('plugin.version');
        if (file_exists($path)) {
            wp_enqueue_style('rsssl-plugin', $url, [], $version);
        }
    }

    /**
     * Determine whether the current admin page is a plugin or theme overview screen.
     *
     * Supports both regular admin and multisite network-admin pages.
     */
    private function isComponentOverviewScreen(string $hook): bool
    {
        return in_array($hook, ['plugins.php', 'plugins-network.php', 'themes.php', 'themes-network.php'], true);
    }

    /**
     * Schedule a debounced vulnerability sync.
     *
     * Uses the DebouncedScheduler trait to prevent multiple rapidly fired
     * triggers from scheduling duplicate jobs.
     */
    public function scheduleSync(): void
    {
        $this->scheduleDebounced(
            self::SYNC_EVENT,
            self::SYNC_DEBOUNCE,
            []
        );
    }

    /**
     * Execute the vulnerability sync and release the scheduling lock.
     *
     * After the sync completes, the completion action is fired to allow other
     * components to react.
     */
    public function runSync(): void
    {
        // Run the sync logic (example):
        $this->vulnerabilitySyncService->syncAllComponents();

        // Release the debounce lock so future triggers can schedule again.
        $this->releaseDebounceLock(self::SYNC_EVENT);

        // Notify that the sync has completed.
        do_action(self::SYNC_COMPLETED_ACTION);
    }

}
