<?php

declare(strict_types=1);

use App\Models\AuditLog;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\Audit\AuditActionId;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Livewire\Livewire;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    Http::preventStrayRequests();
});

// --- T016: it_only_lists_workspaces_user_is_member_of ---

it('only lists workspaces user is member of', function (): void {
    $user = User::factory()->create();

    $workspaceA = Workspace::factory()->create(['name' => 'My Workspace']);
    $workspaceB = Workspace::factory()->create(['name' => 'Other Workspace']);

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

    // User is NOT a member of workspaceB.
    WorkspaceMembership::factory()->create([
        'workspace_id' => $workspaceB->getKey(),
        'user_id' => User::factory()->create()->getKey(),
        'role' => 'owner',
    ]);

    $user->forceFill(['last_workspace_id' => (int) $workspaceA->getKey()])->save();

    $this->actingAs($user)
        ->get(route('filament.admin.pages.choose-workspace'))
        ->assertOk()
        ->assertSee('My Workspace')
        ->assertDontSee('Other Workspace');
});

it('excludes archived workspaces from the list', function (): void {
    $user = User::factory()->create();

    $activeWorkspace = Workspace::factory()->create(['name' => 'Active WS']);
    $archivedWorkspace = Workspace::factory()->create(['name' => 'Archived WS', 'archived_at' => now()]);

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

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

    $user->forceFill(['last_workspace_id' => (int) $activeWorkspace->getKey()])->save();

    $this->actingAs($user)
        ->get(route('filament.admin.pages.choose-workspace'))
        ->assertOk()
        ->assertSee('Active WS')
        ->assertDontSee('Archived WS');
});

// --- T017: it_shows_name_role_and_tenants_count_per_workspace ---

it('shows name role and tenants count per workspace', function (): void {
    $user = User::factory()->create();

    $workspace = Workspace::factory()->create(['name' => 'Test Corp']);

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

    // Create 2 active tenants.
    ManagedEnvironment::factory()->count(2)->create([
        'workspace_id' => $workspace->getKey(),
        'status' => 'active',
    ]);

    // Create 1 inactive tenant (should not count).
    ManagedEnvironment::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'status' => 'pending_validation',
    ]);

    $user->forceFill(['last_workspace_id' => (int) $workspace->getKey()])->save();

    $this->actingAs($user)
        ->get(route('filament.admin.pages.choose-workspace'))
        ->assertOk()
        ->assertSee('Test Corp')
        ->assertSee('Manager')
        ->assertSee('2 tenants');
});

it('shows singular tenant label when count is one', function (): void {
    $user = User::factory()->create();

    $workspace = Workspace::factory()->create(['name' => 'Solo Corp']);

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

    ManagedEnvironment::factory()->create([
        'workspace_id' => $workspace->getKey(),
        'status' => 'active',
    ]);

    $user->forceFill(['last_workspace_id' => (int) $workspace->getKey()])->save();

    $this->actingAs($user)
        ->get(route('filament.admin.pages.choose-workspace'))
        ->assertOk()
        ->assertSee('1 tenant');
});

// --- T018: it_shows_empty_state_when_no_memberships ---

it('shows empty state when no memberships', function (): void {
    $user = User::factory()->create();

    $this->actingAs($user)
        ->get(route('filament.admin.pages.choose-workspace'))
        ->assertOk()
        ->assertSee("You don't have access to any workspace yet.", false);
});

// --- T019: manage link visibility ---

it('shows manage link for owner role', function (): void {
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();

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

    $user->forceFill(['last_workspace_id' => (int) $workspace->getKey()])->save();

    $this->actingAs($user)
        ->get(route('filament.admin.pages.choose-workspace'))
        ->assertOk()
        ->assertSee('Manage workspaces')
        ->assertSee(route('filament.admin.resources.workspaces.index', absolute: false), false);
});

it('hides manage link for non-owner roles', function (): void {
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();

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

    $user->forceFill(['last_workspace_id' => (int) $workspace->getKey()])->save();

    $this->actingAs($user)
        ->get(route('filament.admin.pages.choose-workspace'))
        ->assertOk()
        ->assertDontSee('Manage workspaces')
        ->assertDontSee(route('filament.admin.resources.workspaces.index', absolute: false), false);
});

// --- T020: it_has_no_n_plus_1_queries_in_chooser ---

it('has no n plus 1 queries in chooser', function (): void {
    $user = User::factory()->create();

    // Create 5 workspaces with memberships.
    $workspaces = Workspace::factory()->count(5)->create();

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

        ManagedEnvironment::factory()->count(2)->create([
            'workspace_id' => $workspace->getKey(),
            'status' => 'active',
        ]);
    }

    $user->forceFill(['last_workspace_id' => (int) $workspaces->first()->getKey()])->save();

    DB::enableQueryLog();

    $this->actingAs($user)
        ->get(route('filament.admin.pages.choose-workspace'))
        ->assertOk();

    $queryCount = count(DB::getQueryLog());
    DB::disableQueryLog();

    // Should be bounded: auth query + workspaces (with count) + memberships for roles + minimal Filament overhead.
    // Not proportional to workspace count.
    expect($queryCount)->toBeLessThan(20);
});

// --- T031: it_persists_last_used_workspace_on_manual_selection ---

it('persists last used workspace on manual selection', function (): void {
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();

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

    Livewire::actingAs($user)
        ->test(\App\Filament\Pages\ChooseWorkspace::class)
        ->call('selectWorkspace', (int) $workspace->getKey());

    $user->refresh();
    expect($user->last_workspace_id)->toBe((int) $workspace->getKey());
});

it('emits audit event on manual selection', function (): void {
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();

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

    Livewire::actingAs($user)
        ->test(\App\Filament\Pages\ChooseWorkspace::class)
        ->call('selectWorkspace', (int) $workspace->getKey());

    $auditLog = AuditLog::query()
        ->where('action', AuditActionId::WorkspaceSelected->value)
        ->where('workspace_id', $workspace->getKey())
        ->first();

    expect($auditLog)->not->toBeNull();
    expect($auditLog->metadata)->toMatchArray([
        'method' => 'manual',
        'reason' => 'chooser',
    ]);
});

// --- T033: it_rejects_non_member_workspace_selection_with_404 ---

it('rejects non member workspace selection with 404', function (): void {
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();

    // User is NOT a member.
    Livewire::actingAs($user)
        ->test(\App\Filament\Pages\ChooseWorkspace::class)
        ->call('selectWorkspace', (int) $workspace->getKey())
        ->assertStatus(404);
});

it('rejects archived workspace selection with 404', function (): void {
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create(['archived_at' => now()]);

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

    Livewire::actingAs($user)
        ->test(\App\Filament\Pages\ChooseWorkspace::class)
        ->call('selectWorkspace', (int) $workspace->getKey())
        ->assertStatus(404);
});
