<?php

declare(strict_types=1);

use App\Filament\Pages\Workspaces\ManagedEnvironmentOnboardingWizard;
use App\Models\AuditLog;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentPermission;
use App\Models\User;
use App\Models\WorkspaceMembership;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Providers\ProviderReasonCodes;
use App\Support\Verification\VerificationReportWriter;
use App\Support\Workspaces\WorkspaceContext;
use Livewire\Livewire;

function assistConfiguredPermissionKeys(): array
{
    $configured = array_merge(
        config('intune_permissions.permissions', []),
        config('entra_permissions.permissions', []),
    );

    return array_values(array_filter(array_map(static function (mixed $permission): ?string {
        if (! is_array($permission)) {
            return null;
        }

        $key = $permission['key'] ?? null;

        return is_string($key) && trim($key) !== '' ? trim($key) : null;
    }, $configured)));
}

function seedAssistPermissionInventory(
    ManagedEnvironment $tenant,
    ?string $missingKey = null,
    ?int $staleDays = null,
    array $errorKeys = [],
): void {
    foreach (assistConfiguredPermissionKeys() as $key) {
        if ($missingKey !== null && $key === $missingKey) {
            continue;
        }

        ManagedEnvironmentPermission::query()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'permission_key' => $key,
            'status' => in_array($key, $errorKeys, true) ? 'error' : 'granted',
            'details' => in_array($key, $errorKeys, true) ? ['reason_code' => 'permission_denied'] : ['source' => 'db'],
            'last_checked_at' => $staleDays === null ? now() : now()->subDays($staleDays),
        ]);
    }
}

/**
 * @return array{0:User,1:ManagedEnvironment,2:\App\Models\ManagedEnvironmentOnboardingSession,3:ProviderConnection,4:OperationRun,5:?string}
 */
function createVerificationAssistDraft(
    string $state = 'blocked',
    string $workspaceRole = 'owner',
    string $tenantRole = 'owner',
    bool $staleVerificationRun = false,
): array {
    [$user, $tenant] = createUserWithTenant(
        role: $tenantRole,
        workspaceRole: $workspaceRole,
        ensureDefaultMicrosoftProviderConnection: false,
    );

    $workspace = $tenant->workspace()->firstOrFail();

    $verifiedConnection = ProviderConnection::factory()->platform()->consentGranted()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => (string) $tenant->managed_environment_id,
        'display_name' => 'Verified connection',
        'is_default' => true,
        'consent_status' => 'granted',
    ]);

    $selectedConnection = $verifiedConnection;

    if ($staleVerificationRun) {
        $selectedConnection = ProviderConnection::factory()->platform()->consentGranted()->create([
            'workspace_id' => (int) $workspace->getKey(),
            'managed_environment_id' => (int) $tenant->getKey(),
            'provider' => 'dummy',
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'display_name' => 'Current selected connection',
            'is_default' => false,
            'consent_status' => 'granted',
        ]);
    }

    $allPermissionKeys = assistConfiguredPermissionKeys();
    $missingKey = $allPermissionKeys[0] ?? null;
    $errorKeys = [];
    $staleDays = null;
    $check = [];
    $outcome = OperationRunOutcome::Succeeded->value;

    if ($state === 'blocked') {
        seedAssistPermissionInventory($tenant, missingKey: $missingKey);

        $check = [
            'key' => 'permissions.admin_consent',
            'title' => 'Required application permissions',
            'status' => 'fail',
            'severity' => 'critical',
            'blocking' => true,
            'reason_code' => ProviderReasonCodes::ProviderPermissionMissing,
            'message' => 'Missing required Graph permissions.',
            'evidence' => [],
            'next_steps' => [],
        ];

        $outcome = OperationRunOutcome::Blocked->value;
    } elseif ($state === 'needs_attention') {
        seedAssistPermissionInventory($tenant, staleDays: 45);

        $check = [
            'key' => 'permissions.admin_consent',
            'title' => 'Required application permissions',
            'status' => 'warn',
            'severity' => 'medium',
            'blocking' => false,
            'reason_code' => ProviderReasonCodes::ProviderPermissionRefreshFailed,
            'message' => 'Stored permission data needs review.',
            'evidence' => [],
            'next_steps' => [],
        ];
    } elseif ($state === 'degraded') {
        $errorKeys = array_slice($allPermissionKeys, 0, 1);
        seedAssistPermissionInventory($tenant, staleDays: 45, errorKeys: $errorKeys);

        $check = [
            'key' => 'permissions.admin_consent',
            'title' => 'Required application permissions',
            'status' => 'warn',
            'severity' => 'medium',
            'blocking' => false,
            'reason_code' => ProviderReasonCodes::ProviderPermissionRefreshFailed,
            'message' => 'Stored permission data needs review.',
            'evidence' => [],
            'next_steps' => [],
        ];
    } else {
        seedAssistPermissionInventory($tenant);

        $check = [
            'key' => 'provider.connection.check',
            'title' => 'Provider connection check',
            'status' => 'pass',
            'severity' => 'info',
            'blocking' => false,
            'reason_code' => 'ok',
            'message' => 'Connection is healthy.',
            'evidence' => [],
            'next_steps' => [],
        ];
    }

    $run = OperationRun::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'type' => 'provider.connection.check',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => $outcome,
        'context' => [
            'provider_connection_id' => (int) $verifiedConnection->getKey(),
            'target_scope' => [
                'entra_tenant_id' => (string) $tenant->managed_environment_id,
                'entra_tenant_name' => (string) $tenant->name,
            ],
            'verification_report' => VerificationReportWriter::build('provider.connection.check', [$check]),
        ],
    ]);

    $draft = createOnboardingDraft([
        'workspace' => $workspace,
        'tenant' => $tenant,
        'started_by' => $user,
        'updated_by' => $user,
        'current_step' => 'verify',
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'environment_name' => (string) $tenant->name,
            'provider_connection_id' => (int) $selectedConnection->getKey(),
            'verification_operation_run_id' => (int) $run->getKey(),
        ],
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    return [$user, $tenant, $draft, $selectedConnection, $run, $missingKey];
}

it('shows the assist trigger for blocked and needs-attention states and hides it when verification is ready', function (string $state, bool $shouldSeeTrigger): void {
    [$user, , $draft] = createVerificationAssistDraft($state);

    $component = Livewire::actingAs($user)
        ->test(ManagedEnvironmentOnboardingWizard::class, ['onboardingDraft' => (int) $draft->getKey()]);

    if ($shouldSeeTrigger) {
        $component->assertActionVisible('wizardVerificationRequiredPermissionsAssist');

        return;
    }

    $component->assertActionHidden('wizardVerificationRequiredPermissionsAssist');
})->with([
    'blocked' => ['blocked', true],
    'needs attention' => ['needs_attention', true],
    'ready' => ['ready', false],
]);

it('opens and closes the assist slideover without changing the verify step', function (): void {
    [$user, , $draft] = createVerificationAssistDraft('blocked');

    $existingRunCount = OperationRun::query()->count();
    $existingAuditCount = AuditLog::query()->count();

    session()->put(WorkspaceContext::SESSION_KEY, (int) $user->last_workspace_id);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentOnboardingWizard::class, ['onboardingDraft' => (int) $draft->getKey()])
        ->mountAction('wizardVerificationRequiredPermissionsAssist')
        ->assertMountedActionModalSee('Required permissions assist')
        ->assertMountedActionModalSee('Open full page')
        ->unmountAction();

    expect($draft->fresh()?->current_step)->toBe('verify')
        ->and(OperationRun::query()->count())->toBe($existingRunCount)
        ->and(AuditLog::query()->count())->toBe($existingAuditCount);
});

it('renders summary metadata and missing application permissions in the assist slideover', function (): void {
    [$user, , $draft, , , $missingKey] = createVerificationAssistDraft('blocked');

    session()->put(WorkspaceContext::SESSION_KEY, (int) $user->last_workspace_id);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentOnboardingWizard::class, ['onboardingDraft' => (int) $draft->getKey()])
        ->mountAction('wizardVerificationRequiredPermissionsAssist')
        ->assertMountedActionModalSee('Missing application permissions')
        ->assertMountedActionModalSee('Copy missing application permissions')
        ->assertMountedActionModalSee((string) $missingKey)
        ->assertMountedActionModalDontSee('Copy missing delegated permissions');
});

it('renders degraded fallback and hides unavailable copy actions when stored detail is incomplete', function (): void {
    [$user, , $draft] = createVerificationAssistDraft('degraded', staleVerificationRun: true);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $user->last_workspace_id);

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentOnboardingWizard::class, ['onboardingDraft' => (int) $draft->getKey()])
        ->mountAction('wizardVerificationRequiredPermissionsAssist')
        ->assertMountedActionModalSee('Verification result is stale')
        ->assertMountedActionModalSee('Stored permission data needs refresh')
        ->assertMountedActionModalSee('Compact detail is incomplete')
        ->assertMountedActionModalDontSee('Copy missing application permissions')
        ->assertMountedActionModalDontSee('Copy missing delegated permissions');
});

it('returns 404 for workspace members who are out of scope for the tenant assist surface', function (): void {
    [$authorizedUser, $tenant, $draft] = createVerificationAssistDraft('blocked');

    $workspace = $tenant->workspace()->firstOrFail();
    $outOfScopeUser = User::factory()->create();

    WorkspaceMembership::query()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'user_id' => (int) $outOfScopeUser->getKey(),
        'role' => 'owner',
    ]);
    createUserWithTenant(
        tenant: ManagedEnvironment::factory()->create(['workspace_id' => (int) $workspace->getKey()]),
        user: $outOfScopeUser,
        role: 'owner',
    );

    $this->actingAs($outOfScopeUser)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]))
        ->assertNotFound();
});
