<?php

declare(strict_types=1);

use App\Filament\Resources\ReviewPackResource;
use App\Filament\Resources\ReviewPackResource\Pages\ListReviewPacks;
use App\Filament\Resources\ReviewPackResource\Pages\ViewReviewPack;
use App\Models\OperationRun;
use App\Models\ReviewPack;
use App\Models\Tenant;
use App\Services\ReviewPackService;
use App\Support\Auth\UiTooltips;
use App\Support\ReviewPackStatus;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    Storage::fake('exports');
});

// ─── List Page ───────────────────────────────────────────────

it('renders the list page for an authorized user', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $this->actingAs($user)
        ->get(ReviewPackResource::getUrl('index', tenant: $tenant))
        ->assertOk();
});

it('shows review packs belonging to the active tenant', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $otherTenant = Tenant::factory()->create();

    $pack = ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
    ]);

    ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $otherTenant->getKey(),
    ]);

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

    Livewire::actingAs($user)
        ->test(ListReviewPacks::class)
        ->assertCanSeeTableRecords([$pack]);
});

it('displays the empty state when no packs exist', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

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

    Livewire::actingAs($user)
        ->test(ListReviewPacks::class)
        ->assertSee('No review packs yet');
});

// ─── List Page Header Action ─────────────────────────────────

it('shows the generate_pack header action for a MANAGE user', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

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

    Livewire::actingAs($user)
        ->test(ListReviewPacks::class)
        ->assertActionVisible('generate_pack');
});

it('disables the generate_pack action for a readonly user', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');

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

    Livewire::actingAs($user)
        ->test(ListReviewPacks::class)
        ->assertActionVisible('generate_pack')
        ->assertActionDisabled('generate_pack')
        ->assertActionExists('generate_pack', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission());
});

it('reuses an existing ready pack instead of starting a new run', function (): void {
    Queue::fake();

    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $fingerprint = app(ReviewPackService::class)->computeFingerprint($tenant, [
        'include_pii' => true,
        'include_operations' => true,
    ]);

    ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
        'fingerprint' => $fingerprint,
        'expires_at' => now()->addDay(),
    ]);

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

    $operationRunsBefore = OperationRun::query()->count();
    $reviewPacksBefore = ReviewPack::query()->count();

    Livewire::actingAs($user)
        ->test(ListReviewPacks::class)
        ->callAction('generate_pack', [
            'include_pii' => true,
            'include_operations' => true,
        ])
        ->assertNotified();

    expect(OperationRun::query()->count())->toBe($operationRunsBefore);
    expect(ReviewPack::query()->count())->toBe($reviewPacksBefore);

    Queue::assertNothingPushed();
});

// ─── Table Row Actions ───────────────────────────────────────

it('shows the download action for a ready pack', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $filePath = 'review-packs/test.zip';
    Storage::disk('exports')->put($filePath, 'PK-fake');

    $pack = ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
        'file_path' => $filePath,
    ]);

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

    Livewire::actingAs($user)
        ->test(ListReviewPacks::class)
        ->assertTableActionVisible('download', $pack);
});

it('shows the expire action for a ready pack with confirmation', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $filePath = 'review-packs/expire-test.zip';
    Storage::disk('exports')->put($filePath, 'PK-fake');

    $pack = ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
        'file_path' => $filePath,
        'file_disk' => 'exports',
    ]);

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

    Livewire::actingAs($user)
        ->test(ListReviewPacks::class)
        ->assertTableActionVisible('expire', $pack)
        ->callTableAction('expire', $pack);

    $pack->refresh();
    expect($pack->status)->toBe(ReviewPackStatus::Expired->value);
    Storage::disk('exports')->assertMissing($filePath);
});

// ─── View Page ───────────────────────────────────────────────

it('renders the view page for a ready pack', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $pack = ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
        'summary' => [
            'finding_count' => 5,
            'report_count' => 2,
            'operation_count' => 12,
            'data_freshness' => [
                'permission_posture' => now()->toIso8601String(),
                'entra_admin_roles' => now()->toIso8601String(),
                'findings' => now()->toIso8601String(),
                'hardening' => now()->toIso8601String(),
            ],
        ],
        'options' => ['include_pii' => true, 'include_operations' => true],
    ]);

    $this->actingAs($user)
        ->get(ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $tenant))
        ->assertOk();
});

it('shows download header action on view page for a ready pack', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $pack = ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
    ]);

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

    Livewire::actingAs($user)
        ->test(ViewReviewPack::class, ['record' => $pack->getKey()])
        ->assertActionVisible('download');
});

it('shows regenerate header action on view page', function (): void {
    $tenant = Tenant::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    $pack = ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'initiated_by_user_id' => (int) $user->getKey(),
    ]);

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

    Livewire::actingAs($user)
        ->test(ViewReviewPack::class, ['record' => $pack->getKey()])
        ->assertActionVisible('regenerate');
});

// ─── Non-Member Access ───────────────────────────────────────

it('returns 404 for non-members on list page', function (): void {
    $tenant = Tenant::factory()->create();
    $otherTenant = Tenant::factory()->create();

    [$user] = createUserWithTenant($otherTenant, role: 'owner');

    $this->actingAs($user)
        ->get(ReviewPackResource::getUrl('index', tenant: $tenant))
        ->assertNotFound();
});

it('returns 404 for non-members on view page', function (): void {
    $tenant = Tenant::factory()->create();
    $otherTenant = Tenant::factory()->create();

    [$user] = createUserWithTenant($otherTenant, role: 'owner');

    $pack = ReviewPack::factory()->ready()->create([
        'tenant_id' => (int) $tenant->getKey(),
    ]);

    $this->actingAs($user)
        ->get(ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $tenant))
        ->assertNotFound();
});
