<?php

namespace App\Models;

use App\Support\Providers\ProviderConnectionType;
use App\Support\Providers\ProviderConsentStatus;
use App\Support\Providers\ProviderReasonCodes;
use App\Support\Providers\ProviderVerificationStatus;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;

class ProviderConnection extends Model
{
    use HasFactory;

    protected $guarded = [];

    protected $casts = [
        'is_default' => 'boolean',
        'is_enabled' => 'boolean',
        'connection_type' => ProviderConnectionType::class,
        'consent_status' => ProviderConsentStatus::class,
        'consent_granted_at' => 'datetime',
        'consent_last_checked_at' => 'datetime',
        'verification_status' => ProviderVerificationStatus::class,
        'migration_review_required' => 'boolean',
        'migration_reviewed_at' => 'datetime',
        'scopes_granted' => 'array',
        'metadata' => 'array',
        'last_health_check_at' => 'datetime',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(ManagedEnvironment::class, 'managed_environment_id');
    }

    public function workspace(): BelongsTo
    {
        return $this->belongsTo(Workspace::class);
    }

    public function credential(): HasOne
    {
        return $this->hasOne(ProviderCredential::class, 'provider_connection_id');
    }

    public function makeDefault(): void
    {
        DB::transaction(function (): void {
            static::query()
                ->where('managed_environment_id', $this->managed_environment_id)
                ->where('provider', $this->provider)
                ->where('is_default', true)
                ->whereKeyNot($this->getKey())
                ->update(['is_default' => false]);

            static::query()
                ->whereKey($this->getKey())
                ->update(['is_default' => true]);
        });

        $this->refresh();
    }

    /**
     * @return array{
     *   legacy_identity_classification_source: ?string,
     *   legacy_identity_review_required: bool,
     *   legacy_identity_result: ?string,
     *   legacy_identity_signals: array<string, mixed>,
     *   legacy_identity_classified_at: ?string,
     *   effective_app: array{app_id: ?string, source: string}
     * }
     */
    public function legacyIdentityMetadata(): array
    {
        $metadata = is_array($this->metadata) ? $this->metadata : [];
        $effectiveApp = Arr::get($metadata, 'effective_app');

        return [
            'legacy_identity_classification_source' => is_string($metadata['legacy_identity_classification_source'] ?? null)
                ? $metadata['legacy_identity_classification_source']
                : null,
            'legacy_identity_review_required' => (bool) ($metadata['legacy_identity_review_required'] ?? $this->migration_review_required),
            'legacy_identity_result' => is_string($metadata['legacy_identity_result'] ?? null)
                ? $metadata['legacy_identity_result']
                : null,
            'legacy_identity_signals' => is_array($metadata['legacy_identity_signals'] ?? null)
                ? $metadata['legacy_identity_signals']
                : [],
            'legacy_identity_classified_at' => is_string($metadata['legacy_identity_classified_at'] ?? null)
                ? $metadata['legacy_identity_classified_at']
                : null,
            'effective_app' => [
                'app_id' => is_array($effectiveApp) && filled($effectiveApp['app_id'] ?? null)
                    ? (string) $effectiveApp['app_id']
                    : null,
                'source' => is_array($effectiveApp) && filled($effectiveApp['source'] ?? null)
                    ? (string) $effectiveApp['source']
                    : $this->defaultEffectiveAppSource(),
            ],
        ];
    }

    /**
     * @return array{app_id: ?string, source: string}
     */
    public function effectiveAppMetadata(): array
    {
        $metadata = $this->legacyIdentityMetadata();
        $effectiveApp = $metadata['effective_app'];

        if ($effectiveApp['app_id'] !== null || $effectiveApp['source'] === 'review_required') {
            return $effectiveApp;
        }

        if ($this->connection_type === ProviderConnectionType::Dedicated) {
            $payload = $this->credential?->payload;
            $clientId = is_array($payload) ? trim((string) ($payload['client_id'] ?? '')) : '';

            return [
                'app_id' => $clientId !== '' ? $clientId : null,
                'source' => 'dedicated_credential',
            ];
        }

        $platformClientId = trim((string) config('graph.client_id'));

        return [
            'app_id' => $platformClientId !== '' ? $platformClientId : null,
            'source' => 'platform_config',
        ];
    }

    public function effectiveAppId(): ?string
    {
        return $this->effectiveAppMetadata()['app_id'];
    }

    public function requiresMigrationReview(): bool
    {
        return $this->legacyIdentityMetadata()['legacy_identity_review_required'];
    }

    /**
     * @return array<string, mixed>
     */
    public function classificationProjection(
        \App\Services\Providers\ProviderConnectionClassificationResult $result,
    ): array {
        $metadata = array_merge(
            is_array($this->metadata) ? $this->metadata : [],
            $result->metadata(),
            ['legacy_identity_classified_at' => now()->toJSON()],
        );

        $projection = [
            'connection_type' => $result->suggestedConnectionType->value,
            'migration_review_required' => $result->reviewRequired,
            'metadata' => $metadata,
        ];

        if ($result->reviewRequired) {
            return $projection + [
                'verification_status' => ProviderVerificationStatus::Blocked->value,
                'last_error_reason_code' => ProviderReasonCodes::ProviderConnectionReviewRequired,
                'last_error_message' => 'Legacy provider connection requires explicit migration review.',
                'migration_reviewed_at' => null,
            ];
        }

        $currentVerificationStatus = $this->verification_status;
        $currentReasonCode = is_string($this->last_error_reason_code) ? $this->last_error_reason_code : null;

        if (
            ($this->migration_review_required || $currentReasonCode === ProviderReasonCodes::ProviderConnectionReviewRequired)
            && $currentVerificationStatus === ProviderVerificationStatus::Blocked
        ) {
            $currentVerificationStatus = ProviderVerificationStatus::Unknown;
        }

        if (
            $this->migration_review_required
            || $currentReasonCode === ProviderReasonCodes::ProviderConnectionReviewRequired
        ) {
            return $projection + [
                'verification_status' => $currentVerificationStatus instanceof ProviderVerificationStatus
                    ? $currentVerificationStatus->value
                    : $currentVerificationStatus,
                'last_error_reason_code' => $currentReasonCode === ProviderReasonCodes::ProviderConnectionReviewRequired
                    ? null
                    : $currentReasonCode,
                'last_error_message' => $currentReasonCode === ProviderReasonCodes::ProviderConnectionReviewRequired
                    ? null
                    : $this->last_error_message,
            ];
        }

        return $projection;
    }

    private function defaultEffectiveAppSource(): string
    {
        if ($this->connection_type === ProviderConnectionType::Dedicated) {
            return 'dedicated_credential';
        }

        return 'platform_config';
    }
}
