<?php

declare(strict_types=1);

namespace ReallySimplePlugins\RSS\Core\Features\Vulnerability\Controllers;

use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Repositories\VulnerabilityStorageRepository;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Services\VulnerabilityPresentationService;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Traits\HasFrontendUrl;
use ReallySimplePlugins\RSS\Core\Interfaces\ControllerInterface;
use ReallySimplePlugins\RSS\Core\Support\Helpers\Storages\EnvironmentConfig;

/**
 * Integrates vulnerability indicators into the WordPress Themes admin screen.
 *
 * This controller is responsible only for UI integration:
 * - It enqueues the Themes overview script on the correct admin screen.
 * - It exposes a pre-shaped payload via `wp_localize_script()` for that script.
 * - It delegates vulnerability data access to repositories and presentation details
 *   (labels, messaging) to dedicated services.
 *
 * No business logic (severity calculation, storage writes) is performed here.
 */
final class ThemeController implements ControllerInterface
{
    use HasFrontendUrl;

    private VulnerabilityStorageRepository $vulnerabilityStorageRepository;
    private VulnerabilityPresentationService $presentationService;
    private EnvironmentConfig $env;

    public function __construct(
        VulnerabilityStorageRepository $vulnerabilityStorageRepository,
        VulnerabilityPresentationService $presentationService,
        EnvironmentConfig $env
    ) {
        $this->vulnerabilityStorageRepository = $vulnerabilityStorageRepository;
        $this->presentationService = $presentationService;
        $this->env = $env;
    }

    /**
     * Registers WordPress admin hooks for the Themes overview integration.
     *
     * This is called once during plugin boot by the controller manager.
     */
    public function register(): void
    {
        add_action('admin_enqueue_scripts', [$this, 'enqueueThemeAssets']);
    }

    /**
     * Enqueues the Themes overview script and attaches localized vulnerability data.
     *
     * WordPress passes the current admin page hook suffix as `$hook`. We only
     * enqueue and localize on the Themes overview screen (`themes.php`).
     *
     * @param string $hook Current admin page hook suffix.
     */
    public function enqueueThemeAssets(string $hook): void
    {
        if (!$this->isThemeOverviewScreen($hook)) {
            return;
        }

        $assetsBasePath = trailingslashit($this->env->getString('core.assets_path'));
        $assetsBaseUrl = trailingslashit($this->env->getString('core.assets_url'));
        $version = $this->env->get('plugin.version');

        $jsUrl = $assetsBaseUrl . 'js/rsssl-theme-vulnerabilities.js';
        $jsPath = $assetsBasePath . 'js/rsssl-theme-vulnerabilities.js';

        if (!file_exists($jsPath)) {
            return;
        }

        $handle = 'rsssl-theme-vulnerabilities';

        wp_enqueue_script(
            $handle,
            $jsUrl,
            [],
            $version,
            true
        );

        $this->outputThemeVulnerabilityData($handle);
    }

    /**
     * Determine whether the current admin request targets a Themes overview screen.
     *
     * Supports both regular admin and multisite network-admin theme pages by
     * checking the passed hook suffix first and falling back to `get_current_screen()`.
     */
    private function isThemeOverviewScreen(string $hook): bool
    {
        if (in_array($hook, ['themes.php', 'themes-network.php'], true)) {
            return true;
        }

        if (!function_exists('get_current_screen')) {
            return false;
        }

        $screen = get_current_screen();
        if ($screen === null) {
            return false;
        }

        return in_array((string) $screen->base, ['themes', 'themes-network'], true);
    }

    /**
     * Localizes vulnerable theme data for the Themes overview script.
     *
     * The payload is exposed to JavaScript under the global `rssslVulnerabilities`
     * object (WordPress convention via `wp_localize_script()`).
     *
     * @param string $handle The script handle to attach the localized payload to.
     */
    public function outputThemeVulnerabilityData(string $handle): void
    {
        $themes = $this->buildThemePayload();

        wp_localize_script(
            $handle,
            'rssslVulnerabilities',
            [
                'themes' => $themes,
            ]
        );
    }

    /**
     * Builds the Themes overview payload (vulnerable themes only).
     *
     * @return list<array{
     *   slug: non-empty-string,
     *   severity: non-empty-string,
     *   label: string,
     *   info: string,
     *   url: string
     * }>
     */
    private function buildThemePayload(): array
    {
        $allComponents = $this->vulnerabilityStorageRepository->getAllRaw();

        if ($allComponents === []) {
            return [];
        }

        $themes = [];

        foreach ($allComponents as $allComponent) {
            if (!is_array($allComponent)) {
                continue;
            }

            if (strtolower((string)($allComponent['type'] ?? '')) !== 'theme') {
                continue;
            }

            $slug = (string)($allComponent['slug'] ?? '');
            if ($slug === '') {
                continue;
            }

            $highest = $this->vulnerabilityStorageRepository->getHighestSeverityForThemeSlug($slug);
            if ($highest === null) {
                continue;
            }

            $severity = $highest->severity;
            $label = $this->presentationService->getLabelForSeverity($severity);

            $themes[] = [
                'slug' => $slug,
                'severity' => $severity,
                'label' => $label,
                'info' => __('Really Simple Security detected a vulnerability in this theme', 'really-simple-ssl'),
                'url' => $this->getFrontendUrl(
                    'theme',
                    $slug,
                    $highest->lookup
                ),
            ];
        }

        return $themes;
    }
}
