<?php

declare(strict_types=1);

namespace App\Support\Verification;

use App\Models\OperationRun;
use App\Support\OpsUx\RunFailureSanitizer;
use App\Support\Providers\ProviderReasonCodes;

final class BlockedVerificationReportFactory
{
    /**
     * @return array<int, array<string, mixed>>
     */
    public static function checks(OperationRun $run): array
    {
        $context = is_array($run->context ?? null) ? $run->context : [];

        $reasonCode = self::normalizedReasonCode($context['reason_code'] ?? null);
        $message = self::blockedMessage($run);

        $nextSteps = $context['next_steps'] ?? [];
        $nextSteps = VerificationReportSanitizer::sanitizeNextStepsPayload($nextSteps);

        return [[
            'key' => 'provider.connection.check',
            'title' => 'Provider connection preflight',
            'status' => 'fail',
            'severity' => 'critical',
            'blocking' => true,
            'reason_code' => $reasonCode,
            'message' => $message,
            'evidence' => self::evidence($run, $context),
            'next_steps' => $nextSteps,
        ]];
    }

    /**
     * @return array<string, mixed>
     */
    public static function identity(OperationRun $run): array
    {
        $context = is_array($run->context ?? null) ? $run->context : [];

        $identity = [];

        $providerConnectionId = $context['provider_connection_id'] ?? null;
        if (is_numeric($providerConnectionId)) {
            $identity['provider_connection_id'] = (int) $providerConnectionId;
        }

        $targetScope = $context['target_scope'] ?? [];
        $targetScope = is_array($targetScope) ? $targetScope : [];

        $targetScopeIdentifier = self::targetScopeIdentifier($targetScope);
        if ($targetScopeIdentifier !== null) {
            $identity['target_scope'] = self::targetScopeIdentity($targetScope);
        } else {
            $entraTenantId = $targetScope['entra_tenant_id'] ?? null;
            if (is_string($entraTenantId) && trim($entraTenantId) !== '') {
                $identity['entra_tenant_id'] = trim($entraTenantId);
            }
        }

        $connectionType = $context['connection_type'] ?? ($targetScope['connection_type'] ?? ($context['identity']['connection_type'] ?? null));
        if (is_string($connectionType) && trim($connectionType) !== '') {
            $identity['connection_type'] = trim($connectionType);
        }

        $effectiveClientId = $context['identity']['effective_client_id'] ?? null;
        if (is_string($effectiveClientId) && trim($effectiveClientId) !== '') {
            $identity['effective_client_id'] = trim($effectiveClientId);
        }

        $credentialSource = $context['identity']['credential_source'] ?? null;
        if (is_string($credentialSource) && trim($credentialSource) !== '') {
            $identity['credential_source'] = trim($credentialSource);
        }

        return $identity;
    }

    private static function normalizedReasonCode(mixed $reasonCode): string
    {
        if (! is_string($reasonCode)) {
            return ProviderReasonCodes::UnknownError;
        }

        return RunFailureSanitizer::normalizeReasonCode($reasonCode);
    }

    private static function blockedMessage(OperationRun $run): string
    {
        $failures = is_array($run->failure_summary ?? null) ? $run->failure_summary : [];
        $firstFailure = $failures[0] ?? null;

        if (is_array($firstFailure) && is_string($firstFailure['message'] ?? null) && trim((string) $firstFailure['message']) !== '') {
            return trim((string) $firstFailure['message']);
        }

        return match (self::normalizedReasonCode(($run->context['reason_code'] ?? null))) {
            ProviderReasonCodes::PlatformIdentityMissing => 'Platform app identity is not configured.',
            ProviderReasonCodes::PlatformIdentityIncomplete => 'Platform app identity is incomplete.',
            ProviderReasonCodes::DedicatedCredentialMissing => 'Dedicated connection credentials are missing.',
            ProviderReasonCodes::DedicatedCredentialInvalid => 'Dedicated connection credentials are invalid.',
            ProviderReasonCodes::ProviderConsentFailed => 'Admin consent failed. Retry admin consent before verification can proceed.',
            ProviderReasonCodes::ProviderConsentRevoked => 'Admin consent was revoked. Grant admin consent again before verification can proceed.',
            default => 'Operation blocked due to provider configuration.',
        };
    }

    /**
     * @param  array<string, mixed>  $context
     * @return array<int, array{kind: string, value: int|string}>
     */
    private static function evidence(OperationRun $run, array $context): array
    {
        $evidence = [];

        $providerConnectionId = $context['provider_connection_id'] ?? null;
        if (is_numeric($providerConnectionId)) {
            $evidence[] = [
                'kind' => 'provider_connection_id',
                'value' => (int) $providerConnectionId,
            ];
        }

        $targetScope = $context['target_scope'] ?? [];
        $targetScope = is_array($targetScope) ? $targetScope : [];

        $targetScopeIdentifier = self::targetScopeIdentifier($targetScope);
        if ($targetScopeIdentifier !== null) {
            $evidence[] = [
                'kind' => 'target_scope_identifier',
                'value' => $targetScopeIdentifier,
            ];
        } else {
            $entraTenantId = $targetScope['entra_tenant_id'] ?? null;
            if (is_string($entraTenantId) && trim($entraTenantId) !== '') {
                $evidence[] = [
                    'kind' => 'entra_tenant_id',
                    'value' => trim($entraTenantId),
                ];
            }
        }

        $connectionType = $context['connection_type'] ?? ($targetScope['connection_type'] ?? ($context['identity']['connection_type'] ?? null));
        if (is_string($connectionType) && trim($connectionType) !== '') {
            $evidence[] = [
                'kind' => 'connection_type',
                'value' => trim($connectionType),
            ];
        }

        $credentialSource = $context['identity']['credential_source'] ?? null;
        if (is_string($credentialSource) && trim($credentialSource) !== '') {
            $evidence[] = [
                'kind' => 'credential_source',
                'value' => trim($credentialSource),
            ];
        }

        $effectiveClientId = $context['identity']['effective_client_id'] ?? null;
        if (is_string($effectiveClientId) && trim($effectiveClientId) !== '') {
            $evidence[] = [
                'kind' => 'app_id',
                'value' => trim($effectiveClientId),
            ];
        }

        $evidence[] = [
            'kind' => 'operation_run_id',
            'value' => (int) $run->getKey(),
        ];

        return $evidence;
    }

    /**
     * @param  array<string, mixed>  $targetScope
     */
    private static function targetScopeIdentifier(array $targetScope): ?string
    {
        $scopeIdentifier = $targetScope['scope_identifier'] ?? null;

        return is_string($scopeIdentifier) && trim($scopeIdentifier) !== ''
            ? trim($scopeIdentifier)
            : null;
    }

    /**
     * @param  array<string, mixed>  $targetScope
     * @return array<string, string>
     */
    private static function targetScopeIdentity(array $targetScope): array
    {
        $identity = [];

        foreach (['provider', 'scope_kind', 'scope_identifier', 'scope_display_name'] as $key) {
            $value = $targetScope[$key] ?? null;

            if (is_string($value) && trim($value) !== '') {
                $identity[$key] = trim($value);
            }
        }

        return $identity;
    }
}
