<?php

declare(strict_types=1);

use App\Filament\Pages\Governance\DecisionRegister;
use App\Models\EvidenceSnapshot;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\FindingExceptionDecision;
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Models\User;
use App\Support\Evidence\EvidenceCompletenessState;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('renders open and recently closed decision rows for visible tenants only', function (): void {
    $visibleTenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'name' => 'Visible ManagedEnvironment',
        'external_id' => 'visible-tenant',
    ]);
    [$user, $visibleTenant] = createUserWithTenant($visibleTenant, role: 'readonly', workspaceRole: 'readonly');

    $hiddenTenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'workspace_id' => (int) $visibleTenant->workspace_id,
        'name' => 'Hidden ManagedEnvironment',
        'external_id' => 'hidden-tenant',
    ]);

    decisionRegisterPageException(
        tenant: $visibleTenant,
        actor: $user,
        status: FindingException::STATUS_PENDING,
        validityState: FindingException::VALIDITY_MISSING_SUPPORT,
        decisionType: FindingExceptionDecision::TYPE_REQUESTED,
        decisionReason: 'Visible approval request',
        exceptionAttributes: [
            'requested_at' => now()->subDays(2),
            'review_due_at' => now()->addDay(),
        ],
        decisionAttributes: [
            'decided_at' => now()->subDays(2),
        ],
    );

    decisionRegisterPageException(
        tenant: $visibleTenant,
        actor: $user,
        status: FindingException::STATUS_REJECTED,
        validityState: FindingException::VALIDITY_REJECTED,
        decisionType: FindingExceptionDecision::TYPE_REJECTED,
        decisionReason: 'Recently rejected closure reason',
        exceptionAttributes: [
            'rejected_at' => now()->subDays(2),
            'review_due_at' => now()->subDays(3),
        ],
        decisionAttributes: [
            'decided_at' => now()->subDays(2),
        ],
    );

    decisionRegisterPageException(
        tenant: $hiddenTenant,
        actor: $user,
        status: FindingException::STATUS_PENDING,
        validityState: FindingException::VALIDITY_MISSING_SUPPORT,
        decisionType: FindingExceptionDecision::TYPE_REQUESTED,
        decisionReason: 'Hidden tenant request',
    );

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id])
        ->get(DecisionRegister::getUrl(panel: 'admin'))
        ->assertOk()
        ->assertSee('Decision register')
        ->assertSee('Visible ManagedEnvironment')
        ->assertSee('Review approval')
        ->assertSee('Open decision')
        ->assertDontSee('Recently rejected closure reason')
        ->assertDontSee('Hidden tenant request');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id])
        ->get(DecisionRegister::getUrl(panel: 'admin').'?register_state=recently_closed')
        ->assertOk()
        ->assertSee('Recently rejected closure reason')
        ->assertDontSee('Visible approval request');
});

it('shows truthful filtered empty states for tenant and register-state filters', function (): void {
    $alphaTenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'name' => 'Alpha ManagedEnvironment',
        'external_id' => 'alpha-tenant',
    ]);
    [$user, $alphaTenant] = createUserWithTenant($alphaTenant, role: 'owner', workspaceRole: 'owner');

    $bravoTenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'workspace_id' => (int) $alphaTenant->workspace_id,
        'name' => 'Bravo ManagedEnvironment',
        'external_id' => 'bravo-tenant',
    ]);

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

    decisionRegisterPageException(
        tenant: $bravoTenant,
        actor: $user,
        status: FindingException::STATUS_PENDING,
        validityState: FindingException::VALIDITY_MISSING_SUPPORT,
        decisionType: FindingExceptionDecision::TYPE_REQUESTED,
        decisionReason: 'Bravo tenant request',
    );

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id])
        ->get(DecisionRegister::getUrl(panel: 'admin').'?environment_id='.(string) $alphaTenant->getKey())
        ->assertOk()
        ->assertSee('This environment filter is hiding other visible decision follow-through')
        ->assertSee('Clear environment filter');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id])
        ->get(DecisionRegister::getUrl(panel: 'admin').'?register_state=recently_closed')
        ->assertOk()
        ->assertSee('No recently closed decisions match this filter right now.');
});

it('renders proof and operation affordances only when real links are available', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
        'name' => 'Proof ManagedEnvironment',
        'external_id' => 'proof-tenant',
    ]);
    [$user, $tenant] = createUserWithTenant($tenant, role: 'owner', workspaceRole: 'owner');

    $run = OperationRun::factory()->forTenant($tenant)->create([
        'type' => 'tenant.evidence.snapshot.generate',
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
        'completed_at' => now(),
    ]);

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

    $withProof = decisionRegisterPageException(
        tenant: $tenant,
        actor: $user,
        status: FindingException::STATUS_PENDING,
        validityState: FindingException::VALIDITY_MISSING_SUPPORT,
        decisionType: FindingExceptionDecision::TYPE_REQUESTED,
        decisionReason: 'Proof-backed request',
        exceptionAttributes: [
            'evidence_summary' => ['reference_count' => 1],
            'review_due_at' => now()->addDay(),
        ],
    );

    $withProof->evidenceReferences()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'source_type' => 'evidence_snapshot',
        'source_id' => (string) $snapshot->getKey(),
        'label' => 'Current evidence snapshot',
        'summary_payload' => [],
    ]);

    decisionRegisterPageException(
        tenant: $tenant,
        actor: $user,
        status: FindingException::STATUS_ACTIVE,
        validityState: FindingException::VALIDITY_VALID,
        decisionType: FindingExceptionDecision::TYPE_APPROVED,
        decisionReason: 'No proof request',
        exceptionAttributes: [
            'approved_by_user_id' => (int) $user->getKey(),
            'approved_at' => now()->subDay(),
            'effective_from' => now()->subDay(),
            'evidence_summary' => ['reference_count' => 0],
            'review_due_at' => now()->addDays(2),
        ],
    );

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

/**
 * @param  array<string, mixed>  $exceptionAttributes
 * @param  array<string, mixed>  $decisionAttributes
 */
function decisionRegisterPageException(
    ManagedEnvironment $tenant,
    User $actor,
    string $status,
    string $validityState,
    string $decisionType,
    string $decisionReason,
    array $exceptionAttributes = [],
    array $decisionAttributes = [],
): FindingException {
    $finding = Finding::factory()->for($tenant)->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);

    $exception = FindingException::query()->create(array_merge([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'finding_id' => (int) $finding->getKey(),
        'requested_by_user_id' => (int) $actor->getKey(),
        'owner_user_id' => (int) $actor->getKey(),
        'status' => $status,
        'current_validity_state' => $validityState,
        'request_reason' => 'Decision register page test',
        'requested_at' => now()->subDay(),
        'review_due_at' => now()->addDay(),
        'evidence_summary' => ['reference_count' => 0],
    ], $exceptionAttributes));

    $decision = $exception->decisions()->create(array_merge([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'actor_user_id' => (int) $actor->getKey(),
        'decision_type' => $decisionType,
        'reason' => $decisionReason,
        'metadata' => [],
        'decided_at' => now()->subDay(),
    ], $decisionAttributes));

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

    return $exception->fresh(['currentDecision']);
}
