<?php

declare(strict_types=1);

use App\Filament\Pages\CrossEnvironmentComparePage;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\Feature\Concerns\BuildsPortfolioCompareFixtures;

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

it('returns 404 for non-members on the cross-environment compare route', function (): void {
    $workspace = Workspace::factory()->create();
    $user = User::factory()->create();

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get(CrossEnvironmentComparePage::getUrl(panel: 'admin'))
        ->assertNotFound();
});

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

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $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([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get(CrossEnvironmentComparePage::getUrl(panel: 'admin'))
        ->assertForbidden();
});

it('returns 404 when the requested target environment is outside the actor scope', function (): void {
    $fixture = $this->makeCrossEnvironmentCompareFixture();
    $hiddenTarget = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $fixture['workspace']->getKey(),
        'name' => 'Hidden Target',
    ]);

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

    $this->withSession($session)
        ->get(CrossEnvironmentComparePage::getUrl(parameters: [
            'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
            'target_environment_id' => (int) $hiddenTarget->getKey(),
        ], panel: 'admin'))
        ->assertNotFound();
});

it('keeps promotion preflight visible but disabled for readonly members and forbids forced execution', function (): void {
    $fixture = $this->makeCrossEnvironmentCompareFixture(workspaceRole: 'readonly', tenantRole: 'readonly');

    $this->createPortfolioCompareSubject(
        tenant: $fixture['sourceEnvironment'],
        displayName: 'Readonly Policy',
        snapshot: ['settings' => [['key' => 'readonly', 'value' => 1]]],
    );
    $this->createPortfolioCompareSubject(
        tenant: $fixture['targetEnvironment'],
        displayName: 'Readonly Policy',
        snapshot: ['settings' => [['key' => 'readonly', 'value' => 1]]],
    );

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

    $query = [
        'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
        'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
        'policy_type' => ['deviceConfiguration'],
    ];

    Livewire::withQueryParams($query)
        ->actingAs($fixture['user'])
        ->test(CrossEnvironmentComparePage::class)
        ->assertActionVisible('generatePromotionPreflight')
        ->assertActionDisabled('generatePromotionPreflight')
        ->assertActionExists('generatePromotionPreflight', fn (Action $action): bool => $action->getTooltip() === 'You need workspace baseline manage access to generate a promotion preflight.')
        ->call('generatePromotionPreflight')
        ->assertForbidden();
});