<?php

declare(strict_types=1);

use App\Filament\Pages\Workspaces\ManagedEnvironmentOnboardingWizard;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\Verification\VerificationReportWriter;
use App\Support\Workspaces\WorkspaceContext;
use Livewire\Livewire;

it('returns 404 when the requested onboarding draft does not exist', 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(route('admin.onboarding.draft', ['onboardingDraft' => 999999]))
        ->assertNotFound();
});

it('returns 404 when a draft is requested from a different selected workspace', function (): void {
    $workspaceA = Workspace::factory()->create();
    $workspaceB = Workspace::factory()->create();
    $ownerA = User::factory()->create();
    $userB = User::factory()->create();

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

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

    $draft = createOnboardingDraft([
        'workspace' => $workspaceA,
        'started_by' => $ownerA,
        'updated_by' => $ownerA,
    ]);

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

    $this->actingAs($userB)
        ->get(route('admin.onboarding.draft', ['onboardingDraft' => $draft->getKey()]))
        ->assertNotFound();
});

it('returns 404 when a non-member requests an onboarding draft route', function (): void {
    $workspace = Workspace::factory()->create();
    $owner = User::factory()->create();
    $nonMember = User::factory()->create();

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

    $draft = createOnboardingDraft([
        'workspace' => $workspace,
        'started_by' => $owner,
        'updated_by' => $owner,
    ]);

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

    $this->actingAs($nonMember)
        ->get(route('admin.onboarding.draft', ['onboardingDraft' => $draft->getKey()]))
        ->assertNotFound();
});

it('returns 404 when the actor can access the workspace but lacks tenant entitlement for an identified draft', function (): void {
    $workspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ]);
    $owner = User::factory()->create();
    $workspaceOnlyUser = User::factory()->create();

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

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

    $draft = createOnboardingDraft([
        'workspace' => $workspace,
        'tenant' => $tenant,
        'started_by' => $owner,
        'updated_by' => $owner,
    ]);

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

    $this->actingAs($workspaceOnlyUser)
        ->get(route('admin.onboarding.draft', ['onboardingDraft' => $draft->getKey()]))
        ->assertNotFound();
});

it('returns 403 for an in-scope member with tenant entitlement but without onboarding capability', function (): void {
    $workspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ]);
    $readonlyUser = User::factory()->create();

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

    $draft = createOnboardingDraft([
        'workspace' => $workspace,
        'tenant' => $tenant,
        'started_by' => $readonlyUser,
        'updated_by' => $readonlyUser,
    ]);

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

    $this->actingAs($readonlyUser)
        ->get(route('admin.onboarding.draft', ['onboardingDraft' => $draft->getKey()]))
        ->assertForbidden();
});

it('renders shared verification family markers for an entitled requested verify draft', function (): void {
    $workspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
    ]);
    $user = User::factory()->create();

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

    $connection = ProviderConnection::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => (string) $tenant->managed_environment_id,
        'display_name' => 'Requested verify connection',
        'is_default' => true,
    ]);

    $run = OperationRun::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'type' => 'provider.connection.check',
        'status' => 'completed',
        'outcome' => 'blocked',
        'context' => [
            'provider_connection_id' => (int) $connection->getKey(),
            'verification_report' => VerificationReportWriter::build('provider.connection.check', [
                [
                    'key' => 'requested_verify_draft',
                    'title' => 'Requested verify draft check',
                    'status' => 'fail',
                    'severity' => 'high',
                    'blocking' => false,
                    'reason_code' => 'missing_configuration',
                    'message' => 'Draft needs attention.',
                    '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(),
        ],
    ]);

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

    $response->assertSuccessful()->assertSee('Requested verify draft check');

    expect($response->getContent())
        ->toContain('data-shared-detail-family="verification-report"')
        ->toContain('data-host-kind="onboarding_wizard"');
});

it('mounts the requested draft with canonical persisted continuity state even when other drafts exist', function (): void {
    $workspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
        'managed_environment_id' => '23232323-2323-2323-2323-232323232323',
        'name' => 'Canonical Continuity ManagedEnvironment',
    ]);
    $otherTenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
        'name' => 'Other Draft ManagedEnvironment',
    ]);
    $user = User::factory()->create();

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

    $user->tenants()->syncWithoutDetaching([
        $otherTenant->getKey() => ['role' => 'owner'],
    ]);

    $connection = ProviderConnection::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $tenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => (string) $tenant->managed_environment_id,
        'display_name' => 'Canonical continuity connection',
        'is_default' => true,
    ]);

    createOnboardingDraft([
        'workspace' => $workspace,
        'tenant' => $otherTenant,
        'started_by' => $user,
        'updated_by' => $user,
        'current_step' => 'identify',
    ]);

    $draft = createOnboardingDraft([
        'workspace' => $workspace,
        'tenant' => $tenant,
        'started_by' => $user,
        'updated_by' => $user,
        'current_step' => 'bootstrap',
        'state' => [
            'entra_tenant_id' => (string) $tenant->managed_environment_id,
            'environment_name' => (string) $tenant->name,
            'environment' => 'prod',
            'notes' => 'Canonical persisted note',
            'provider_connection_id' => (int) $connection->getKey(),
            'bootstrap_operation_types' => ['inventory.sync'],
        ],
    ]);

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

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentOnboardingWizard::class, [
            'onboardingDraft' => (int) $draft->getKey(),
        ])
        ->assertSet('onboardingSessionId', (int) $draft->getKey())
        ->assertSet('showDraftPicker', false)
        ->assertSet('showStartState', false)
        ->assertSet('selectedProviderConnectionId', (int) $connection->getKey())
        ->assertSet('selectedBootstrapOperationTypes', ['inventory.sync'])
        ->assertSet('data.provider_connection_id', (int) $connection->getKey())
        ->assertSet('data.name', (string) $tenant->name);
});

it('refreshes continuity state from the requested draft even when public draft state is forged before refresh', function (): void {
    $workspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
        'managed_environment_id' => '24242424-2424-2424-2424-242424242424',
        'name' => 'Requested Draft ManagedEnvironment',
    ]);
    $otherTenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'status' => ManagedEnvironment::STATUS_ONBOARDING,
        'managed_environment_id' => '25252525-2525-2525-2525-252525252525',
        'name' => 'Forged Draft ManagedEnvironment',
    ]);
    $user = User::factory()->create();

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

    $user->tenants()->syncWithoutDetaching([
        $otherTenant->getKey() => ['role' => 'owner'],
    ]);

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

    $otherConnection = ProviderConnection::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'managed_environment_id' => (int) $otherTenant->getKey(),
        'provider' => 'microsoft',
        'entra_tenant_id' => (string) $otherTenant->managed_environment_id,
        'display_name' => 'Forged connection',
        'is_default' => true,
    ]);

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

    $otherDraft = createOnboardingDraft([
        'workspace' => $workspace,
        'tenant' => $otherTenant,
        'started_by' => $user,
        'updated_by' => $user,
        'current_step' => 'connection',
        'state' => [
            'entra_tenant_id' => (string) $otherTenant->managed_environment_id,
            'environment_name' => (string) $otherTenant->name,
            'provider_connection_id' => (int) $otherConnection->getKey(),
        ],
    ]);

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

    Livewire::actingAs($user)
        ->test(ManagedEnvironmentOnboardingWizard::class, [
            'onboardingDraft' => (int) $draft->getKey(),
        ])
        ->set('onboardingSession', $otherDraft)
        ->set('managedEnvironment', $otherTenant)
        ->call('refreshCheckpointLifecycle')
        ->assertSet('onboardingSessionId', (int) $draft->getKey())
        ->assertSet('managedEnvironmentId', (int) $tenant->getKey())
        ->assertSet('selectedProviderConnectionId', (int) $connection->getKey())
        ->assertSet('data.provider_connection_id', (int) $connection->getKey())
        ->assertSet('data.name', (string) $tenant->name);
});
