<?php

namespace App\Support\Providers\TargetScope;

use App\Models\ProviderConnection;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\Providers\Capabilities\ProviderCapabilityEvaluator;
use App\Support\Providers\Capabilities\ProviderCapabilityResult;
use App\Support\Providers\ProviderConsentStatus;
use App\Support\Providers\ProviderVerificationStatus;

final class ProviderConnectionSurfaceSummary
{
    /**
     * @param  list<ProviderIdentityContextMetadata>  $contextualIdentityDetails
     */
    public function __construct(
        public readonly string $provider,
        public readonly ProviderConnectionTargetScopeDescriptor $targetScope,
        public readonly string $consentState,
        public readonly string $verificationState,
        public readonly string $readinessSummary,
        public readonly array $contextualIdentityDetails = [],
        public readonly bool $isEnabled = true,
        public readonly array $providerCapabilities = [],
        public readonly ?array $primaryProviderCapability = null,
    ) {}

    public static function forConnection(ProviderConnection $connection): self
    {
        /** @var ProviderConnectionTargetScopeNormalizer $normalizer */
        $normalizer = app(ProviderConnectionTargetScopeNormalizer::class);
        $targetScope = $normalizer->descriptorForConnection($connection);
        $consentState = self::stateValue($connection->consent_status);
        $verificationState = self::stateValue($connection->verification_status);
        $providerCapabilities = self::providerCapabilitiesForConnection($connection);
        $primaryProviderCapability = self::primaryProviderCapability($providerCapabilities);

        return new self(
            provider: trim((string) $connection->provider),
            targetScope: $targetScope,
            consentState: $consentState,
            verificationState: $verificationState,
            readinessSummary: self::readinessSummary(
                isEnabled: (bool) $connection->is_enabled,
                consentState: $consentState,
                verificationState: $verificationState,
            ),
            contextualIdentityDetails: $normalizer->contextualIdentityDetailsForConnection($connection),
            isEnabled: (bool) $connection->is_enabled,
            providerCapabilities: $providerCapabilities,
            primaryProviderCapability: $primaryProviderCapability,
        );
    }

    public function targetScopeSummary(): string
    {
        return $this->targetScope->summary();
    }

    public function contextualIdentityLine(): ?string
    {
        if ($this->contextualIdentityDetails === []) {
            return null;
        }

        return collect($this->contextualIdentityDetails)
            ->map(fn (ProviderIdentityContextMetadata $detail): string => sprintf('%s: %s', $detail->detailLabel, $detail->detailValue))
            ->implode("\n");
    }

    public function providerCapabilitySummary(): string
    {
        if (! is_array($this->primaryProviderCapability)) {
            return 'Provider capabilities not evaluated';
        }

        $label = (string) ($this->primaryProviderCapability['label'] ?? 'Provider capability');
        $status = (string) ($this->primaryProviderCapability['status'] ?? 'unknown');
        $statusLabel = BadgeRenderer::spec(BadgeDomain::ProviderCapabilityStatus, $status)->label;

        return "{$label}: {$statusLabel}";
    }

    /**
     * @return array{
     *     provider: string,
     *     target_scope: array<string, string>,
     *     consent_state: string,
     *     verification_state: string,
     *     readiness_summary: string,
     *     target_scope_summary: string,
     *     provider_context: array{provider: string, details: list<array<string, string>>},
     *     contextual_identity_line: ?string,
     *     is_enabled: bool,
     *     provider_capabilities: array<int, array<string, mixed>>,
     *     primary_provider_capability: ?array<string, mixed>,
     *     provider_capability_summary: string
     * }
     */
    public function toArray(): array
    {
        return [
            'provider' => $this->provider,
            'target_scope' => $this->targetScope->toArray(),
            'consent_state' => $this->consentState,
            'verification_state' => $this->verificationState,
            'readiness_summary' => $this->readinessSummary,
            'target_scope_summary' => $this->targetScopeSummary(),
            'provider_context' => $this->providerContext(),
            'contextual_identity_line' => $this->contextualIdentityLine(),
            'is_enabled' => $this->isEnabled,
            'provider_capabilities' => $this->providerCapabilities,
            'primary_provider_capability' => $this->primaryProviderCapability,
            'provider_capability_summary' => $this->providerCapabilitySummary(),
        ];
    }

    /**
     * @return array{provider: string, details: list<array<string, string>>}
     */
    public function providerContext(): array
    {
        return [
            'provider' => $this->provider,
            'details' => array_map(
                static fn (ProviderIdentityContextMetadata $detail): array => $detail->toArray(),
                $this->contextualIdentityDetails,
            ),
        ];
    }

    private static function stateValue(mixed $state): string
    {
        if ($state instanceof ProviderConsentStatus || $state instanceof ProviderVerificationStatus) {
            return $state->value;
        }

        return trim((string) $state);
    }

    private static function readinessSummary(bool $isEnabled, string $consentState, string $verificationState): string
    {
        if (! $isEnabled) {
            return 'Disabled';
        }

        if ($consentState !== ProviderConsentStatus::Granted->value) {
            return sprintf(
                'Consent %s',
                strtolower(BadgeRenderer::spec(BadgeDomain::ProviderConsentStatus, $consentState)->label),
            );
        }

        return match ($verificationState) {
            ProviderVerificationStatus::Healthy->value => 'Ready',
            ProviderVerificationStatus::Degraded->value => 'Ready with warnings',
            ProviderVerificationStatus::Blocked->value => 'Verification blocked',
            ProviderVerificationStatus::Error->value => 'Verification failed',
            ProviderVerificationStatus::Pending->value => 'Verification pending',
            default => 'Verification not run',
        };
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private static function providerCapabilitiesForConnection(ProviderConnection $connection): array
    {
        try {
            /** @var ProviderCapabilityEvaluator $evaluator */
            $evaluator = app(ProviderCapabilityEvaluator::class);

            return array_map(
                static fn (ProviderCapabilityResult $result): array => $result->toArray(),
                $evaluator->evaluateForConnection($connection),
            );
        } catch (\Throwable) {
            return [];
        }
    }

    /**
     * @param  array<int, array<string, mixed>>  $capabilities
     * @return array<string, mixed>|null
     */
    private static function primaryProviderCapability(array $capabilities): ?array
    {
        if ($capabilities === []) {
            return null;
        }

        usort($capabilities, static function (array $a, array $b): int {
            $aStatus = (string) ($a['status'] ?? 'unknown');
            $bStatus = (string) ($b['status'] ?? 'unknown');

            $aPriority = match ($aStatus) {
                'blocked' => 0,
                'missing' => 1,
                'unknown' => 2,
                'supported' => 3,
                default => 4,
            };
            $bPriority = match ($bStatus) {
                'blocked' => 0,
                'missing' => 1,
                'unknown' => 2,
                'supported' => 3,
                default => 4,
            };

            return $aPriority <=> $bPriority;
        });

        return $capabilities[0];
    }
}
