<?php

declare(strict_types=1);

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

use ReallySimplePlugins\RSS\Core\Support\Helpers\Storage;

/**
 * Immutable data transfer object representing a vulnerability snapshot summary.
 *
 * A snapshot captures the aggregated vulnerability state of the system at a
 * specific point in time. It is used to:
 * - Compare the current state against a previously stored snapshot.
 * - Decide whether notifications should be sent (via policy logic).
 * - Persist historical state for idempotent scheduled runs.
 *
 * This DTO contains data only:
 * - No business logic
 * - No persistence logic
 * - No scheduling concerns
 */
final class VulnerabilitySnapshotDto
{
    /**
     * Highest severity label present in the snapshot (or null if none).
     */
    private ?string $highestSeverity;

    /**
     * Normalized numeric severity score used for comparisons.
     */
    private int $severityScore;

    /**
     * Total number of vulnerable components.
     */
    private int $vulnerableCount;

    /**
     * Number of vulnerable components with updates available.
     */
    private int $updatableComponents;

    /**
     * UNIX timestamp when the snapshot was generated.
     */
    private int $generatedAt;

    public function __construct(
        ?string $highestSeverity,
        int $severityScore,
        int $vulnerableCount,
        int $updatableComponents,
        int $generatedAt
    ) {
        $this->highestSeverity = $highestSeverity;
        $this->severityScore = $severityScore;
        $this->vulnerableCount = $vulnerableCount;
        $this->updatableComponents = $updatableComponents;
        $this->generatedAt = $generatedAt;
    }

    /**
     * Returns the highest severity label present in the snapshot (or null if none).
     */
    public function getHighestSeverity(): ?string
    {
        return $this->highestSeverity;
    }

    /**
     * Returns the normalized numeric severity score used for comparisons.
     */
    public function getSeverityScore(): int
    {
        return $this->severityScore;
    }

    /**
     * Returns the total number of vulnerable components.
     */
    public function getVulnerableCount(): int
    {
        return $this->vulnerableCount;
    }

    /**
     * Returns the number of vulnerable components with updates available.
     */
    public function getUpdatableComponents(): int
    {
        return $this->updatableComponents;
    }

    /**
     * Returns the UNIX timestamp when the snapshot was generated.
     */
    public function getGeneratedAt(): int
    {
        return $this->generatedAt;
    }

    /**
     * Returns an array representation of the snapshot intended for persistence (options/storage).
     *
     * The array shape is stable and versioned implicitly by the DTO.
     *
     * @return array{
     *     highestSeverity: ?string,
     *     severityScore: int,
     *     vulnerableCount: int,
     *     updatableComponents: int,
     *     generatedAt: int
     * }
     */
    public function toArray(): array
    {
        return [
            'highestSeverity' => $this->highestSeverity,
            'severityScore' => $this->severityScore,
            'vulnerableCount' => $this->vulnerableCount,
            'updatableComponents' => $this->updatableComponents,
            'generatedAt' => $this->generatedAt,
        ];
    }

    /**
     * Rebuilds a snapshot DTO from persisted storage.
     *
     * Missing keys are handled defensively via the Storage helper.
     *
     * @param array<string, mixed> $data
     */
    public static function fromArray(array $data): self
    {
        $storage = new Storage($data);
        return new self(
            $storage->getString('highestSeverity'),
            $storage->getInt('severityScore'),
            $storage->getInt('vulnerableCount'),
            $storage->getInt('updatableComponents'),
            $storage->getInt('generatedAt'),
        );
    }
}
