<?php

declare(strict_types=1);

use App\Filament\Pages\Monitoring\Operations;
use App\Filament\Resources\AlertDeliveryResource\Pages\ListAlertDeliveries;
use App\Filament\Resources\BackupScheduleResource\Pages\ListBackupSchedules;
use App\Filament\Resources\BackupSetResource\Pages\ListBackupSets;
use App\Filament\Resources\BaselineSnapshotResource\Pages\ListBaselineSnapshots;
use App\Filament\Resources\EntraGroupResource\Pages\ListEntraGroups;
use App\Filament\Resources\FindingResource\Pages\ListFindings;
use App\Filament\Resources\InventoryItemResource\Pages\ListInventoryItems;
use App\Filament\Resources\PolicyResource\Pages\ListPolicies;
use App\Filament\Resources\PolicyVersionResource\Pages\ListPolicyVersions;
use App\Filament\Resources\ProviderConnectionResource\Pages\ListProviderConnections;
use App\Filament\Resources\RestoreRunResource\Pages\ListRestoreRuns;
use App\Filament\Resources\TenantResource\Pages\ListTenants;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

/**
 * @param  array<string, mixed>  $parameters
 */
function spec125AssertPersistedTableState(
    string $componentClass,
    array $parameters,
    string $search,
    string $sortColumn,
    string $sortDirection,
    string $filterPath,
    mixed $filterValue,
): void {
    $component = Livewire::test($componentClass, $parameters)
        ->searchTable($search)
        ->call('sortTable', $sortColumn, $sortDirection)
        ->set($filterPath, $filterValue);

    $instance = $component->instance();

    expect(session()->get($instance->getTableSearchSessionKey()))->toBe($search);
    expect(session()->get($instance->getTableSortSessionKey()))->toBe("{$sortColumn}:{$sortDirection}");
    expect(data_get(session()->get($instance->getTableFiltersSessionKey()), str($filterPath)->after('tableFilters.')->value()))->toBe($filterValue);

    Livewire::test($componentClass, $parameters)
        ->assertSet('tableSearch', $search)
        ->assertSet('tableSort', "{$sortColumn}:{$sortDirection}")
        ->assertSet($filterPath, $filterValue);
}

it('persists tenant list search, sort, and filter state across remounts', function (): void {
    [$user] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListTenants::class,
        [],
        'Tenant',
        'name',
        'desc',
        'tableFilters.environment.value',
        'prod',
    );
});

it('persists policy list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListPolicies::class,
        [],
        'Policy',
        'display_name',
        'desc',
        'tableFilters.visibility.value',
        'active',
    );
});

it('persists backup-set list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListBackupSets::class,
        [],
        'Backup',
        'name',
        'desc',
        'tableFilters.trashed.value',
        1,
    );
});

it('persists backup-schedule list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListBackupSchedules::class,
        [],
        'Schedule',
        'name',
        'desc',
        'tableFilters.enabled_state.value',
        'enabled',
    );
});

it('persists provider-connections list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListProviderConnections::class,
        [],
        'Contoso',
        'display_name',
        'desc',
        'tableFilters.default_only.isActive',
        true,
    );
});

it('persists findings list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'manager');

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

    spec125AssertPersistedTableState(
        ListFindings::class,
        [],
        'drift',
        'created_at',
        'asc',
        'tableFilters.status.value',
        'new',
    );
});

it('persists inventory item list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListInventoryItems::class,
        [],
        'Policy',
        'display_name',
        'asc',
        'tableFilters.platform.value',
        'windows',
    );
});

it('persists policy version list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListPolicyVersions::class,
        [],
        'Policy',
        'captured_at',
        'asc',
        'tableFilters.platform.value',
        'windows',
    );
});

it('persists restore run list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListRestoreRuns::class,
        [],
        'Restore',
        'started_at',
        'asc',
        'tableFilters.status.value',
        'completed',
    );
});

it('persists alert delivery list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListAlertDeliveries::class,
        [],
        'alert',
        'created_at',
        'asc',
        'tableFilters.status.value',
        'sent',
    );
});

it('persists Entra group list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        ListEntraGroups::class,
        [],
        'Group',
        'display_name',
        'desc',
        'tableFilters.group_type.value',
        'security',
    );
});

it('persists baseline snapshot list search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user);
    session([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]);

    spec125AssertPersistedTableState(
        ListBaselineSnapshots::class,
        [],
        'Baseline',
        'captured_at',
        'asc',
        'tableFilters.snapshot_state.value',
        'with_gaps',
    );
});

it('persists monitoring operations search, sort, and filter state across remounts', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

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

    spec125AssertPersistedTableState(
        Operations::class,
        [],
        'policy',
        'type',
        'desc',
        'tableFilters.status.value',
        'queued',
    );
});
