<?php

declare(strict_types=1);

use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentPermission;
use App\Models\User;
use App\Models\Workspace;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Verification\VerificationReportWriter;
use App\Support\Workspaces\WorkspaceContext;

pest()->browser()->timeout(10_000);

it('keeps stale verification warnings and the selected provider connection stable after refresh', function (): void {
    $workspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => '30303030-3030-3030-3030-303030303030',
        'name' => 'Stale Verification ManagedEnvironment',
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ]);
    $user = User::factory()->create(['name' => 'Verification Owner']);

    createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: 'owner',
        workspaceRole: 'owner',
        ensureDefaultMicrosoftProviderConnection: false,
    );

    $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' => 'Previously verified connection',
        'is_default' => true,
        'consent_status' => 'granted',
    ]);

    $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',
    ]);

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

    $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(),
        ],
    ]);

    $this->actingAs($user)->withSession([
        WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
    ]);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    $page = visit(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]));

    $page
        ->assertNoJavaScriptErrors()
        ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
        ->assertSee('Verify access')
        ->assertSee('Status: Needs attention')
        ->assertSee('The selected provider connection has changed since this verification operation. Start verification again to validate the current connection.')
        ->assertSee('Start verification')
        ->refresh()
        ->waitForText('The selected provider connection has changed since this verification operation. Start verification again to validate the current connection.')
        ->assertNoJavaScriptErrors()
        ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
        ->assertSee('Status: Needs attention')
        ->assertSee('Start verification')
        ->click('Select an existing connection or create a new one.')
        ->assertSee('Edit selected connection');
});

it('preserves bootstrap revisit state and blocked activation guards after refresh', function (): void {
    $workspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => '40404040-4040-4040-4040-404040404040',
        'name' => 'Blocked Review ManagedEnvironment',
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ]);
    $user = User::factory()->create(['name' => 'Review Owner']);

    createUserWithTenant(
        tenant: $tenant,
        user: $user,
        role: 'owner',
        workspaceRole: 'owner',
        ensureDefaultMicrosoftProviderConnection: false,
    );

    $connection = 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' => 'Blocked review connection',
        'is_default' => true,
        'consent_status' => 'granted',
    ]);

    $verificationRun = OperationRun::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'type' => 'provider.connection.check',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
            'target_scope' => [
                'entra_tenant_id' => (string) $tenant->managed_environment_id,
                'entra_tenant_name' => (string) $tenant->name,
            ],
            'verification_report' => VerificationReportWriter::build('provider.connection.check', [
                [
                    'key' => 'permissions.admin_consent',
                    'title' => 'Required application permissions',
                    'status' => 'fail',
                    'severity' => 'critical',
                    'blocking' => true,
                    'reason_code' => 'permission_denied',
                    'message' => 'Missing required Graph permissions.',
                    'evidence' => [],
                    'next_steps' => [],
                ],
            ]),
        ],
    ]);

    $bootstrapRun = createInventorySyncOperationRun($tenant, [
        'workspace_id' => (int) $workspace->getKey(),
        'status' => 'success',
    ]);

    $draft = createOnboardingDraft([
        'workspace' => $workspace,
        'tenant' => $tenant,
        'started_by' => $user,
        'updated_by' => $user,
        'current_step' => 'complete',
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'environment_name' => (string) $tenant->name,
            'provider_connection_id' => (int) $connection->getKey(),
            'verification_operation_run_id' => (int) $verificationRun->getKey(),
            'bootstrap_operation_types' => ['inventory_sync'],
            'bootstrap_operation_runs' => [
                'inventory_sync' => (int) $bootstrapRun->getKey(),
            ],
        ],
    ]);

    $this->actingAs($user)->withSession([
        WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
    ]);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    $page = visit(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]));

    $page
        ->assertNoJavaScriptErrors()
        ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
        ->assertSee('Verify access')
        ->assertSee('Status: Blocked')
        ->assertSee('View required permissions')
        ->refresh()
        ->waitForText('View required permissions')
        ->assertNoJavaScriptErrors()
        ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
        ->assertSee('Status: Blocked')
        ->assertSee('View required permissions');
});

it('opens the full-page permissions deep dive in a new tab without replacing onboarding', function (): void {
    [$user, $tenant] = createUserWithTenant(
        role: 'owner',
        ensureDefaultMicrosoftProviderConnection: false,
    );

    $tenant->forceFill([
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ])->save();

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

    $configured = array_merge(
        config('intune_permissions.permissions', []),
        config('entra_permissions.permissions', []),
    );

    $permissionKeys = 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)));

    if ($permissionKeys === []) {
        test()->markTestSkipped('No configured required permissions found.');
    }

    $missingKey = $permissionKeys[0];

    foreach (array_slice($permissionKeys, 1) as $key) {
        ManagedEnvironmentPermission::query()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $workspace->getKey(),
            'permission_key' => $key,
            'status' => 'granted',
            'details' => ['source' => 'db'],
            'last_checked_at' => now(),
        ]);
    }

    $connection = 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' => 'Browser assist connection',
        'is_default' => true,
        'consent_status' => 'granted',
    ]);

    $run = OperationRun::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'type' => 'provider.connection.check',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
            'target_scope' => [
                'entra_tenant_id' => (string) $tenant->managed_environment_id,
                'entra_tenant_name' => (string) $tenant->name,
            ],
            'verification_report' => VerificationReportWriter::build('provider.connection.check', [
                [
                    'key' => 'permissions.admin_consent',
                    'title' => 'Required application permissions',
                    'status' => 'fail',
                    'severity' => 'critical',
                    'blocking' => true,
                    'reason_code' => 'permission_denied',
                    'message' => 'Missing required Graph permissions.',
                    'evidence' => [],
                    'next_steps' => [],
                ],
            ]),
        ],
    ]);

    $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) $connection->getKey(),
            'verification_operation_run_id' => (int) $run->getKey(),
        ],
    ]);

    $this->actingAs($user)->withSession([
        WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
    ]);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    $page = visit(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]));

    $page->script(<<<'JS'
document.querySelectorAll('.fi-sc-wizard-header-step-btn')[2]?.click();
JS);

    $page
        ->assertNoJavaScriptErrors()
        ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
        ->wait(1)
        ->assertScript("document.querySelector('[data-testid=\"contextual-help-link-open-required-permissions\"]') !== null", true)
        ->assertAttribute('[data-testid="contextual-help-link-open-required-permissions"]', 'target', '_blank')
        ->assertAttribute('[data-testid="contextual-help-link-open-required-permissions"]', 'rel', 'noopener noreferrer')
        ->click('[data-testid="contextual-help-link-open-required-permissions"]')
        ->wait(1)
        ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
        ->click('Select an existing connection or create a new one.')
        ->assertSee('Edit selected connection');
});

it('opens the permissions assist from report remediation steps without leaving onboarding', function (): void {
    [$user, $tenant] = createUserWithTenant(
        role: 'owner',
        ensureDefaultMicrosoftProviderConnection: false,
    );

    $tenant->forceFill([
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ])->save();

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

    $configured = array_merge(
        config('intune_permissions.permissions', []),
        config('entra_permissions.permissions', []),
    );

    $permissionKeys = 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)));

    if ($permissionKeys === []) {
        test()->markTestSkipped('No configured required permissions found.');
    }

    foreach (array_slice($permissionKeys, 1) as $key) {
        ManagedEnvironmentPermission::query()->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $workspace->getKey(),
            'permission_key' => $key,
            'status' => 'granted',
            'details' => ['source' => 'db'],
            'last_checked_at' => now(),
        ]);
    }

    $connection = 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' => 'Browser next-step connection',
        'is_default' => true,
        'consent_status' => 'granted',
    ]);

    $run = OperationRun::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'type' => 'provider.connection.check',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Failed->value,
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
            'target_scope' => [
                'entra_tenant_id' => (string) $tenant->managed_environment_id,
                'entra_tenant_name' => (string) $tenant->name,
            ],
            'verification_report' => VerificationReportWriter::build('provider.connection.check', [
                [
                    'key' => 'provider.connection.preflight',
                    'title' => 'Provider connection preflight',
                    'status' => 'fail',
                    'severity' => 'critical',
                    'blocking' => true,
                    'reason_code' => 'permission_denied',
                    'message' => 'Provider connection requires admin consent before use.',
                    'evidence' => [],
                    'next_steps' => [
                        [
                            'label' => 'Grant admin consent',
                            'url' => 'https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/grant-admin-consent',
                        ],
                        [
                            'label' => 'Review platform connection',
                            'url' => route('filament.admin.resources.provider-connections.edit', ['tenant' => $tenant->external_id, 'record' => (int) $connection->getKey()]),
                        ],
                    ],
                ],
            ]),
        ],
    ]);

    $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) $connection->getKey(),
            'verification_operation_run_id' => (int) $run->getKey(),
        ],
    ]);

    $this->actingAs($user)->withSession([
        WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
    ]);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    $page = visit(route('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()]));

    $page->script(<<<'JS'
document.querySelectorAll('.fi-sc-wizard-header-step-btn')[2]?.click();
JS);

    $page
        ->assertNoJavaScriptErrors()
        ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
        ->wait(1)
        ->assertScript("document.querySelector('[data-testid=\"verification-next-step-grant-admin-consent\"]') !== null", true)
        ->click('[data-testid="verification-next-step-grant-admin-consent"]')
        ->assertScript("document.querySelector('[data-testid=\"verification-assist-root\"]') !== null", true)
        ->assertRoute('admin.onboarding.draft', ['onboardingDraft' => (int) $draft->getKey()])
        ->assertAttribute('[data-testid="verification-assist-full-page"]', 'target', '_blank')
        ->assertSee('Use the existing Start verification action in this step after reviewing changes.');
});
