<?php

declare(strict_types=1);

use App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard;
use App\Models\Tenant;
use App\Models\TenantOnboardingSession;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\Workspaces\WorkspaceContext;
use Livewire\Livewire;

it('returns 404 for non-members when starting onboarding with a selected workspace', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

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

    $this->actingAs($user)
        ->get('/admin/onboarding')
        ->assertNotFound();
});

it('allows workspace members without onboarding capability to view the wizard but forbids execution', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'readonly',
    ]);

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

    $this->actingAs($user)
        ->get('/admin/onboarding')
        ->assertSuccessful();

    Livewire::actingAs($user)
        ->test(ManagedTenantOnboardingWizard::class)
        ->call('identifyManagedTenant', [
            'entra_tenant_id' => '11111111-1111-1111-1111-111111111111',
            'environment' => 'prod',
            'name' => 'Acme',
        ])
        ->assertStatus(403);

    expect(Tenant::query()->count())->toBe(0);
    expect(TenantOnboardingSession::query()->count())->toBe(0);
});

it('renders onboarding wizard for workspace owners and allows identifying a managed tenant', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

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

    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());
    $this->actingAs($user)
        ->get('/admin/onboarding')
        ->assertSuccessful();

    $entraTenantId = '22222222-2222-2222-2222-222222222222';

    Livewire::actingAs($user)
        ->test(ManagedTenantOnboardingWizard::class)
        ->call('identifyManagedTenant', [
            'entra_tenant_id' => $entraTenantId,
            'environment' => 'prod',
            'name' => 'Acme',
            'primary_domain' => 'acme.example',
            'notes' => 'Initial onboarding',
        ]);

    $tenant = Tenant::query()->where('tenant_id', $entraTenantId)->firstOrFail();

    expect((int) $tenant->workspace_id)->toBe((int) $workspace->getKey());
    expect($tenant->status)->toBe(Tenant::STATUS_ONBOARDING);

    $this->assertDatabaseHas('tenant_memberships', [
        'tenant_id' => (int) $tenant->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => 'owner',
    ]);

    $this->assertDatabaseHas('managed_tenant_onboarding_sessions', [
        'workspace_id' => (int) $workspace->getKey(),
        'tenant_id' => (int) $tenant->getKey(),
        'entra_tenant_id' => $entraTenantId,
        'current_step' => 'identify',
    ]);
});

it('initializes entangled wizard state keys to avoid Livewire entangle errors', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

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

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

    Livewire::actingAs($user)
        ->test(ManagedTenantOnboardingWizard::class)
        ->assertSet('data.notes', '')
        ->assertSet('data.override_blocked', false)
        ->assertSet('data.override_reason', '');
});

it('is idempotent when identifying the same Entra tenant ID twice', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

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

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

    $entraTenantId = '33333333-3333-3333-3333-333333333333';

    $component = Livewire::actingAs($user)->test(ManagedTenantOnboardingWizard::class);

    $component->call('identifyManagedTenant', [
        'entra_tenant_id' => $entraTenantId,
        'environment' => 'prod',
        'name' => 'Acme',
    ]);

    $component->call('identifyManagedTenant', [
        'entra_tenant_id' => $entraTenantId,
        'environment' => 'prod',
        'name' => 'Acme',
    ]);

    expect(Tenant::query()->where('tenant_id', $entraTenantId)->count())->toBe(1);
    expect(TenantOnboardingSession::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('entra_tenant_id', $entraTenantId)
        ->whereNull('completed_at')
        ->count())->toBe(1);
});

it('returns 404 and does not create anything when entra_tenant_id exists in another workspace', function (): void {
    $entraTenantId = '44444444-4444-4444-4444-444444444444';

    $workspaceA = Workspace::factory()->create();
    $workspaceB = Workspace::factory()->create();

    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $workspaceA->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => 'owner',
    ]);

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $workspaceB->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => 'owner',
    ]);

    Tenant::factory()->create([
        'workspace_id' => (int) $workspaceA->getKey(),
        'tenant_id' => $entraTenantId,
        'status' => Tenant::STATUS_ACTIVE,
    ]);

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

    Livewire::actingAs($user)
        ->test(ManagedTenantOnboardingWizard::class)
        ->call('identifyManagedTenant', [
            'entra_tenant_id' => $entraTenantId,
            'environment' => 'prod',
            'name' => 'Other Workspace',
        ])
        ->assertStatus(404);
});

it('returns 404 for legacy onboarding entry points', function (): void {
    $user = User::factory()->create();
    $this->actingAs($user);

    $this->get('/admin/register-tenant')->assertNotFound();
    $this->get('/admin/managed-tenants')->assertNotFound();
    $this->get('/admin/managed-tenants/onboarding')->assertNotFound();
    $this->get('/admin/new')->assertNotFound();
});

/*
|--------------------------------------------------------------------------
| Legacy onboarding suite (deprecated)
|--------------------------------------------------------------------------
|
| The remainder of this file previously contained an end-to-end onboarding
| suite that relied on deprecated routes and pre-enterprise state semantics.
| Spec 073 replaces it with focused coverage under tests/Feature/Onboarding
| and tests/Feature/Rbac.
|
| Keeping the legacy assertions around (commented) is intentional to avoid
| reintroducing removed routes or old semantics.


    $this->actingAs($user);

    $tenantGuid = '22222222-2222-2222-2222-222222222222';

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);

    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);
    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    expect(Tenant::query()->where('tenant_id', $tenantGuid)->count())->toBe(1);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    expect(TenantOnboardingSession::query()
        ->where('workspace_id', $workspace->getKey())
        ->where('tenant_id', $tenant->getKey())
        ->count())->toBe(1);

    $this->assertDatabaseHas('managed_tenant_onboarding_sessions', [
        'workspace_id' => (int) $workspace->getKey(),
        'tenant_id' => (int) $tenant->getKey(),
    ]);
});

it('returns 404 and does not create anything when tenant_id exists in another workspace', function (): void {
    $workspaceA = Workspace::factory()->create();
    $workspaceB = Workspace::factory()->create();

    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspaceB->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $tenantGuid = '33333333-3333-3333-3333-333333333333';

    Tenant::factory()->create([
        'workspace_id' => $workspaceA->getKey(),
        'tenant_id' => $tenantGuid,
        'name' => 'Acme',
        'status' => 'active',
    ]);

    $this->actingAs($user);

    Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspaceB])
        ->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme'])
        ->assertStatus(404);

    expect(Tenant::query()->where('tenant_id', $tenantGuid)->count())->toBe(1);

    expect(TenantOnboardingSession::query()
        ->where('workspace_id', $workspaceB->getKey())
        ->whereIn('tenant_id', Tenant::query()->where('tenant_id', $tenantGuid)->pluck('id'))
        ->count())->toBe(0);
});

it('binds an unscoped existing tenant to the current workspace when safe and allows identifying it', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $tenantGuid = '77777777-7777-7777-7777-777777777777';

    $tenant = Tenant::factory()->create([
        'workspace_id' => null,
        'tenant_id' => $tenantGuid,
        'name' => 'Acme',
        'status' => 'active',
    ]);

    \App\Models\TenantMembership::query()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => 'owner',
        'source' => 'manual',
        'created_by_user_id' => (int) $user->getKey(),
    ]);

    $this->assertDatabaseHas('tenants', [
        'id' => (int) $tenant->getKey(),
        'workspace_id' => null,
        'tenant_id' => $tenantGuid,
    ]);

    $this->assertDatabaseHas('tenant_memberships', [
        'tenant_id' => (int) $tenant->getKey(),
        'user_id' => (int) $user->getKey(),
    ]);

    $this->actingAs($user);

    Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace])
        ->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme'])
        ->assertOk();

    $this->assertDatabaseHas('tenants', [
        'id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $workspace->getKey(),
        'tenant_id' => $tenantGuid,
    ]);
});

it('auto-selects the default provider connection and allows switching', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $tenantGuid = '99999999-9999-9999-9999-999999999999';

    $tenant = Tenant::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'tenant_id' => $tenantGuid,
        'name' => 'Acme',
        'status' => 'pending',
    ]);

    $default = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => $tenantGuid,
        'display_name' => 'Default',
        'is_default' => true,
    ]);

    $other = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft_alt',
        'entra_tenant_id' => $tenantGuid,
        'display_name' => 'Other',
        'is_default' => false,
    ]);

    $this->actingAs($user);

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);

    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    $component->assertSet('selectedProviderConnectionId', (int) $default->getKey());

    $session = TenantOnboardingSession::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('tenant_id', (int) $tenant->getKey())
        ->firstOrFail();

    expect($session->state['provider_connection_id'] ?? null)->toBe((int) $default->getKey());

    $component->call('selectProviderConnection', (int) $other->getKey());
    $component->assertSet('selectedProviderConnectionId', (int) $other->getKey());

    $session->refresh();
    expect($session->state['provider_connection_id'] ?? null)->toBe((int) $other->getKey());
});

it('dedupes verification runs: starting verification twice returns the active run and dispatches only once', function (): void {
    Bus::fake();

    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $this->actingAs($user);

    $tenantGuid = '77777777-7777-7777-7777-777777777777';

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);
    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    $connection = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'is_default' => true,
    ]);

    $component->set('selectedProviderConnectionId', (int) $connection->getKey());

    $component->call('startVerification');
    $component->call('startVerification');

    expect(OperationRun::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->where('type', 'provider.connection.check')
        ->count())->toBe(1);

    Bus::assertDispatchedTimes(\App\Jobs\ProviderConnectionHealthCheckJob::class, 1);

    $this->assertDatabaseHas('audit_logs', [
        'workspace_id' => (int) $workspace->getKey(),
        'actor_id' => (int) $user->getKey(),
        'action' => 'managed_tenant_onboarding.verification_start',
        'resource_type' => 'operation_run',
    ]);

    $session = TenantOnboardingSession::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('tenant_id', (int) $tenant->getKey())
        ->firstOrFail();

    expect($session->state['verification_operation_run_id'] ?? null)->not->toBeNull();
});

it('creates a provider connection with encrypted credentials and does not persist secrets in session state', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $this->actingAs($user);

    $tenantGuid = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa';
    $secret = 'super-secret-123';

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);

    $component
        ->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme'])
        ->call('createProviderConnection', [
            'display_name' => 'Onboarding Connection',
            'client_id' => 'client-id-1',
            'client_secret' => $secret,
            'is_default' => true,
        ])
        ->assertDontSee($secret);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    $connection = ProviderConnection::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->where('provider', 'microsoft')
        ->where('entra_tenant_id', $tenantGuid)
        ->firstOrFail();

    expect($connection->credential)->toBeInstanceOf(ProviderCredential::class);
    expect($connection->credential->toArray())->not->toHaveKey('payload');

    $session = TenantOnboardingSession::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('tenant_id', (int) $tenant->getKey())
        ->firstOrFail();

    $state = $session->state ?? [];
    expect($state)->not->toHaveKey('client_id');
    expect($state)->not->toHaveKey('client_secret');
    expect($state['provider_connection_id'] ?? null)->toBe((int) $connection->getKey());
});

it('starts verification, creates an operation run, dispatches the job, and does not include secrets in run context', function (): void {
    Bus::fake();

    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $this->actingAs($user);

    $tenantGuid = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb';

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);
    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    $connection = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => $tenantGuid,
        'is_default' => true,
    ]);

    $component->set('selectedProviderConnectionId', (int) $connection->getKey());
    $component->call('startVerification');

    $run = OperationRun::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->where('type', 'provider.connection.check')
        ->latest('id')
        ->firstOrFail();

    expect($run->context)->toBeArray();
    expect($run->context['provider_connection_id'] ?? null)->toBe((int) $connection->getKey());
    expect($run->context)->not->toHaveKey('client_id');
    expect($run->context)->not->toHaveKey('client_secret');

    Bus::assertDispatched(\App\Jobs\ProviderConnectionHealthCheckJob::class);
});

it('can resume the latest onboarding session as a different authorized workspace member', function (): void {
    Bus::fake();

    $workspace = Workspace::factory()->create();

    $initiator = User::factory()->create();
    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $initiator->getKey(),
        'role' => 'owner',
    ]);

    $resumer = User::factory()->create();
    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $resumer->getKey(),
        'role' => 'manager',
    ]);

    $tenantGuid = 'cccccccc-cccc-cccc-cccc-cccccccccccc';

    $this->actingAs($initiator);

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);
    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    $connection = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => $tenantGuid,
        'is_default' => true,
    ]);

    $session = TenantOnboardingSession::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('tenant_id', (int) $tenant->getKey())
        ->firstOrFail();

    $session->update([
        'state' => array_merge($session->state ?? [], [
            'provider_connection_id' => (int) $connection->getKey(),
        ]),
    ]);

    $this->actingAs($resumer);

    Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace])
        ->call('startVerification');

    Bus::assertDispatched(\App\Jobs\ProviderConnectionHealthCheckJob::class);
});

it('completes onboarding only after verification succeeded and redirects to tenant dashboard', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $this->actingAs($user);

    $tenantGuid = 'dddddddd-dddd-dddd-dddd-dddddddddddd';

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);
    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    $connection = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => $tenantGuid,
        'is_default' => true,
    ]);

    $run = OperationRun::query()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'user_id' => (int) $user->getKey(),
        'initiator_name' => $user->name,
        'type' => 'provider.connection.check',
        'status' => 'completed',
        'outcome' => 'succeeded',
        'run_identity_hash' => sha1('verify-ok-'.(string) $connection->getKey()),
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
        ],
    ]);

    $session = TenantOnboardingSession::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('tenant_id', (int) $tenant->getKey())
        ->firstOrFail();

    $session->update([
        'state' => array_merge($session->state ?? [], [
            'provider_connection_id' => (int) $connection->getKey(),
            'verification_operation_run_id' => (int) $run->getKey(),
        ]),
    ]);

    $component
        ->call('completeOnboarding')
        ->assertRedirect(TenantDashboard::getUrl(tenant: $tenant));

    $tenant->refresh();
    expect($tenant->status)->toBe('active');

    $session->refresh();
    expect($session->completed_at)->not->toBeNull();
});

it('starts selected bootstrap actions as separate operation runs and dispatches their jobs', function (): void {
    Bus::fake();

    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $this->actingAs($user);

    $tenantGuid = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee';

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);
    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    $connection = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => $tenantGuid,
        'is_default' => true,
    ]);

    $verificationRun = OperationRun::query()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'user_id' => (int) $user->getKey(),
        'initiator_name' => $user->name,
        'type' => 'provider.connection.check',
        'status' => 'completed',
        'outcome' => 'succeeded',
        'run_identity_hash' => sha1('verify-ok-bootstrap-'.(string) $connection->getKey()),
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
        ],
    ]);

    $session = TenantOnboardingSession::query()
        ->where('workspace_id', (int) $workspace->getKey())
        ->where('tenant_id', (int) $tenant->getKey())
        ->firstOrFail();

    $session->update([
        'state' => array_merge($session->state ?? [], [
            'provider_connection_id' => (int) $connection->getKey(),
            'verification_operation_run_id' => (int) $verificationRun->getKey(),
        ]),
    ]);

    $component->call('startBootstrap', ['inventory_sync', 'compliance.snapshot']);

    Bus::assertDispatchedTimes(\App\Jobs\ProviderInventorySyncJob::class, 1);
    Bus::assertDispatchedTimes(\App\Jobs\ProviderComplianceSnapshotJob::class, 1);

    expect(OperationRun::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->whereIn('type', ['inventory_sync', 'compliance.snapshot'])
        ->count())->toBe(2);

    $session->refresh();
    $runs = $session->state['bootstrap_operation_runs'] ?? [];
    expect($runs)->toBeArray();
    expect($runs['inventory_sync'] ?? null)->toBeInt();
    expect($runs['compliance.snapshot'] ?? null)->toBeInt();
});

it('returns scope-busy semantics for verification when another run is active for the same connection scope', function (): void {
    Bus::fake();

    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $this->actingAs($user);

    $tenantGuid = '88888888-8888-8888-8888-888888888888';

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);
    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    $connection = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'is_default' => true,
    ]);

    OperationRun::query()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'user_id' => (int) $user->getKey(),
        'initiator_name' => $user->name,
        'type' => 'inventory_sync',
        'status' => 'queued',
        'outcome' => 'pending',
        'run_identity_hash' => sha1('busy-'.(string) $connection->getKey()),
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
        ],
    ]);

    $component->set('selectedProviderConnectionId', (int) $connection->getKey());

    $component->call('startVerification');

    expect(OperationRun::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->where('type', 'provider.connection.check')
        ->count())->toBe(0);

    Bus::assertNotDispatched(\App\Jobs\ProviderConnectionHealthCheckJob::class);
});

it('fails a stale queued verification run and allows starting a new verification run', function (): void {
    Bus::fake();

    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
    ]);

    $this->actingAs($user);

    $tenantGuid = '99999999-9999-9999-9999-999999999999';

    $component = Livewire::test(\App\Filament\Pages\Workspaces\ManagedTenantOnboardingWizard::class, ['workspace' => $workspace]);
    $component->call('identifyManagedTenant', ['tenant_id' => $tenantGuid, 'name' => 'Acme']);

    $tenant = Tenant::query()->where('tenant_id', $tenantGuid)->firstOrFail();

    $connection = ProviderConnection::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => $tenantGuid,
        'is_default' => true,
    ]);

    $staleRun = OperationRun::query()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $workspace->getKey(),
        'user_id' => (int) $user->getKey(),
        'initiator_name' => $user->name,
        'type' => 'provider.connection.check',
        'status' => 'queued',
        'outcome' => 'pending',
        'run_identity_hash' => sha1('stale-queued-verify-'.(string) $connection->getKey()),
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
        ],
        'created_at' => now()->subMinutes(10),
        'updated_at' => now()->subMinutes(10),
    ]);

    $component->set('selectedProviderConnectionId', (int) $connection->getKey());
    $component->call('startVerification');

    $staleRun->refresh();
    expect($staleRun->status)->toBe('completed');
    expect($staleRun->outcome)->toBe('failed');
    expect($staleRun->context)->toBeArray();
    expect($staleRun->context['verification_report'] ?? null)->toBeArray();

    $report = $staleRun->context['verification_report'] ?? null;
    expect($report['checks'] ?? null)->toBeArray();
    expect($report['checks'][0]['message'] ?? null)->toBe('Run was queued but never started. A queue worker may not be running.');

    $newRun = OperationRun::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->where('type', 'provider.connection.check')
        ->latest('id')
        ->firstOrFail();

    expect((int) $newRun->getKey())->not->toBe((int) $staleRun->getKey());

    Bus::assertDispatched(\App\Jobs\ProviderConnectionHealthCheckJob::class);
});

it('registers the onboarding capability in the canonical registry', function (): void {
    expect(Capabilities::isKnown(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD))->toBeTrue();
});

it('maps onboarding capability to owner and manager workspace roles', function (): void {
    expect(WorkspaceRoleCapabilityMap::hasCapability('owner', Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD))->toBeTrue();
    expect(WorkspaceRoleCapabilityMap::hasCapability('manager', Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD))->toBeTrue();

    expect(WorkspaceRoleCapabilityMap::hasCapability('operator', Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD))->toBeFalse();
    expect(WorkspaceRoleCapabilityMap::hasCapability('readonly', Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD))->toBeFalse();
});

it('authorizes onboarding via Gate for owner and manager memberships', function (): void {
    $workspace = Workspace::factory()->create();

    $owner = User::factory()->create();
    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $owner->getKey(),
        'role' => 'owner',
    ]);

    $manager = User::factory()->create();
    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $manager->getKey(),
        'role' => 'manager',
    ]);

    $readonly = User::factory()->create();
    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'user_id' => $readonly->getKey(),
        'role' => 'readonly',
    ]);

    expect(Gate::forUser($owner)->allows(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD, $workspace))->toBeTrue();
    expect(Gate::forUser($manager)->allows(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD, $workspace))->toBeTrue();
    expect(Gate::forUser($readonly)->allows(Capabilities::WORKSPACE_MANAGED_TENANT_ONBOARD, $workspace))->toBeFalse();
});

it('keeps filament tenant routing key stable (external_id resolves /admin/t/{tenant})', function (): void {
    [$user, $tenant] = createUserWithTenant(
        Tenant::factory()->create([
            'workspace_id' => null,
            'tenant_id' => '11111111-1111-1111-1111-111111111111',
        ]),
        role: 'owner',
    );

    $this->actingAs($user)
        ->get(TenantDashboard::getUrl(tenant: $tenant))
        ->assertSuccessful();

    $tenant->refresh();

    expect($tenant->external_id)->toBe($tenant->tenant_id);
});

it('can persist a tenant onboarding session row', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $session = TenantOnboardingSession::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'tenant_id' => (int) $tenant->getKey(),
        'current_step' => 'identify',
        'state' => ['example' => 'value'],
        'started_by_user_id' => (int) $user->getKey(),
        'updated_by_user_id' => (int) $user->getKey(),
    ]);

    expect($session->exists)->toBeTrue();
    $this->assertDatabaseHas('managed_tenant_onboarding_sessions', [
        'id' => $session->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'tenant_id' => (int) $tenant->getKey(),
        'current_step' => 'identify',
    ]);
});

*/
