<?php

declare(strict_types=1);

namespace ReallySimplePlugins\RSS\Core\Features\Pro\Vulnerability\Services;

use ReallySimplePlugins\RSS\Core\Features\Pro\Vulnerability\Services\Policies\VulnerabilitySeverityPolicy;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Repositories\CoreRepository;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Repositories\PluginRepository;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Repositories\ThemeRepository;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Repositories\VulnerabilityStorageRepository;

/**
 * Builds an index of the currently active vulnerability measures per component.
 *
 * This service aggregates data from multiple repositories (plugins, themes, core)
 * and determines which security measure currently applies to each component based
 * on the highest known vulnerability severity.
 *
 * High-level flow:
 * 1) Iterate over all installed plugins, themes, and core components.
 * 2) Look up the highest vulnerability severity for each component.
 * 3) Normalize the severity and determine the corresponding measure.
 * 4) Index the result by a stable vulnerability identifier.
 *
 * Notes for juniors:
 * - This class does not execute measures; it only builds a read-only index.
 * - Missing or incomplete vulnerability data is intentionally skipped.
 * - The returned index is typically consumed by the measures pipeline.
 */
final class VulnerabilityCurrentMeasureIndexBuilder
{
    private PluginRepository $pluginRepository;
    private ThemeRepository $themeRepository;
    private CoreRepository $coreRepository;
    private VulnerabilityStorageRepository $vulnerabilityStorageRepository;
    private VulnerabilitySeverityPolicy $severityPolicy;

    public function __construct(
        PluginRepository $pluginRepository,
        ThemeRepository $themeRepository,
        CoreRepository $coreRepository,
        VulnerabilityStorageRepository $vulnerabilityStorageRepository,
        VulnerabilitySeverityPolicy $severityPolicy
    ) {
        $this->pluginRepository = $pluginRepository;
        $this->themeRepository = $themeRepository;
        $this->coreRepository = $coreRepository;
        $this->vulnerabilityStorageRepository = $vulnerabilityStorageRepository;
        $this->severityPolicy = $severityPolicy;
    }

    /**
     * Build the current measures index.
     *
     * The returned array is keyed by a vulnerability identifier and contains
     * all information required to execute or display the active measure.
     *
     * @return array<string, array{
     *   component_name: string,
     *   component_slug: string,
     *   plugin_file: string,
     *   type: string,
     *   measure: string,
     *   risk: string,
     *   identifier: string
     * }>
     */
    public function build(): array
    {
        $index = [];

        // Build index entries for all installed plugins.
        foreach ($this->pluginRepository->getInstalledComponents() as $plugin) {
            $index += $this->buildForComponent(
                'plugin',
                $plugin->getSlug(),
                $plugin->getName(),
                $plugin->getFile()
            );
        }

        // Build index entries for all installed themes.
        foreach ($this->themeRepository->getInstalledComponents() as $theme) {
            $index += $this->buildForComponent(
                'theme',
                $theme->getSlug(),
                $theme->getName(),
                ''
            );
        }

        // Build index entries for WordPress core.
        foreach ($this->coreRepository->getInstalledComponents() as $core) {
            $index += $this->buildForComponent(
                'core',
                $core->getSlug(),
                $core->getName(),
                ''
            );
        }

        return $index;
    }

    /**
     * Build the measure index entry for a single component.
     *
     * This method determines the highest vulnerability severity for the given
     * component and resolves it to a concrete measure via the severity policy.
     *
     * @param string $type       Component type (plugin, theme, or core).
     * @param string $slug       Component slug.
     * @param string $name       Human-readable component name.
     * @param string $pluginFile Plugin file path (plugins only).
     *
     * @return array<string, array<string, mixed>> Empty when no measure applies.
     */
    private function buildForComponent(
        string $type,
        string $slug,
        string $name,
        string $pluginFile
    ): array {
        // Retrieve the highest known vulnerability severity for this component.
        $highest = $type === 'plugin'
            ? $this->vulnerabilityStorageRepository->getHighestSeverityForPluginSlug($slug)
            : $this->vulnerabilityStorageRepository->getHighestSeverityForThemeSlug($slug);

        // Normalize severity and extract the vulnerability identifier.
        $risk = $this->severityPolicy->normalizeSeverity((string) ($highest->severity ?? ''));
        $identifier = (string) ($highest->lookup ?? '');

        if ($risk === null || $identifier === '') {
            return [];
        }

        // Resolve the concrete measure that applies to this severity.
        $measure = $this->severityPolicy->getHighestMeasure($risk);
        if ($measure === null) {
            return [];
        }

        // Build the index entry keyed by the vulnerability identifier.
        return [
            $identifier => [
                'component_name' => (string) ($highest->name ?? $name),
                'component_slug' => $slug,
                'plugin_file' => $pluginFile,
                'type' => $type,
                'measure' => $measure,
                'risk' => $risk,
                'identifier' => $identifier,
            ],
        ];
    }
}
