<?php

declare(strict_types=1);

require_once dirname(__DIR__).'/Baselines/Support/FakeCompareStrategy.php';

use App\Filament\Pages\BaselineCompareMatrix;
use App\Filament\Resources\BaselineProfileResource;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Models\WorkspaceMembership;
use App\Support\Baselines\Compare\CompareStrategyRegistry;
use App\Support\Baselines\Compare\IntuneCompareStrategy;
use App\Support\Governance\GovernanceSubjectTaxonomyRegistry;
use Filament\Actions\Action;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\Feature\Baselines\Support\FakeCompareStrategy;
use Tests\Feature\Baselines\Support\FakeGovernanceSubjectTaxonomyRegistry;
use Tests\Feature\Concerns\BuildsBaselineCompareMatrixFixtures;

uses(RefreshDatabase::class, BuildsBaselineCompareMatrixFixtures::class);

it('renders dense auto mode with sticky subject behavior and compact support surfaces', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $run = $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenantTwo'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenant'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $this->makeBaselineCompareMatrixFinding(
        $fixture['visibleTenantTwo'],
        $fixture['profile'],
        $run,
        'wifi-corp-profile',
    );

    $session = $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace'], $fixture['visibleTenant']);

    $this->withSession($session)
        ->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->assertOk()
        ->assertSee('Visible-set baseline')
        ->assertSee('Requested: Auto mode. Resolved: Dense mode.')
        ->assertDontSee('Monitoring landing')
        ->assertDontSee('Focused review lane')
        ->assertDontSee('fonts/filament/filament/inter/inter-latin-wght-normal', false)
        ->assertDontSee('Passive auto-refresh every 5 seconds')
        ->assertSee('Grouped legend')
        ->assertSee('Apply filters')
        ->assertSee('Compact unlocks at one visible environment')
        ->assertSee('Dense multi-environment scan')
        ->assertSee('Open finding')
        ->assertSee('More follow-up')
        ->assertSee('data-testid="baseline-compare-matrix-dense-shell"', false)
        ->assertSee('sticky left-0', false);
});

it('stages heavy filter changes until apply and preserves mode and subject continuity in drilldown urls', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $run = $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenant'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $finding = $this->makeBaselineCompareMatrixFinding(
        $fixture['visibleTenant'],
        $fixture['profile'],
        $run,
        'wifi-corp-profile',
    );

    $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenantTwo'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace'], $fixture['visibleTenant']);

    $component = Livewire::withQueryParams([
        'mode' => 'dense',
        'policy_type' => ['deviceConfiguration'],
        'state' => ['differ'],
        'severity' => ['high'],
        'subject_key' => 'wifi-corp-profile',
    ])
        ->actingAs($fixture['user'])
        ->test(BaselineCompareMatrix::class, ['record' => $fixture['profile']->getKey()])
        ->assertSet('requestedMode', 'dense')
        ->assertSee('Requested: Dense mode. Resolved: Dense mode.')
        ->assertSee('Focused subject')
        ->assertSee('wifi-corp-profile');

    expect($component->instance()->hasStagedFilterChanges())->toBeFalse();

    $component
        ->set('draftSelectedPolicyTypes', ['compliancePolicy'])
        ->set('draftSelectedStates', ['match'])
        ->set('draftSelectedSeverities', [])
        ->set('draftTenantSort', 'freshness_urgency')
        ->set('draftSubjectSort', 'display_name')
        ->assertSee('Draft filters are staged');

    expect($component->instance()->hasStagedFilterChanges())->toBeTrue();

    $component->call('applyFilters')->assertRedirect(
        BaselineProfileResource::compareMatrixUrl($fixture['profile']).'?mode=dense&policy_type%5B0%5D=compliancePolicy&state%5B0%5D=match&tenant_sort=freshness_urgency&subject_sort=display_name&subject_key=wifi-corp-profile'
    );

    $applied = Livewire::withQueryParams([
        'mode' => 'dense',
        'policy_type' => ['compliancePolicy'],
        'state' => ['match'],
        'tenant_sort' => 'freshness_urgency',
        'subject_sort' => 'display_name',
        'subject_key' => 'wifi-corp-profile',
    ])
        ->actingAs($fixture['user'])
        ->test(BaselineCompareMatrix::class, ['record' => $fixture['profile']->getKey()]);

    $tenantCompareUrl = $applied->instance()->tenantCompareUrl((int) $fixture['visibleTenant']->getKey(), 'wifi-corp-profile');
    $findingUrl = $applied->instance()->findingUrl((int) $fixture['visibleTenant']->getKey(), (int) $finding->getKey(), 'wifi-corp-profile');

    expect(urldecode((string) $tenantCompareUrl))->toContain('mode=dense')
        ->and(urldecode((string) $tenantCompareUrl))->toContain('subject_key=wifi-corp-profile')
        ->and(urldecode((string) $findingUrl))->toContain('mode=dense')
        ->and($findingUrl)->toContain('nav%5Bsource_surface%5D=baseline_compare_matrix');

    $applied->call('resetFilters')->assertRedirect(
        BaselineProfileResource::compareMatrixUrl($fixture['profile']).'?mode=dense'
    );
});

it('resolves auto to compact for the visible-set-only single-tenant edge case and still allows dense override', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $run = $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenant'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenantTwo'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $this->makeBaselineCompareMatrixFinding(
        $fixture['visibleTenant'],
        $fixture['profile'],
        $run,
        'wifi-corp-profile',
        ['severity' => 'critical'],
    );

    $viewer = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $fixture['workspace']->getKey(),
        'user_id' => (int) $viewer->getKey(),
        'role' => 'owner',
    ]);
    createUserWithTenant(
        tenant: ManagedEnvironment::factory()->create(['workspace_id' => (int) $fixture['workspace']->getKey()]),
        user: $viewer,
        role: 'owner',
    );

    $viewer->tenants()->syncWithoutDetaching([
        (int) $fixture['visibleTenant']->getKey() => ['role' => 'owner'],
    ]);

    $session = $this->setAdminWorkspaceContext($viewer, $fixture['workspace'], $fixture['visibleTenant']);

    $this->withSession($session)
        ->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->assertOk()
        ->assertSee('Requested: Auto mode. Resolved: Compact mode.')
        ->assertSee('Compact compare results')
        ->assertSee('data-testid="baseline-compare-matrix-compact-shell"', false)
        ->assertDontSee('data-testid="baseline-compare-matrix-dense-shell"', false);

    $this->withSession($session)
        ->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']).'?mode=dense')
        ->assertOk()
        ->assertSee('Requested: Dense mode. Resolved: Dense mode.')
        ->assertSee('data-testid="baseline-compare-matrix-dense-shell"', false);
});

it('renders a blocked state when the baseline profile has no usable reference snapshot', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $fixture['snapshot']->markIncomplete();

    $session = $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);

    $this->withSession($session)
        ->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->assertOk()
        ->assertSee('No usable reference snapshot')
        ->assertSee('Capture a complete baseline snapshot before using the compare matrix.');
});

it('disables compare-assigned-tenants when the scope spans multiple compare strategy families', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    app()->instance(GovernanceSubjectTaxonomyRegistry::class, new FakeGovernanceSubjectTaxonomyRegistry);
    app()->instance(CompareStrategyRegistry::class, new CompareStrategyRegistry([
        app(IntuneCompareStrategy::class),
        app(FakeCompareStrategy::class),
    ]));

    $fixture['profile']->update([
        'scope_jsonb' => [
            'version' => 2,
            'entries' => [
                [
                    'domain_key' => 'intune',
                    'subject_class' => 'policy',
                    'subject_type_keys' => ['deviceConfiguration'],
                    'filters' => [],
                ],
                [
                    'domain_key' => 'entra',
                    'subject_class' => 'control',
                    'subject_type_keys' => ['conditionalAccessPolicy'],
                    'filters' => [],
                ],
            ],
        ],
    ]);

    $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);

    Livewire::actingAs($fixture['user'])
        ->test(BaselineCompareMatrix::class, ['record' => $fixture['profile']->getKey()])
        ->assertActionVisible('compareAssignedTenants')
        ->assertActionDisabled('compareAssignedTenants')
        ->assertActionExists('compareAssignedTenants', fn (Action $action): bool => $action->getTooltip() === 'The selected governed subjects span multiple compare strategy families and must be narrowed before comparing assigned environments.');
});

it('renders an empty state when the baseline profile has no assigned environments', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $fixture['profile']->tenantAssignments()->delete();

    $session = $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);

    $this->withSession($session)
        ->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->assertOk()
        ->assertSee('No assigned environments');
});

it('renders an empty state when the assigned set is not visible to the current actor', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();
    $viewer = User::factory()->create();

    $scopedTenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $fixture['workspace']->getKey(),
        'status' => 'active',
    ]);

    createUserWithTenant(tenant: $scopedTenant, user: $viewer, role: 'owner');

    $session = $this->setAdminWorkspaceContext($viewer, $fixture['workspace']);

    $this->withSession($session)
        ->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->assertOk()
        ->assertSee('No visible assigned environments');
});

it('renders a passive auto-refresh cue instead of a perpetual blocking state while compare runs remain active', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenant'],
        $fixture['profile'],
        $fixture['snapshot'],
        attributes: [
            'status' => \App\Support\OperationRunStatus::Queued->value,
            'outcome' => \App\Support\OperationRunOutcome::Pending->value,
            'completed_at' => null,
            'started_at' => now(),
        ],
    );

    $session = $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);

    $this->withSession($session)
        ->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->assertOk()
        ->assertSee('Passive auto-refresh every 5 seconds')
        ->assertSee('wire:poll.5s="pollMatrix"', false)
        ->assertSee('Refresh matrix');
});

it('renders a filtered zero-result state that preserves mode and offers reset filters as the primary cta', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenant'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenantTwo'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $session = $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);

    $this->withSession($session)
        ->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']).'?mode=dense&state[]=missing')
        ->assertOk()
        ->assertSee('Requested: Dense mode. Resolved: Dense mode.')
        ->assertSee('No rows match the current filters')
        ->assertSee('Reset filters');
});

it('drops draft-only filter edits on remount while preserving the applied focus subject from the query', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $this->makeBaselineCompareMatrixRun(
        $fixture['visibleTenant'],
        $fixture['profile'],
        $fixture['snapshot'],
    );

    $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace'], $fixture['visibleTenant']);

    $component = Livewire::withQueryParams([
        'subject_key' => 'wifi-corp-profile',
    ])
        ->actingAs($fixture['user'])
        ->test(BaselineCompareMatrix::class, ['record' => $fixture['profile']->getKey()])
        ->assertSet('focusedSubjectKey', 'wifi-corp-profile')
        ->set('draftSelectedPolicyTypes', ['compliancePolicy'])
        ->set('draftSelectedStates', ['match'])
        ->assertSee('Draft filters are staged');

    expect($component->instance()->hasStagedFilterChanges())->toBeTrue();

    Livewire::withQueryParams([
        'subject_key' => 'wifi-corp-profile',
    ])
        ->actingAs($fixture['user'])
        ->test(BaselineCompareMatrix::class, ['record' => $fixture['profile']->getKey()])
        ->assertSet('focusedSubjectKey', 'wifi-corp-profile')
        ->assertSet('draftSelectedPolicyTypes', [])
        ->assertSet('draftSelectedStates', [])
        ->assertDontSee('Draft filters are staged');
});
