<?php

declare(strict_types=1);

use App\Filament\Pages\Governance\DecisionRegister;
use App\Filament\Pages\Governance\GovernanceInbox;
use App\Filament\Pages\Monitoring\EvidenceOverview;
use App\Filament\Pages\Monitoring\FindingExceptionsQueue;
use App\Filament\Pages\Reviews\CustomerReviewWorkspace;
use App\Filament\Pages\Reviews\ReviewRegister;
use App\Filament\Resources\ProviderConnectionResource;
use App\Filament\Resources\ProviderConnectionResource\Pages\ListProviderConnections;
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\ProviderConnection;
use App\Models\User;
use App\Support\EnvironmentReviewStatus;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\OperationRunLinks;
use App\Support\Workspaces\WorkspaceContext;
use Livewire\Livewire;

pest()->browser()->timeout(60_000);

it('Spec316 smokes filtered workspace hub clear and reload behavior', function (): void {
    [$user, $environmentA, $environmentB] = spec316BrowserClearFilterWorkspace();
    $workspace = $environmentA->workspace()->firstOrFail();

    $this->actingAs($user)->withSession([
        WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
        WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [
            (string) $workspace->getKey() => (int) $environmentA->getKey(),
        ],
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());
    session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
        (string) $workspace->getKey() => (int) $environmentA->getKey(),
    ]);

    $hubs = [
        'operations' => [
            'filtered_url' => OperationRunLinks::index($environmentA),
            'clean_url' => OperationRunLinks::index(),
            'wide_text' => 'Inventory sync',
        ],
        'provider connections' => [
            'filtered_url' => ProviderConnectionResource::getUrl('index', [
                'environment_id' => (int) $environmentA->getKey(),
            ], panel: 'admin'),
            'clean_url' => ProviderConnectionResource::getUrl('index', panel: 'admin'),
            'wide_text' => 'Spec316 Browser Provider B',
        ],
        'finding exceptions queue' => [
            'filtered_url' => FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
                'environment_id' => (int) $environmentA->getKey(),
            ]),
            'clean_url' => FindingExceptionsQueue::getUrl(panel: 'admin'),
            'wide_text' => $environmentB->name,
        ],
        'evidence overview' => [
            'filtered_url' => route('admin.evidence.overview', [
                'environment_id' => (int) $environmentA->getKey(),
            ]),
            'clean_url' => route('admin.evidence.overview'),
            'wide_text' => $environmentB->name,
        ],
        'review register' => [
            'filtered_url' => ReviewRegister::getUrl(panel: 'admin', parameters: [
                'environment_id' => (int) $environmentA->getKey(),
            ]),
            'clean_url' => ReviewRegister::getUrl(panel: 'admin'),
            'wide_text' => $environmentB->name,
        ],
        'customer review workspace' => [
            'filtered_url' => CustomerReviewWorkspace::environmentFilterUrl($environmentA),
            'clean_url' => CustomerReviewWorkspace::getUrl(panel: 'admin'),
            'wide_text' => $environmentB->name,
        ],
        'governance inbox' => [
            'filtered_url' => GovernanceInbox::getUrl(panel: 'admin', parameters: [
                'environment_id' => (int) $environmentA->getKey(),
            ]),
            'clean_url' => GovernanceInbox::getUrl(panel: 'admin'),
            'wide_text' => 'Spec316 Browser Governance B',
        ],
        'decision register' => [
            'filtered_url' => DecisionRegister::getUrl(panel: 'admin', parameters: [
                'environment_id' => (int) $environmentA->getKey(),
            ]),
            'clean_url' => DecisionRegister::getUrl(panel: 'admin'),
            'wide_text' => $environmentB->name,
        ],
    ];

    foreach ($hubs as $hub) {
        $cleanPath = json_encode((string) parse_url($hub['clean_url'], PHP_URL_PATH), JSON_THROW_ON_ERROR);

        $page = visit($hub['filtered_url'])
            ->waitForText('Environment filter:')
            ->assertSee($environmentA->name)
            ->assertDontSee($hub['wide_text'])
            ->assertNoJavaScriptErrors();

        $page
            ->click('[data-testid="workspace-hub-environment-filter-clear"]')
            ->waitForText(__('localization.shell.no_environment_selected'))
            ->assertDontSee('Environment filter:')
            ->assertSee($hub['wide_text'])
            ->assertScript("window.location.pathname === {$cleanPath}", true)
            ->assertScript('! window.location.search.includes("environment_id=")', true)
            ->assertScript('! window.location.search.includes("tenant=")', true)
            ->assertScript('! window.location.search.includes("managed_environment_id=")', true)
            ->assertScript('! window.location.search.includes("tenant_scope=")', true)
            ->assertScript('! window.location.search.includes("tableFilters")', true)
            ->assertNoJavaScriptErrors();

        $page->script('window.location.reload();');

        $page
            ->waitForText(__('localization.shell.no_environment_selected'))
            ->assertDontSee('Environment filter:')
            ->assertSee($hub['wide_text'])
            ->assertScript("window.location.pathname === {$cleanPath}", true)
            ->assertScript('! window.location.search.includes("environment_id=")', true)
            ->assertNoJavaScriptErrors();
    }
});

it('Spec316 smokes browser back and forward alignment for high risk hubs', function (): void {
    [$user, $environmentA, $environmentB] = spec316BrowserClearFilterWorkspace();
    $workspace = $environmentA->workspace()->firstOrFail();

    $this->actingAs($user)->withSession([
        WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    $hubs = [
        ProviderConnectionResource::getUrl('index', [
            'environment_id' => (int) $environmentA->getKey(),
        ], panel: 'admin'),
        FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
            'environment_id' => (int) $environmentA->getKey(),
        ]),
        CustomerReviewWorkspace::environmentFilterUrl($environmentA),
        route('admin.evidence.overview', [
            'environment_id' => (int) $environmentA->getKey(),
        ]),
    ];

    foreach ($hubs as $filteredUrl) {
        $page = visit($filteredUrl)
            ->waitForText('Environment filter:')
            ->assertSee($environmentA->name)
            ->assertDontSee($environmentB->name);

        $page
            ->click('[data-testid="workspace-hub-environment-filter-clear"]')
            ->waitForText(__('localization.shell.no_environment_selected'))
            ->assertDontSee('Environment filter:')
            ->assertSee($environmentB->name);

        $page->script('window.history.back();');

        $page
            ->waitForText('Environment filter:')
            ->assertSee($environmentA->name)
            ->assertDontSee($environmentB->name)
            ->assertScript('window.location.search.includes("environment_id=")', true);

        $page->script('window.history.forward();');

        $page
            ->waitForText(__('localization.shell.no_environment_selected'))
            ->assertDontSee('Environment filter:')
            ->assertSee($environmentB->name)
            ->assertScript('! window.location.search.includes("environment_id=")', true)
            ->assertNoJavaScriptErrors();
    }
});

it('Spec316 smokes persisted environment filters do not survive clean browser entry', function (): void {
    [$user, $environmentA, $environmentB] = spec316BrowserClearFilterWorkspace();
    $workspace = $environmentA->workspace()->firstOrFail();

    $this->actingAs($user)->withSession([
        WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(),
    ]);

    session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

    $cases = [
        [
            'component' => ListProviderConnections::class,
            'url' => ProviderConnectionResource::getUrl('index', panel: 'admin'),
            'filter_name' => 'tenant',
            'filter_value' => (string) $environmentA->external_id,
            'wide_text' => 'Spec316 Browser Provider B',
        ],
        [
            'component' => FindingExceptionsQueue::class,
            'url' => FindingExceptionsQueue::getUrl(panel: 'admin'),
            'filter_name' => 'managed_environment_id',
            'filter_value' => (string) $environmentA->getKey(),
            'wide_text' => $environmentB->name,
        ],
        [
            'component' => CustomerReviewWorkspace::class,
            'url' => CustomerReviewWorkspace::getUrl(panel: 'admin'),
            'filter_name' => 'managed_environment_id',
            'filter_value' => (string) $environmentA->getKey(),
            'wide_text' => $environmentB->name,
        ],
        [
            'component' => EvidenceOverview::class,
            'url' => route('admin.evidence.overview'),
            'filter_name' => 'managed_environment_id',
            'filter_value' => (string) $environmentA->getKey(),
            'wide_text' => $environmentB->name,
        ],
    ];

    foreach ($cases as $case) {
        $component = Livewire::actingAs($user)->test($case['component']);
        $filtersSessionKey = $component->instance()->getTableFiltersSessionKey();

        session()->put($filtersSessionKey, [
            $case['filter_name'] => ['value' => $case['filter_value']],
        ]);

        visit($case['url'])
            ->waitForText(__('localization.shell.no_environment_selected'))
            ->assertDontSee('Environment filter:')
            ->assertSee($case['wide_text'])
            ->assertNoJavaScriptErrors();
    }
});

/**
 * @return array{0: User, 1: ManagedEnvironment, 2: ManagedEnvironment}
 */
function spec316BrowserClearFilterWorkspace(): array
{
    $environmentA = ManagedEnvironment::factory()->active()->create([
        'name' => 'Spec316 Browser Environment A',
        'external_id' => 'spec316-browser-environment-a',
    ]);
    [$user, $environmentA] = createUserWithTenant(tenant: $environmentA, role: 'owner', workspaceRole: 'manager');

    $environmentB = ManagedEnvironment::factory()->active()->create([
        'workspace_id' => (int) $environmentA->workspace_id,
        'name' => 'Spec316 Browser Environment B',
        'external_id' => 'spec316-browser-environment-b',
    ]);
    createUserWithTenant(tenant: $environmentB, user: $user, role: 'owner', workspaceRole: 'manager');

    OperationRun::factory()->forTenant($environmentA)->create(['type' => 'policy.sync']);
    OperationRun::factory()->forTenant($environmentB)->create(['type' => 'inventory_sync']);

    spec316BrowserFindingException($environmentA, $user, 'Spec316 Browser Governance A', 'Spec316 Browser Decision A');
    spec316BrowserFindingException($environmentB, $user, 'Spec316 Browser Governance B', 'Spec316 Browser Decision B');

    ProviderConnection::factory()->create([
        'workspace_id' => (int) $environmentA->workspace_id,
        'managed_environment_id' => (int) $environmentA->getKey(),
        'display_name' => 'Spec316 Browser Provider A',
    ]);
    ProviderConnection::factory()->create([
        'workspace_id' => (int) $environmentB->workspace_id,
        'managed_environment_id' => (int) $environmentB->getKey(),
        'display_name' => 'Spec316 Browser Provider B',
    ]);

    $snapshotA = spec316BrowserEvidenceSnapshot($environmentA);
    $snapshotB = spec316BrowserEvidenceSnapshot($environmentB);

    spec316BrowserPublishedReview($environmentA, $user, $snapshotA);
    spec316BrowserPublishedReview($environmentB, $user, $snapshotB);

    return [$user, $environmentA, $environmentB];
}

function spec316BrowserFindingException(
    ManagedEnvironment $environment,
    User $actor,
    string $requestReason,
    string $decisionReason,
): FindingException {
    $finding = Finding::factory()->for($environment)->riskAccepted()->create([
        'workspace_id' => (int) $environment->workspace_id,
        'subject_external_id' => str()->slug($requestReason),
    ]);

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

    $decision = $exception->decisions()->create([
        'workspace_id' => (int) $environment->workspace_id,
        'managed_environment_id' => (int) $environment->getKey(),
        'actor_user_id' => (int) $actor->getKey(),
        'decision_type' => FindingExceptionDecision::TYPE_REQUESTED,
        'reason' => $decisionReason,
        'metadata' => [],
        'decided_at' => now()->subDay(),
    ]);

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

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

function spec316BrowserEvidenceSnapshot(ManagedEnvironment $environment): EvidenceSnapshot
{
    return EvidenceSnapshot::query()->create([
        'managed_environment_id' => (int) $environment->getKey(),
        'workspace_id' => (int) $environment->workspace_id,
        'status' => EvidenceSnapshotStatus::Active->value,
        'summary' => ['missing_dimensions' => 0, 'stale_dimensions' => 0],
        'generated_at' => now(),
    ]);
}

function spec316BrowserPublishedReview(ManagedEnvironment $environment, User $user, EvidenceSnapshot $snapshot): void
{
    $review = composeEnvironmentReviewForTest($environment, $user, $snapshot);
    $review->forceFill([
        'status' => EnvironmentReviewStatus::Published->value,
        'published_at' => now(),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();
}
