<?php

namespace App\Support\Providers;

use App\Support\Governance\PlatformVocabularyGlossary;
use App\Support\ReasonTranslation\PlatformReasonFamily;
use App\Support\ReasonTranslation\ReasonOwnershipDescriptor;

final class ProviderReasonCodes
{
    public const string ProviderConnectionMissing = 'provider_connection_missing';

    public const string ProviderConnectionInvalid = 'provider_connection_invalid';

    public const string ProviderCredentialMissing = 'provider_credential_missing';

    public const string ProviderCredentialInvalid = 'provider_credential_invalid';

    public const string ProviderConnectionTypeInvalid = 'provider_connection_type_invalid';

    public const string PlatformIdentityMissing = 'platform_identity_missing';

    public const string PlatformIdentityIncomplete = 'platform_identity_incomplete';

    public const string DedicatedCredentialMissing = 'dedicated_credential_missing';

    public const string DedicatedCredentialInvalid = 'dedicated_credential_invalid';

    public const string ProviderConsentMissing = 'provider_consent_missing';

    public const string ProviderConsentFailed = 'provider_consent_failed';

    public const string ProviderConsentRevoked = 'provider_consent_revoked';

    public const string ProviderConnectionReviewRequired = 'provider_connection_review_required';

    public const string ProviderBindingUnsupported = 'provider_binding_unsupported';

    public const string ProviderAuthFailed = 'provider_auth_failed';

    public const string ProviderPermissionMissing = 'provider_permission_missing';

    public const string ProviderPermissionDenied = 'provider_permission_denied';

    public const string ProviderPermissionRefreshFailed = 'provider_permission_refresh_failed';

    public const string IntuneRbacPermissionMissing = 'intune_rbac.permission_missing';

    public const string TenantTargetMismatch = 'tenant_target_mismatch';

    public const string NetworkUnreachable = 'network_unreachable';

    public const string RateLimited = 'rate_limited';

    public const string UnknownError = 'unknown_error';

    public const string IntuneRbacNotConfigured = 'intune_rbac.not_configured';

    public const string IntuneRbacUnhealthy = 'intune_rbac.unhealthy';

    public const string IntuneRbacStale = 'intune_rbac.stale';

    /**
     * @return array<int, string>
     */
    public static function all(): array
    {
        return [
            self::ProviderConnectionMissing,
            self::ProviderConnectionInvalid,
            self::ProviderCredentialMissing,
            self::ProviderCredentialInvalid,
            self::ProviderConnectionTypeInvalid,
            self::PlatformIdentityMissing,
            self::PlatformIdentityIncomplete,
            self::DedicatedCredentialMissing,
            self::DedicatedCredentialInvalid,
            self::ProviderConsentMissing,
            self::ProviderConsentFailed,
            self::ProviderConsentRevoked,
            self::ProviderConnectionReviewRequired,
            self::ProviderBindingUnsupported,
            self::ProviderAuthFailed,
            self::ProviderPermissionMissing,
            self::ProviderPermissionDenied,
            self::ProviderPermissionRefreshFailed,
            self::IntuneRbacPermissionMissing,
            self::TenantTargetMismatch,
            self::NetworkUnreachable,
            self::RateLimited,
            self::UnknownError,
            self::IntuneRbacNotConfigured,
            self::IntuneRbacUnhealthy,
            self::IntuneRbacStale,
        ];
    }

    public static function isKnown(string $reasonCode): bool
    {
        return in_array($reasonCode, self::all(), true) || str_starts_with($reasonCode, 'ext.');
    }

    public static function registryKey(): string
    {
        return 'provider_reason_codes';
    }

    /**
     * @return list<string>
     */
    public static function canonicalNouns(): array
    {
        return ['reason_code'];
    }

    public static function ownerLayer(string $reasonCode): string
    {
        return PlatformVocabularyGlossary::OWNER_PROVIDER_OWNED;
    }

    public static function boundaryClassification(string $reasonCode): string
    {
        return PlatformVocabularyGlossary::BOUNDARY_INTUNE_SPECIFIC;
    }

    public static function ownerNamespace(string $reasonCode): string
    {
        return str_starts_with($reasonCode, 'intune_rbac.')
            ? 'provider.intune_rbac'
            : 'provider.microsoft_graph';
    }

    public static function platformReasonFamily(string $reasonCode): PlatformReasonFamily
    {
        return match ($reasonCode) {
            self::ProviderPermissionMissing,
            self::ProviderPermissionDenied,
            self::IntuneRbacPermissionMissing => PlatformReasonFamily::Authorization,
            self::NetworkUnreachable,
            self::RateLimited,
            self::ProviderPermissionRefreshFailed,
            self::ProviderAuthFailed => PlatformReasonFamily::Availability,
            self::ProviderConnectionTypeInvalid,
            self::TenantTargetMismatch,
            self::ProviderBindingUnsupported,
            self::ProviderConnectionReviewRequired => PlatformReasonFamily::Compatibility,
            default => PlatformReasonFamily::Prerequisite,
        };
    }

    public static function ownershipDescriptor(string $reasonCode): ?ReasonOwnershipDescriptor
    {
        if (! self::isKnown($reasonCode)) {
            return null;
        }

        return new ReasonOwnershipDescriptor(
            ownerLayer: self::ownerLayer($reasonCode),
            ownerNamespace: self::ownerNamespace($reasonCode),
            reasonCode: $reasonCode,
            platformReasonFamily: self::platformReasonFamily($reasonCode),
        );
    }
}
