<?php

declare(strict_types=1);

use App\Filament\Resources\TenantResource\Pages\ListTenants;
use App\Models\Tenant;
use App\Models\TenantMembership;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

it('does not show tenants from other workspaces on the tenants index', function (): void {
    $user = User::factory()->create();

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

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

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

    $tenantA = Tenant::factory()->create([
        'workspace_id' => $workspaceA->getKey(),
        'external_id' => '11111111-1111-1111-1111-111111111111',
        'tenant_id' => '11111111-1111-1111-1111-111111111111',
        'name' => 'Tenant A',
        'status' => 'active',
    ]);

    $tenantB = Tenant::factory()->create([
        'workspace_id' => $workspaceB->getKey(),
        'external_id' => '22222222-2222-2222-2222-222222222222',
        'tenant_id' => '22222222-2222-2222-2222-222222222222',
        'name' => 'Tenant B',
        'status' => 'active',
    ]);

    TenantMembership::query()->create([
        'tenant_id' => $tenantA->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
        'source' => 'manual',
        'source_ref' => null,
        'created_by_user_id' => null,
    ]);

    TenantMembership::query()->create([
        'tenant_id' => $tenantB->getKey(),
        'user_id' => $user->getKey(),
        'role' => 'owner',
        'source' => 'manual',
        'source_ref' => null,
        'created_by_user_id' => null,
    ]);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspaceA->getKey()])
        ->get(route('filament.admin.resources.tenants.index', filamentTenantRouteParams($tenantA)))
        ->assertOk()
        ->assertSee('Tenant A')
        ->assertDontSee('Tenant B');
});

it('keeps tenant list defaults calm and persists list state in-session', function (): void {
    [$user] = createUserWithTenant(role: 'owner');

    $this->actingAs($user);
    Filament::setTenant(null, true);

    $component = Livewire::actingAs($user)
        ->test(\App\Filament\Resources\TenantResource\Pages\ListTenants::class)
        ->assertTableEmptyStateActionsExistInOrder(['add_tenant'])
        ->searchTable('Tenant')
        ->call('sortTable', 'name', 'desc')
        ->set('tableFilters.environment.value', 'prod');

    $table = $component->instance()->getTable();

    expect($table->getPaginationPageOptions())->toBe(\App\Support\Filament\TablePaginationProfiles::resource());
    expect($table->getEmptyStateHeading())->toBe('No tenants connected');
    expect($table->getColumn('name')?->isSearchable())->toBeTrue();
    expect($table->getColumn('name')?->isSortable())->toBeTrue();
    expect($table->getColumn('tenant_id')?->isToggledHiddenByDefault())->toBeTrue();
    expect($table->getColumn('domain')?->isToggledHiddenByDefault())->toBeTrue();
    expect(count($table->getVisibleColumns()))->toBeLessThanOrEqual(7);
    expect(session()->get($component->instance()->getTableSearchSessionKey()))->toBe('Tenant');
    expect(session()->get($component->instance()->getTableSortSessionKey()))->toBe('name:desc');

    Livewire::actingAs($user)
        ->test(\App\Filament\Resources\TenantResource\Pages\ListTenants::class)
        ->assertSet('tableSearch', 'Tenant')
        ->assertSet('tableSort', 'name:desc')
        ->assertSet('tableFilters.environment.value', 'prod');
});

it('keeps posture filters scoped to visible workspace tenants only', function (): void {
    $visibleTenant = Tenant::factory()->create(['status' => 'active']);
    [$user, $visibleTenant] = createUserWithTenant($visibleTenant, role: 'owner', workspaceRole: 'readonly');
    workspaceOverviewSeedQuietTenantTruth($visibleTenant);
    workspaceOverviewSeedHealthyBackup($visibleTenant, [
        'completed_at' => now()->subMinutes(10),
    ]);

    $hiddenRecoveryTenant = Tenant::factory()->create([
        'status' => 'active',
        'workspace_id' => (int) $visibleTenant->workspace_id,
        'name' => 'Hidden Recovery Tenant',
    ]);
    workspaceOverviewSeedQuietTenantTruth($hiddenRecoveryTenant);
    workspaceOverviewSeedHealthyBackup($hiddenRecoveryTenant, [
        'completed_at' => now()->subMinutes(9),
    ]);

    $hiddenBackupTenant = Tenant::factory()->create([
        'status' => 'active',
        'workspace_id' => (int) $visibleTenant->workspace_id,
        'name' => 'Hidden Degraded Tenant',
    ]);
    workspaceOverviewSeedQuietTenantTruth($hiddenBackupTenant);
    workspaceOverviewSeedHealthyBackup($hiddenBackupTenant, [
        'completed_at' => now()->subMinutes(8),
    ], [
        'payload' => [],
        'metadata' => [
            'source' => 'metadata_only',
            'assignments_fetch_failed' => true,
        ],
        'assignments' => [],
    ]);

    $this->actingAs($user);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $visibleTenant->workspace_id);
    Filament::setTenant(null, true);

    $recoveryFiltered = Livewire::actingAs($user)
        ->test(ListTenants::class)
        ->filterTable('recovery_evidence', ['unvalidated']);

    expect($recoveryFiltered->instance()->getFilteredTableQuery()?->pluck('tenants.name')->all())
        ->toBe([(string) $visibleTenant->name]);

    $backupFiltered = Livewire::actingAs($user)
        ->test(ListTenants::class)
        ->filterTable('backup_posture', [TenantBackupHealthAssessment::POSTURE_DEGRADED]);

    expect($backupFiltered->instance()->getFilteredTableQuery()?->pluck('tenants.name')->all())
        ->toBe([]);
});
