<?php

declare(strict_types=1);

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

use ReallySimplePlugins\RSS\Core\Features\Pro\Vulnerability\Dtos\VulnerabilityMeasureRowDto;

/**
 * The measures list represents the currently enabled security measures
 * selected in the Pro interface. Data is stored as a flat, numerically
 * indexed list to keep the storage format simple and predictable.
 */
final class VulnerabilityMeasuresRepository
{
    /**
     * WordPress option key that stores the measures list.
     *
     * Note: This key was also used by RSSSL Pro versions prior to 5.6.0.
     */
    private const OPTION_KEY = 'rsssl_measures_list';

    /**
     * Read the measures list from the WordPress options table.
     *
     * The option value can be modified by other code or older plugin versions,
     * so we always normalize it before returning it.
     *
     * @return array<int, array<string, mixed>> A numerically indexed list of normalized measure rows.
     */
    public function getAll(): array
    {
        $stored = get_option(self::OPTION_KEY, []);
        if (!is_array($stored)) {
            return [];
        }

        return $this->normalizeMeasuresList($stored);
    }

    /**
     * Replace the complete measures list in the WordPress options table.
     *
     * This method normalizes and validates every row before saving. Invalid rows
     * are dropped to keep the stored option value predictable.
     *
     * @param array<int, array<string, mixed>> $measures A list of (possibly untrusted) measure rows.
     */
    public function saveAll(array $measures): void
    {
        update_option(self::OPTION_KEY, $this->normalizeMeasuresList($measures), false);
    }

    /**
     * Normalize a list of measures coming from storage or callers.
     *
     * - Drops rows that are not arrays.
     * - Drops rows that fail DTO validation (VulnerabilityMeasureRowDto::fromArray()).
     * - De-duplicates by identifier (last row wins).
     * - Returns a numerically indexed array for stable JSON/storage output.
     *
     * @param array<mixed> $rows
     * @return array<int, array<string, mixed>>
     */
    private function normalizeMeasuresList(array $rows): array
    {
        $normalized = [];

        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }

            // Let the DTO validate and normalize the row structure.
            $dto = VulnerabilityMeasureRowDto::fromArray($row);
            if ($dto === null) {
                continue;
            }

            // De-duplicate by identifier; last write wins.
            $normalized[$dto->getIdentifier()] = $dto->toArray();
        }

        return array_values($normalized);
    }
}
