<?php

declare(strict_types=1);

use App\Filament\Resources\BackupScheduleResource;
use App\Filament\Resources\BackupSetResource;
use App\Filament\Resources\EnvironmentReviewResource;
use App\Filament\Resources\EvidenceSnapshotResource;
use App\Filament\Resources\FindingExceptionResource;
use App\Filament\Resources\FindingResource;
use App\Filament\Resources\InventoryItemResource;
use App\Filament\Resources\PolicyResource;
use App\Filament\Resources\PolicyVersionResource;
use App\Filament\Resources\RestoreRunResource;
use App\Filament\Resources\ReviewPackResource;
use App\Filament\Resources\StoredReportResource;
use App\Models\ManagedEnvironment;
use App\Models\StoredReport;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Http\Request;

it('registers governance resource navigation on the admin panel', function (): void {
    Filament::setCurrentPanel('admin');
    app()->instance('request', Request::create('/admin/workspaces/spec-282-workspace/environments/spec-282-production'));

    expect(FindingResource::shouldRegisterNavigation())->toBeTrue()
        ->and(FindingExceptionResource::shouldRegisterNavigation())->toBeTrue()
        ->and(InventoryItemResource::shouldRegisterNavigation())->toBeTrue()
        ->and(PolicyResource::shouldRegisterNavigation())->toBeTrue()
        ->and(PolicyVersionResource::shouldRegisterNavigation())->toBeTrue()
        ->and(BackupScheduleResource::shouldRegisterNavigation())->toBeTrue()
        ->and(BackupSetResource::shouldRegisterNavigation())->toBeTrue()
        ->and(RestoreRunResource::shouldRegisterNavigation())->toBeTrue()
        ->and(EnvironmentReviewResource::shouldRegisterNavigation())->toBeTrue();
});

it('builds workspace-first admin urls for governance resources', function (): void {
    Filament::setCurrentPanel('admin');

    $workspace = Workspace::factory()->create([
        'name' => 'Spec 282 Workspace',
        'slug' => 'spec-282-workspace',
    ]);

    $tenant = ManagedEnvironment::factory()->active()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'name' => 'Spec 282 Production',
        'slug' => 'spec-282-production',
    ]);

    $expectedPrefix = '/admin/workspaces/'.$workspace->getRouteKey().'/environments/'.$tenant->getRouteKey().'/';

    $searchableResources = [];

    foreach ([
        InventoryItemResource::class,
        PolicyResource::class,
        PolicyVersionResource::class,
        BackupScheduleResource::class,
        BackupSetResource::class,
        RestoreRunResource::class,
        FindingResource::class,
        FindingExceptionResource::class,
        EvidenceSnapshotResource::class,
        EnvironmentReviewResource::class,
        ReviewPackResource::class,
        StoredReportResource::class,
    ] as $resourceClass) {
        $path = parse_url($resourceClass::getUrl('index', panel: 'admin', tenant: $tenant), PHP_URL_PATH);

        expect($path)
            ->toBeString()
            ->toStartWith($expectedPrefix)
            ->not->toContain('/admin/t/');
    }
});

it('returns 404 for governance artifact routes when the workspace and environment pair is mismatched', function (): void {
    Filament::setCurrentPanel('admin');

    $workspace = Workspace::factory()->create([
        'name' => 'Spec 282 Primary Workspace',
        'slug' => 'spec-282-primary-workspace',
    ]);
    $otherWorkspace = Workspace::factory()->create([
        'name' => 'Spec 282 Secondary Workspace',
        'slug' => 'spec-282-secondary-workspace',
    ]);

    $tenant = ManagedEnvironment::factory()->active()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'name' => 'Spec 282 Production',
        'slug' => 'spec-282-production',
    ]);

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

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

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

    $report = StoredReport::factory()
        ->permissionPosture()
        ->create([
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
        ]);

    $this->actingAs($user)
        ->withSession([
            WorkspaceContext::SESSION_KEY => (int) $otherWorkspace->getKey(),
        ])
        ->get(FindingResource::getUrl('index', ['workspace' => $otherWorkspace], panel: 'admin', tenant: $tenant))
        ->assertNotFound();

    $this->actingAs($user)
        ->withSession([
            WorkspaceContext::SESSION_KEY => (int) $otherWorkspace->getKey(),
        ])
        ->get(StoredReportResource::getUrl('view', ['workspace' => $otherWorkspace, 'record' => $report], panel: 'admin', tenant: $tenant))
        ->assertNotFound();
});

it('keeps touched searchable governance resources on truthful destinations', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', setUiContext: false);

    $this->actingAs($user);
    setAdminPanelContext();
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
    session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
        (string) $tenant->workspace_id => (int) $tenant->getKey(),
    ]);

    $searchableResources = [];

    foreach ([
        InventoryItemResource::class,
        PolicyResource::class,
        PolicyVersionResource::class,
        BackupScheduleResource::class,
        BackupSetResource::class,
        RestoreRunResource::class,
        FindingResource::class,
        FindingExceptionResource::class,
        EvidenceSnapshotResource::class,
        EnvironmentReviewResource::class,
        ReviewPackResource::class,
        StoredReportResource::class,
    ] as $resourceClass) {
        if (! $resourceClass::canGloballySearch()) {
            continue;
        }

        $searchableResources[] = $resourceClass;
    }

    expect($searchableResources)->toBeArray();

    foreach ($searchableResources as $resourceClass) {
        expect($resourceClass::hasPage('view') || $resourceClass::hasPage('edit'))
            ->toBeTrue($resourceClass.' must keep a truthful global-search destination on the admin panel.');
    }
});
