<?php

declare(strict_types=1);

use App\Filament\Pages\Governance\DecisionRegister;
use App\Filament\Resources\EvidenceSnapshotResource;
use App\Models\EvidenceSnapshot;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\FindingExceptionDecision;
use App\Models\ManagedEnvironment;
use App\Support\Evidence\EvidenceCompletenessState;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\Workspaces\WorkspaceContext;

it('keeps the decision register read-only with one dominant row action', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'name' => 'Alpha ManagedEnvironment',
    ]);
    [$user, $tenant] = createUserWithTenant($tenant, role: 'owner', workspaceRole: 'owner');

    $finding = Finding::factory()->for($tenant)->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

    $exception = FindingException::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'finding_id' => (int) $finding->getKey(),
        'requested_by_user_id' => (int) $user->getKey(),
        'owner_user_id' => (int) $user->getKey(),
        'status' => FindingException::STATUS_PENDING,
        'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT,
        'request_reason' => 'Read only boundary test',
        'requested_at' => now()->subDay(),
        'review_due_at' => now()->addDay(),
        'evidence_summary' => ['reference_count' => 0],
    ]);

    $decision = $exception->decisions()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'actor_user_id' => (int) $user->getKey(),
        'decision_type' => FindingExceptionDecision::TYPE_REQUESTED,
        'reason' => 'Read only boundary test',
        'metadata' => [],
        'decided_at' => now()->subDay(),
    ]);

    $exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save();

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(DecisionRegister::getUrl(panel: 'admin'))
        ->assertOk()
        ->assertSee('Open decision')
        ->assertDontSee('Approve exception')
        ->assertDontSee('Reject exception')
        ->assertDontSee('Renew exception')
        ->assertDontSee('Revoke exception');
});

it('omits terminal decisions outside the 30 calendar day recently closed window', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'name' => 'Alpha ManagedEnvironment',
    ]);
    [$user, $tenant] = createUserWithTenant($tenant, role: 'owner', workspaceRole: 'owner');

    $createTerminalException = function (string $status, string $reason, int $daysAgo) use ($tenant, $user): FindingException {
        $finding = Finding::factory()->for($tenant)->create([
            'workspace_id' => (int) $tenant->workspace_id,
        ]);

        $exception = FindingException::query()->create([
            'workspace_id' => (int) $tenant->workspace_id,
            'managed_environment_id' => (int) $tenant->getKey(),
            'finding_id' => (int) $finding->getKey(),
            'requested_by_user_id' => (int) $user->getKey(),
            'owner_user_id' => (int) $user->getKey(),
            'status' => $status,
            'current_validity_state' => $status === FindingException::STATUS_REJECTED
                ? FindingException::VALIDITY_REJECTED
                : FindingException::VALIDITY_REVOKED,
            'request_reason' => 'Recently closed boundary test',
            'review_due_at' => now()->subDays($daysAgo + 1),
            'rejected_at' => $status === FindingException::STATUS_REJECTED ? now()->subDays($daysAgo) : null,
            'revoked_at' => $status === FindingException::STATUS_REVOKED ? now()->subDays($daysAgo) : null,
            'evidence_summary' => ['reference_count' => 0],
        ]);

        $decision = $exception->decisions()->create([
            'workspace_id' => (int) $tenant->workspace_id,
            'managed_environment_id' => (int) $tenant->getKey(),
            'actor_user_id' => (int) $user->getKey(),
            'decision_type' => $status === FindingException::STATUS_REJECTED
                ? FindingExceptionDecision::TYPE_REJECTED
                : FindingExceptionDecision::TYPE_REVOKED,
            'reason' => $reason,
            'metadata' => [],
            'decided_at' => now()->subDays($daysAgo),
        ]);

        $exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save();

        return $exception;
    };

    $createTerminalException(FindingException::STATUS_REJECTED, 'Recent closure reason', 2);
    $createTerminalException(FindingException::STATUS_REVOKED, 'Old closure reason', 45);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(DecisionRegister::getUrl(panel: 'admin', parameters: ['register_state' => 'recently_closed']))
        ->assertOk()
        ->assertSee('Recent closure reason')
        ->assertDontSee('Old closure reason');
});

it('does not leak cross-workspace evidence artifact links from the decision register', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'name' => 'Visible ManagedEnvironment',
    ]);
    [$user, $tenant] = createUserWithTenant($tenant, role: 'owner', workspaceRole: 'owner');

    $otherTenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'name' => 'Other workspace ManagedEnvironment',
    ]);

    $otherSnapshot = EvidenceSnapshot::query()->create([
        'workspace_id' => (int) $otherTenant->workspace_id,
        'managed_environment_id' => (int) $otherTenant->getKey(),
        'status' => EvidenceSnapshotStatus::Active->value,
        'completeness_state' => EvidenceCompletenessState::Complete->value,
        'summary' => ['finding_count' => 1],
        'generated_at' => now(),
    ]);

    $finding = Finding::factory()->for($tenant)->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

    $exception = FindingException::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'finding_id' => (int) $finding->getKey(),
        'requested_by_user_id' => (int) $user->getKey(),
        'owner_user_id' => (int) $user->getKey(),
        'status' => FindingException::STATUS_PENDING,
        'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT,
        'request_reason' => 'Cross workspace proof link test',
        'requested_at' => now()->subDay(),
        'review_due_at' => now()->addDay(),
        'evidence_summary' => ['reference_count' => 1],
    ]);

    $decision = $exception->decisions()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'actor_user_id' => (int) $user->getKey(),
        'decision_type' => FindingExceptionDecision::TYPE_REQUESTED,
        'reason' => 'Cross workspace proof link test',
        'metadata' => [],
        'decided_at' => now()->subDay(),
    ]);

    $exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save();
    $exception->evidenceReferences()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'source_type' => 'evidence_snapshot',
        'source_id' => (string) $otherSnapshot->getKey(),
        'label' => 'Other workspace snapshot',
        'summary_payload' => [],
    ]);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(DecisionRegister::getUrl(panel: 'admin'))
        ->assertOk()
        ->assertSee('1 proof item')
        ->assertSee('View proof')
        ->assertDontSee('View evidence')
        ->assertDontSee('/admin/t', false);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(EvidenceSnapshotResource::getUrl('view', ['record' => $otherSnapshot], tenant: $otherTenant, panel: 'admin'))
        ->assertNotFound();
});

it('does not leak cross-environment evidence artifact links from the decision register', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'name' => 'Visible ManagedEnvironment',
    ]);
    [$user, $tenant] = createUserWithTenant($tenant, role: 'owner', workspaceRole: 'owner');

    $otherTenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'status' => 'active',
        'name' => 'Other environment ManagedEnvironment',
    ]);

    $otherSnapshot = EvidenceSnapshot::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $otherTenant->getKey(),
        'status' => EvidenceSnapshotStatus::Active->value,
        'completeness_state' => EvidenceCompletenessState::Complete->value,
        'summary' => ['finding_count' => 1],
        'generated_at' => now(),
    ]);

    $finding = Finding::factory()->for($tenant)->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

    $exception = FindingException::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'finding_id' => (int) $finding->getKey(),
        'requested_by_user_id' => (int) $user->getKey(),
        'owner_user_id' => (int) $user->getKey(),
        'status' => FindingException::STATUS_PENDING,
        'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT,
        'request_reason' => 'Cross environment proof link test',
        'requested_at' => now()->subDay(),
        'review_due_at' => now()->addDay(),
        'evidence_summary' => ['reference_count' => 1],
    ]);

    $decision = $exception->decisions()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'actor_user_id' => (int) $user->getKey(),
        'decision_type' => FindingExceptionDecision::TYPE_REQUESTED,
        'reason' => 'Cross environment proof link test',
        'metadata' => [],
        'decided_at' => now()->subDay(),
    ]);

    $exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save();
    $exception->evidenceReferences()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'source_type' => 'evidence_snapshot',
        'source_id' => (string) $otherSnapshot->getKey(),
        'label' => 'Other environment snapshot',
        'summary_payload' => [],
    ]);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(DecisionRegister::getUrl(panel: 'admin'))
        ->assertOk()
        ->assertSee('1 proof item')
        ->assertSee('View proof')
        ->assertDontSee('View evidence')
        ->assertDontSee('/admin/t', false);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(EvidenceSnapshotResource::getUrl('view', ['record' => $otherSnapshot], tenant: $otherTenant, panel: 'admin'))
        ->assertNotFound();
});
