<?php

declare(strict_types=1);

namespace App\Support\Baselines;

use InvalidArgumentException;

final readonly class BaselineCompareSummaryAssessment
{
    public const string STATE_POSITIVE = 'positive';

    public const string STATE_CAUTION = 'caution';

    public const string STATE_STALE = 'stale';

    public const string STATE_ACTION_REQUIRED = 'action_required';

    public const string STATE_UNAVAILABLE = 'unavailable';

    public const string STATE_IN_PROGRESS = 'in_progress';

    public const string EVIDENCE_NONE = 'none';

    public const string EVIDENCE_COVERAGE_WARNING = 'coverage_warning';

    public const string EVIDENCE_EVIDENCE_GAP = 'evidence_gap';

    public const string EVIDENCE_STALE_RESULT = 'stale_result';

    public const string EVIDENCE_SUPPRESSED_OUTPUT = 'suppressed_output';

    public const string EVIDENCE_UNAVAILABLE = 'unavailable';

    public const string NEXT_TARGET_LANDING = 'landing';

    public const string NEXT_TARGET_FINDINGS = 'findings';

    public const string NEXT_TARGET_RUN = 'run';

    public const string NEXT_TARGET_NONE = 'none';

    /**
     * @param  array{label: string, target: string}  $nextAction
     */
    public function __construct(
        public string $stateFamily,
        public string $headline,
        public ?string $supportingMessage,
        public string $tone,
        public bool $positiveClaimAllowed,
        public string $trustworthinessLevel,
        public string $evaluationResult,
        public string $evidenceImpact,
        public int $findingsVisibleCount,
        public int $highSeverityCount,
        public array $nextAction,
        public ?string $lastComparedLabel = null,
        public ?string $reasonCode = null,
        public int $overdueOpenFindingsCount = 0,
        public int $expiringGovernanceCount = 0,
        public int $lapsedGovernanceCount = 0,
    ) {
        if (! in_array($this->stateFamily, [
            self::STATE_POSITIVE,
            self::STATE_CAUTION,
            self::STATE_STALE,
            self::STATE_ACTION_REQUIRED,
            self::STATE_UNAVAILABLE,
            self::STATE_IN_PROGRESS,
        ], true)) {
            throw new InvalidArgumentException('Unsupported baseline summary state family: '.$this->stateFamily);
        }

        if (trim($this->headline) === '') {
            throw new InvalidArgumentException('Baseline summary assessments require a headline.');
        }

        if (! in_array($this->evidenceImpact, [
            self::EVIDENCE_NONE,
            self::EVIDENCE_COVERAGE_WARNING,
            self::EVIDENCE_EVIDENCE_GAP,
            self::EVIDENCE_STALE_RESULT,
            self::EVIDENCE_SUPPRESSED_OUTPUT,
            self::EVIDENCE_UNAVAILABLE,
        ], true)) {
            throw new InvalidArgumentException('Unsupported baseline summary evidence impact: '.$this->evidenceImpact);
        }

        if (! in_array($this->nextAction['target'] ?? null, [
            self::NEXT_TARGET_LANDING,
            self::NEXT_TARGET_FINDINGS,
            self::NEXT_TARGET_RUN,
            self::NEXT_TARGET_NONE,
        ], true)) {
            throw new InvalidArgumentException('Unsupported baseline summary next-action target.');
        }

        if (trim((string) ($this->nextAction['label'] ?? '')) === '') {
            throw new InvalidArgumentException('Baseline summary assessments require a next-action label.');
        }

        if ($this->positiveClaimAllowed && $this->stateFamily !== self::STATE_POSITIVE) {
            throw new InvalidArgumentException('Positive claim eligibility must resolve to the positive summary state.');
        }
    }

    public function nextActionLabel(): string
    {
        return $this->nextAction['label'];
    }

    public function nextActionTarget(): string
    {
        return $this->nextAction['target'];
    }

    /**
     * @return array{
     *     stateFamily: string,
     *     headline: string,
     *     supportingMessage: ?string,
     *     tone: string,
     *     positiveClaimAllowed: bool,
     *     trustworthinessLevel: string,
     *     evaluationResult: string,
     *     evidenceImpact: string,
     *     findingsVisibleCount: int,
     *     highSeverityCount: int,
     *     nextAction: array{label: string, target: string},
     *     lastComparedLabel: ?string,
     *     reasonCode: ?string,
     *     overdueOpenFindingsCount: int,
     *     expiringGovernanceCount: int,
     *     lapsedGovernanceCount: int
     * }
     */
    public function toArray(): array
    {
        return [
            'stateFamily' => $this->stateFamily,
            'headline' => $this->headline,
            'supportingMessage' => $this->supportingMessage,
            'tone' => $this->tone,
            'positiveClaimAllowed' => $this->positiveClaimAllowed,
            'trustworthinessLevel' => $this->trustworthinessLevel,
            'evaluationResult' => $this->evaluationResult,
            'evidenceImpact' => $this->evidenceImpact,
            'findingsVisibleCount' => $this->findingsVisibleCount,
            'highSeverityCount' => $this->highSeverityCount,
            'nextAction' => $this->nextAction,
            'lastComparedLabel' => $this->lastComparedLabel,
            'reasonCode' => $this->reasonCode,
            'overdueOpenFindingsCount' => $this->overdueOpenFindingsCount,
            'expiringGovernanceCount' => $this->expiringGovernanceCount,
            'lapsedGovernanceCount' => $this->lapsedGovernanceCount,
        ];
    }
}
