<?php

declare(strict_types=1);

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\RestoreRunResource;
use App\Filament\Resources\ReviewPackResource;
use App\Models\AuditLog;
use App\Models\BackupSet;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\FindingExceptionDecision;
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Models\RestoreRun;
use App\Models\ReviewPack;
use App\Support\Navigation\RelatedNavigationResolver;
use App\Support\OperationRunLinks;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\Ui\GovernanceArtifactTruth\ArtifactTruthPresenter;
use App\Support\Workspaces\WorkspaceContext;

function setGovernanceArtifactAdminContext(ManagedEnvironment $tenant): void
{
    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(),
    ]);
}

function governanceArtifactAuditRecord(ManagedEnvironment $tenant, string $resourceType, int|string $resourceId): AuditLog
{
    return AuditLog::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'actor_email' => 'governance@example.com',
        'actor_name' => 'Governance Operator',
        'action' => 'governance.updated',
        'status' => 'success',
        'resource_type' => $resourceType,
        'resource_id' => (string) $resourceId,
        'summary' => 'Governance resource updated',
        'metadata' => [],
        'recorded_at' => now(),
    ]);
}

it('keeps evidence snapshot truth drillthroughs on workspace-first operation routes', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', setUiContext: false);

    $snapshot = seedEnvironmentReviewEvidence($tenant);

    $run = OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::EvidenceSnapshotGenerate->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Succeeded->value,
        ]);

    $snapshot->forceFill([
        'operation_run_id' => (int) $run->getKey(),
    ])->save();

    $this->actingAs($user);
    setGovernanceArtifactAdminContext($tenant);

    $envelope = app(ArtifactTruthPresenter::class)->forEvidenceSnapshotFresh($snapshot->fresh());

    expect($envelope->nextActionUrl)->toBe(OperationRunLinks::tenantlessView($run))
        ->and(parse_url((string) $envelope->nextActionUrl, PHP_URL_PATH))
        ->toBe('/admin/workspaces/'.$tenant->workspace->getRouteKey().'/operations/'.$run->getRouteKey())
        ->not->toContain('/admin/t/');
});

it('builds workspace-first related record links for governance operations', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', setUiContext: false);

    $backupSet = BackupSet::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
    ]);
    $backupSetRun = OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::BackupSetUpdate->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Succeeded->value,
            'context' => [
                'backup_set_id' => (int) $backupSet->getKey(),
            ],
        ]);

    $restoreRun = RestoreRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
    ]);
    $restoreOperation = OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::RestoreExecute->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Succeeded->value,
            'context' => [
                'restore_run_id' => (int) $restoreRun->getKey(),
            ],
        ]);

    $snapshot = seedEnvironmentReviewEvidence($tenant);
    $snapshotRun = OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::EvidenceSnapshotGenerate->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Succeeded->value,
        ]);
    $snapshot->forceFill([
        'operation_run_id' => (int) $snapshotRun->getKey(),
    ])->save();

    $review = composeEnvironmentReviewForTest($tenant, $user, $snapshot);
    $reviewRun = OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::EnvironmentReviewCompose->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Succeeded->value,
        ]);
    $review->forceFill([
        'operation_run_id' => (int) $reviewRun->getKey(),
    ])->save();

    $packRun = OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::ReviewPackGenerate->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Succeeded->value,
        ]);
    $pack = ReviewPack::factory()->ready()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'environment_review_id' => (int) $review->getKey(),
        'evidence_snapshot_id' => (int) $snapshot->getKey(),
        'initiated_by_user_id' => (int) $user->getKey(),
        'operation_run_id' => (int) $packRun->getKey(),
        'expires_at' => now()->addDay(),
    ]);

    $this->actingAs($user);
    setGovernanceArtifactAdminContext($tenant);

    $backupLinks = OperationRunLinks::related($backupSetRun, $tenant);
    $restoreLinks = OperationRunLinks::related($restoreOperation, $tenant);
    $snapshotLinks = OperationRunLinks::related($snapshotRun, $tenant);
    $reviewLinks = OperationRunLinks::related($reviewRun, $tenant);
    $packLinks = OperationRunLinks::related($packRun, $tenant);

    expect($backupLinks)->toMatchArray([
        OperationRunLinks::collectionLabel() => OperationRunLinks::index($tenant),
        'Backup Sets' => BackupSetResource::getUrl('index', tenant: $tenant),
        'Backup Set' => BackupSetResource::getUrl('view', ['record' => (int) $backupSet->getKey()], tenant: $tenant),
    ]);

    expect($restoreLinks)->toMatchArray([
        OperationRunLinks::collectionLabel() => OperationRunLinks::index($tenant),
        'Restore Runs' => RestoreRunResource::getUrl('index', tenant: $tenant),
        'Restore Run' => RestoreRunResource::getUrl('view', ['record' => (int) $restoreRun->getKey()], tenant: $tenant),
    ]);

    expect($snapshotLinks)->toMatchArray([
        OperationRunLinks::collectionLabel() => OperationRunLinks::index($tenant),
        'Evidence Snapshot' => EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant),
    ]);

    expect($reviewLinks)->toMatchArray([
        OperationRunLinks::collectionLabel() => OperationRunLinks::index($tenant),
        'ManagedEnvironment Review' => EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $review], $tenant),
    ]);

    expect($packLinks)->toMatchArray([
        OperationRunLinks::collectionLabel() => OperationRunLinks::index($tenant),
        'Review Pack' => ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $tenant),
    ]);

    foreach ([$backupLinks, $restoreLinks, $snapshotLinks, $reviewLinks, $packLinks] as $links) {
        foreach ($links as $url) {
            expect(parse_url($url, PHP_URL_PATH))
                ->toBeString()
                ->not->toContain('/admin/t/');
        }
    }
});

it('builds workspace-first audit target links for governance artifact records', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner', setUiContext: false);

    $backupSet = BackupSet::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
    ]);
    $restoreRun = RestoreRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
    ]);
    $finding = Finding::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
    ]);
    $findingException = FindingException::query()->create([
        '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' => 'Temporary exception request',
        'requested_at' => now(),
        'review_due_at' => now()->addWeek(),
        'evidence_summary' => ['reference_count' => 0],
    ]);
    $decision = $findingException->decisions()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'actor_user_id' => (int) $user->getKey(),
        'decision_type' => FindingExceptionDecision::TYPE_REQUESTED,
        'reason' => 'Temporary exception request',
        'metadata' => [],
        'decided_at' => now(),
    ]);
    $findingException->forceFill([
        'current_decision_id' => (int) $decision->getKey(),
    ])->save();

    $this->actingAs($user);
    setGovernanceArtifactAdminContext($tenant);

    $resolver = app(RelatedNavigationResolver::class);

    $cases = [
        [
            'audit' => governanceArtifactAuditRecord($tenant, 'backup_set', (int) $backupSet->getKey()),
            'label' => 'Open backup set',
            'url' => BackupSetResource::getUrl('view', ['record' => (int) $backupSet->getKey()], tenant: $tenant),
        ],
        [
            'audit' => governanceArtifactAuditRecord($tenant, 'restore_run', (int) $restoreRun->getKey()),
            'label' => 'Open restore run',
            'url' => RestoreRunResource::getUrl('view', ['record' => (int) $restoreRun->getKey()], tenant: $tenant),
        ],
        [
            'audit' => governanceArtifactAuditRecord($tenant, 'finding', (int) $finding->getKey()),
            'label' => 'Open finding',
            'url' => FindingResource::getUrl('view', ['record' => (int) $finding->getKey()], tenant: $tenant),
        ],
        [
            'audit' => governanceArtifactAuditRecord($tenant, 'finding_exception', (int) $findingException->getKey()),
            'label' => 'Open finding exception',
            'url' => FindingExceptionResource::getUrl('view', ['record' => $findingException], tenant: $tenant),
        ],
    ];

    foreach ($cases as $case) {
        $link = $resolver->auditTargetLink($case['audit']);

        expect($link)->toMatchArray([
            'label' => $case['label'],
            'url' => $case['url'],
        ]);

        expect(parse_url($link['url'], PHP_URL_PATH))
            ->toBeString()
            ->not->toContain('/admin/t/');
    }
});
