<?php

declare(strict_types=1);

use App\Filament\Pages\BaselineCompareLanding;
use App\Filament\Resources\BaselineProfileResource;
use App\Filament\Resources\FindingResource;
use App\Models\User;
use App\Services\Auth\CapabilityResolver;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Support\Navigation\CanonicalNavigationContext;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Gate;
use Tests\Feature\Concerns\BuildsBaselineCompareMatrixFixtures;

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

it('returns 404 for non-members on the workspace baseline compare matrix', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();
    $nonMember = User::factory()->create();

    $this->actingAs($nonMember)->withSession([
        \App\Support\Workspaces\WorkspaceContext::SESSION_KEY => (int) $fixture['workspace']->getKey(),
    ]);

    $this->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->assertNotFound();
});

it('returns 403 for workspace members missing baseline view capability on the matrix route', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();
    $viewer = User::factory()->create();

    \App\Models\WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $fixture['workspace']->getKey(),
        'user_id' => (int) $viewer->getKey(),
        'role' => 'readonly',
    ]);

    $resolver = \Mockery::mock(WorkspaceCapabilityResolver::class);
    $resolver->shouldReceive('isMember')->andReturnTrue();
    $resolver->shouldReceive('can')->andReturnFalse();
    app()->instance(WorkspaceCapabilityResolver::class, $resolver);

    $this->actingAs($viewer)->withSession([
        \App\Support\Workspaces\WorkspaceContext::SESSION_KEY => (int) $fixture['workspace']->getKey(),
    ]);

    $this->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->assertForbidden();
});

it('returns 404 for matrix tenant drilldowns when the actor is not a tenant member', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();
    $nonMember = User::factory()->create();

    $this->actingAs($nonMember)->withSession([
        \App\Support\Workspaces\WorkspaceContext::SESSION_KEY => (int) $fixture['workspace']->getKey(),
    ]);

    $query = CanonicalNavigationContext::forBaselineCompareMatrix(
        $fixture['profile'],
        subjectKey: 'wifi-corp-profile',
    )->toQuery();

    $this->get(BaselineCompareLanding::getUrl(parameters: $query, panel: 'admin', tenant: $fixture['visibleTenant']))
        ->assertNotFound();
});

it('returns 404 for matrix tenant drilldowns when tenant view capability is missing', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $resolver = \Mockery::mock(CapabilityResolver::class);
    $resolver->shouldReceive('isMember')->andReturnTrue();
    $resolver->shouldReceive('can')->andReturnFalse();
    app()->instance(CapabilityResolver::class, $resolver);

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

    $query = CanonicalNavigationContext::forBaselineCompareMatrix(
        $fixture['profile'],
        subjectKey: 'wifi-corp-profile',
        tenant: $fixture['visibleTenant'],
    )->toQuery();

    $this->get(BaselineCompareLanding::getUrl(parameters: $query, panel: 'admin', tenant: $fixture['visibleTenant']))
        ->assertNotFound();
});

it('returns 403 for matrix finding drilldowns when findings view capability is missing', 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->actingAs($fixture['user']);
    $fixture['visibleTenant']->makeCurrent();

    Gate::define(Capabilities::TENANT_FINDINGS_VIEW, fn (): bool => false);

    $query = CanonicalNavigationContext::forBaselineCompareMatrix(
        $fixture['profile'],
        subjectKey: 'wifi-corp-profile',
        tenant: $fixture['visibleTenant'],
    )->toQuery();

    $this->get(FindingResource::getUrl('view', [
        'record' => $finding,
        ...$query,
    ], tenant: $fixture['visibleTenant']))
        ->assertForbidden();
});

it('drops foreign compare-context launch data instead of leaking another workspace profile', function (): void {
    $fixture = $this->makeBaselineCompareMatrixFixture();

    $foreignProfile = \App\Models\BaselineProfile::factory()->create();

    $this->actingAs($fixture['user']);
    $fixture['visibleTenant']->makeCurrent();

    $component = baselineCompareLandingLivewire($fixture['visibleTenant'], [
        'baseline_profile_id' => (int) $foreignProfile->getKey(),
        'subject_key' => 'wifi-corp-profile',
    ]);

    expect($component->instance()->openCompareMatrixUrl())
        ->toStartWith(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
        ->not->toContain((string) $foreignProfile->getKey());
});
