<?php

declare(strict_types=1);

namespace App\Services\Baselines\SnapshotRendering;

use Illuminate\Support\Str;

enum FidelityState: string
{
    case Full = 'full';
    case Partial = 'partial';
    case ReferenceOnly = 'reference_only';
    case Unsupported = 'unsupported';

    public static function fromEvidence(mixed $value, bool $usesFallback = false): self
    {
        $normalized = Str::of((string) ($value ?? ''))
            ->trim()
            ->lower()
            ->replace(['-', ' '], '_')
            ->toString();

        return match ($normalized) {
            'content', 'full' => self::Full,
            'partial' => self::Partial,
            'meta', 'metadata_only', 'reference_only' => self::ReferenceOnly,
            'unsupported' => self::Unsupported,
            default => $usesFallback ? self::Unsupported : self::Partial,
        };
    }

    /**
     * @param  array<string, mixed>  $summary
     */
    public static function fromSummary(array $summary, bool $hasItems): self
    {
        if (! $hasItems) {
            return self::Unsupported;
        }

        $counts = is_array($summary['fidelity_counts'] ?? null)
            ? $summary['fidelity_counts']
            : [];

        $content = is_numeric($counts['content'] ?? null) ? (int) $counts['content'] : 0;
        $meta = is_numeric($counts['meta'] ?? null) ? (int) $counts['meta'] : 0;

        if ($content > 0 && $meta === 0) {
            return self::Full;
        }

        if ($content > 0 && $meta > 0) {
            return self::Partial;
        }

        if ($meta > 0) {
            return self::ReferenceOnly;
        }

        return self::Unsupported;
    }

    /**
     * @param  array<int, self>  $states
     */
    public static function aggregate(array $states): self
    {
        if ($states === []) {
            return self::Unsupported;
        }

        $worst = self::Full;

        foreach ($states as $state) {
            if ($state->rank() < $worst->rank()) {
                $worst = $state;
            }
        }

        return $worst;
    }

    public function label(): string
    {
        return match ($this) {
            self::Full => 'Full',
            self::Partial => 'Partial',
            self::ReferenceOnly => 'Reference only',
            self::Unsupported => 'Unsupported',
        };
    }

    public function coverageHint(): ?string
    {
        return match ($this) {
            self::Full => null,
            self::Partial => 'Mixed evidence detail is available for this group.',
            self::ReferenceOnly => 'Metadata-only evidence is available for this group.',
            self::Unsupported => 'Support is limited for this policy type. Fallback rendering is being used.',
        };
    }

    private function rank(): int
    {
        return match ($this) {
            self::Full => 4,
            self::Partial => 3,
            self::ReferenceOnly => 2,
            self::Unsupported => 1,
        };
    }
}
