<?php

declare(strict_types=1);

namespace App\Support\Ui\OperatorExplanation;

use App\Support\Badges\BadgeCatalog;
use App\Support\Badges\BadgeDomain;
use App\Support\ReasonTranslation\ReasonResolutionEnvelope;
use App\Support\Ui\GovernanceArtifactTruth\ArtifactTruthEnvelope;

final class OperatorExplanationBuilder
{
    /**
     * @return array{
     *     primaryReason: string,
     *     nextActionText: string,
     *     diagnosticsAvailable: bool,
     *     diagnosticsSummary: ?string
     * }
     */
    public function compressionSummaryInputs(ArtifactTruthEnvelope $truth): array
    {
        $explanation = $truth->operatorExplanation ?? $this->fromArtifactTruthEnvelope($truth);
        $primaryReason = $this->firstNonEmpty(
            $explanation->dominantCauseExplanation,
            $truth->primaryExplanation,
            $explanation->reliabilityStatement,
            $explanation->coverageStatement,
            'Detailed context is available for this artifact.',
        );
        $diagnosticsSummary = $this->firstNonEmpty(
            $explanation->diagnosticsSummary,
            $truth->diagnosticLabel !== null
                ? 'Supporting diagnostics remain available below the primary summary.'
                : null,
        );

        return [
            'primaryReason' => $primaryReason,
            'nextActionText' => $this->firstNonEmpty(
                $explanation->nextActionText,
                $truth->nextStepText(),
            ),
            'diagnosticsAvailable' => $explanation->diagnosticsAvailable || $truth->diagnosticLabel !== null,
            'diagnosticsSummary' => $diagnosticsSummary,
        ];
    }

    /**
     * @param  array<int, CountDescriptor>  $countDescriptors
     */
    public function build(
        ExplanationFamily $family,
        string $headline,
        string $executionOutcome,
        string $executionOutcomeLabel,
        string $evaluationResult,
        TrustworthinessLevel $trustworthinessLevel,
        string $reliabilityStatement,
        ?string $coverageStatement,
        ?string $dominantCauseCode,
        ?string $dominantCauseLabel,
        ?string $dominantCauseExplanation,
        string $nextActionCategory,
        string $nextActionText,
        array $countDescriptors = [],
        bool $diagnosticsAvailable = false,
        ?string $diagnosticsSummary = null,
    ): OperatorExplanationPattern {
        return new OperatorExplanationPattern(
            family: $family,
            headline: $headline,
            executionOutcome: $executionOutcome,
            executionOutcomeLabel: $executionOutcomeLabel,
            evaluationResult: $evaluationResult,
            trustworthinessLevel: $trustworthinessLevel,
            reliabilityStatement: $reliabilityStatement,
            coverageStatement: $coverageStatement,
            dominantCauseCode: $dominantCauseCode,
            dominantCauseLabel: $dominantCauseLabel,
            dominantCauseExplanation: $dominantCauseExplanation,
            nextActionCategory: $nextActionCategory,
            nextActionText: $nextActionText,
            countDescriptors: $countDescriptors,
            diagnosticsAvailable: $diagnosticsAvailable,
            diagnosticsSummary: $diagnosticsSummary,
        );
    }

    /**
     * @param  array<int, CountDescriptor>  $countDescriptors
     */
    public function fromArtifactTruthEnvelope(
        ArtifactTruthEnvelope $truth,
        array $countDescriptors = [],
    ): OperatorExplanationPattern {
        $reason = $truth->reason?->toReasonResolutionEnvelope();
        $family = $this->familyForTruth($truth, $reason);
        $trustworthiness = $this->trustworthinessForTruth($truth, $reason);
        $evaluationResult = $this->evaluationResultForTruth($truth, $family);
        $executionOutcome = $this->executionOutcomeKey($truth->executionOutcome);
        $executionOutcomeLabel = $this->executionOutcomeLabel($truth->executionOutcome);
        $dominantCauseCode = $reason?->internalCode;
        $dominantCauseLabel = $reason?->operatorLabel ?? $truth->primaryLabel;
        $dominantCauseExplanation = $reason?->shortExplanation ?? $truth->primaryExplanation;
        $headline = $this->headlineForTruth($truth, $family, $trustworthiness);
        $reliabilityStatement = $this->reliabilityStatementForTruth($truth, $trustworthiness);
        $coverageStatement = $this->coverageStatementForTruth($truth, $reason);
        $nextActionText = $truth->nextStepText();
        $nextActionCategory = $this->nextActionCategory($truth->actionability, $reason);
        $diagnosticsAvailable = $truth->reason !== null
            || $truth->diagnosticLabel !== null
            || $countDescriptors !== [];

        return $this->build(
            family: $family,
            headline: $headline,
            executionOutcome: $executionOutcome,
            executionOutcomeLabel: $executionOutcomeLabel,
            evaluationResult: $evaluationResult,
            trustworthinessLevel: $trustworthiness,
            reliabilityStatement: $reliabilityStatement,
            coverageStatement: $coverageStatement,
            dominantCauseCode: $dominantCauseCode,
            dominantCauseLabel: $dominantCauseLabel,
            dominantCauseExplanation: $dominantCauseExplanation,
            nextActionCategory: $nextActionCategory,
            nextActionText: $nextActionText,
            countDescriptors: $countDescriptors,
            diagnosticsAvailable: $diagnosticsAvailable,
            diagnosticsSummary: $diagnosticsAvailable
                ? 'Technical truth detail remains available below the primary explanation.'
                : null,
        );
    }

    private function familyForTruth(
        ArtifactTruthEnvelope $truth,
        ?ReasonResolutionEnvelope $reason,
    ): ExplanationFamily {
        return match (true) {
            $reason?->absencePattern === 'suppressed_output' => ExplanationFamily::SuppressedOutput,
            $reason?->absencePattern === 'blocked_prerequisite' => ExplanationFamily::BlockedPrerequisite,
            $truth->executionOutcome === 'pending' || $truth->artifactExistence === 'not_created' && $truth->actionability !== 'required' => ExplanationFamily::InProgress,
            $truth->executionOutcome === 'failed' || $truth->executionOutcome === 'blocked' => ExplanationFamily::BlockedPrerequisite,
            $truth->artifactExistence === 'created_but_not_usable' || $truth->contentState === 'missing_input' => ExplanationFamily::MissingInput,
            $truth->contentState === 'trusted' && $truth->freshnessState === 'current' && $truth->actionability === 'none' && $truth->primaryLabel === 'Trustworthy artifact' => ExplanationFamily::TrustworthyResult,
            $truth->contentState === 'trusted' && $truth->freshnessState === 'current' && $truth->actionability === 'none' => ExplanationFamily::NoIssuesDetected,
            $truth->artifactExistence === 'historical_only' => ExplanationFamily::Unavailable,
            default => ExplanationFamily::CompletedButLimited,
        };
    }

    private function trustworthinessForTruth(
        ArtifactTruthEnvelope $truth,
        ?ReasonResolutionEnvelope $reason,
    ): TrustworthinessLevel {
        if ($reason?->trustImpact !== null) {
            return TrustworthinessLevel::tryFrom($reason->trustImpact) ?? TrustworthinessLevel::LimitedConfidence;
        }

        return match (true) {
            $truth->artifactExistence === 'created_but_not_usable',
            $truth->contentState === 'missing_input',
            $truth->executionOutcome === 'failed',
            $truth->executionOutcome === 'blocked' => TrustworthinessLevel::Unusable,
            $truth->supportState === 'limited_support',
            in_array($truth->contentState, ['reference_only', 'unsupported'], true) => TrustworthinessLevel::DiagnosticOnly,
            $truth->contentState === 'trusted' && $truth->freshnessState === 'current' && $truth->actionability === 'none' => TrustworthinessLevel::Trustworthy,
            default => TrustworthinessLevel::LimitedConfidence,
        };
    }

    private function evaluationResultForTruth(
        ArtifactTruthEnvelope $truth,
        ExplanationFamily $family,
    ): string {
        return match ($family) {
            ExplanationFamily::TrustworthyResult => 'full_result',
            ExplanationFamily::NoIssuesDetected => 'no_result',
            ExplanationFamily::SuppressedOutput => 'suppressed_result',
            ExplanationFamily::MissingInput,
            ExplanationFamily::BlockedPrerequisite,
            ExplanationFamily::Unavailable => 'unavailable',
            ExplanationFamily::InProgress => 'unavailable',
            ExplanationFamily::CompletedButLimited => 'incomplete_result',
        };
    }

    private function executionOutcomeKey(?string $executionOutcome): string
    {
        $normalized = BadgeCatalog::normalizeState($executionOutcome);

        return match ($normalized) {
            'queued', 'running', 'pending' => 'in_progress',
            'partially_succeeded' => 'completed_with_follow_up',
            'blocked' => 'blocked',
            'failed' => 'failed',
            default => 'completed',
        };
    }

    private function executionOutcomeLabel(?string $executionOutcome): string
    {
        if (! is_string($executionOutcome) || trim($executionOutcome) === '') {
            return 'Completed';
        }

        $spec = BadgeCatalog::spec(BadgeDomain::OperationRunOutcome, $executionOutcome);

        return $spec->label !== 'Unknown' ? $spec->label : ucfirst(str_replace('_', ' ', trim($executionOutcome)));
    }

    private function headlineForTruth(
        ArtifactTruthEnvelope $truth,
        ExplanationFamily $family,
        TrustworthinessLevel $trustworthiness,
    ): string {
        return match ($family) {
            ExplanationFamily::TrustworthyResult => 'The result is ready to use.',
            ExplanationFamily::NoIssuesDetected => 'No follow-up was detected from this result.',
            ExplanationFamily::SuppressedOutput => 'The run completed, but normal output was intentionally suppressed.',
            ExplanationFamily::MissingInput => 'The result exists, but missing inputs keep it from being decision-grade.',
            ExplanationFamily::BlockedPrerequisite => 'The workflow did not produce a usable result because a prerequisite blocked it.',
            ExplanationFamily::InProgress => 'The result is still being prepared.',
            ExplanationFamily::Unavailable => 'A result is not currently available for this surface.',
            ExplanationFamily::CompletedButLimited => match ($trustworthiness) {
                TrustworthinessLevel::DiagnosticOnly => 'The result is available for diagnostics, not for a final decision.',
                TrustworthinessLevel::LimitedConfidence => 'The result is available, but it should be read with caution.',
                TrustworthinessLevel::Unusable => 'The result is not reliable enough to use as-is.',
                default => 'The result completed with operator follow-up.',
            },
        };
    }

    private function reliabilityStatementForTruth(
        ArtifactTruthEnvelope $truth,
        TrustworthinessLevel $trustworthiness,
    ): string {
        return match ($trustworthiness) {
            TrustworthinessLevel::Trustworthy => 'Trustworthiness is high for the intended operator task.',
            TrustworthinessLevel::LimitedConfidence => $truth->primaryExplanation
                ?? 'Trustworthiness is limited because coverage, freshness, or publication readiness still need review.',
            TrustworthinessLevel::DiagnosticOnly => 'This output is suitable for diagnostics only and should not be treated as the final answer.',
            TrustworthinessLevel::Unusable => 'This output is not reliable enough to support the intended operator action yet.',
        };
    }

    private function coverageStatementForTruth(
        ArtifactTruthEnvelope $truth,
        ?ReasonResolutionEnvelope $reason,
    ): ?string {
        return match (true) {
            $truth->contentState === 'trusted' && $truth->freshnessState === 'current' => 'Coverage and artifact quality are sufficient for the default reading path.',
            $truth->freshnessState === 'stale' => 'The artifact exists, but freshness limits how confidently it should be used.',
            $truth->contentState === 'partial' => 'Coverage is incomplete, so the visible output should be treated as partial.',
            $truth->contentState === 'missing_input' => $reason?->shortExplanation ?? 'Required inputs were missing or unusable when this result was assembled.',
            in_array($truth->contentState, ['reference_only', 'unsupported'], true) => 'Only reduced-fidelity support is available for this result.',
            $truth->publicationReadiness === 'blocked' => 'The artifact exists, but it is still blocked from the intended downstream use.',
            default => null,
        };
    }

    private function nextActionCategory(
        string $actionability,
        ?ReasonResolutionEnvelope $reason,
    ): string {
        if ($reason?->actionability === 'retryable_transient') {
            return 'retry_later';
        }

        return match ($actionability) {
            'none' => 'none',
            'optional' => 'review_evidence_gaps',
            default => $reason?->actionability === 'prerequisite_missing'
                ? 'fix_prerequisite'
                : 'manual_validate',
        };
    }

    private function firstNonEmpty(?string ...$values): string
    {
        foreach ($values as $value) {
            if (! is_string($value)) {
                continue;
            }

            $normalized = trim((string) preg_replace('/\s+/', ' ', $value));

            if ($normalized !== '') {
                return $normalized;
            }
        }

        return 'No detail available.';
    }
}
