<?php

declare(strict_types=1);

use App\Filament\Pages\EnvironmentDashboard;
use App\Filament\Resources\RestoreRunResource;
use App\Filament\Widgets\Dashboard\NeedsAttention;
use App\Filament\Widgets\Dashboard\RecoveryReadiness;
use App\Models\BackupItem;
use App\Models\BackupSet;
use App\Models\RestoreRun;
use App\Models\ManagedEnvironment;
use App\Services\Auth\CapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Support\Rbac\UiTooltips;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Gate;
use Livewire\Livewire;

use function Pest\Laravel\mock;

function seedRecoveryVisibilityScenario(ManagedEnvironment $tenant): RestoreRun
{
    $backupSet = BackupSet::factory()->for($tenant)->recentCompleted()->create([
        'name' => 'Recovery visibility backup',
        'item_count' => 1,
    ]);

    BackupItem::factory()->for($tenant)->for($backupSet)->create([
        'payload' => ['id' => 'recovery-visibility-policy'],
        'metadata' => [],
        'assignments' => [],
    ]);

    return RestoreRun::factory()
        ->for($tenant)
        ->for($backupSet)
        ->failedOutcome()
        ->create([
            'completed_at' => now()->subMinutes(10),
        ]);
}

it('keeps recovery drillthrough inspectable for readonly tenant members', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user] = createUserWithTenant($tenant, role: 'readonly');
    $restoreRun = seedRecoveryVisibilityScenario($tenant);

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

    Livewire::test(NeedsAttention::class)
        ->assertSee('Recent restore failed')
        ->assertSee('Open restore run');

    Livewire::test(RecoveryReadiness::class)
        ->assertSee('Recovery evidence')
        ->assertSee('Weakened');

    $this->get(EnvironmentDashboard::getUrl(tenant: $tenant))
        ->assertOk();

    $this->get(RestoreRunResource::getUrl('index', tenant: $tenant))
        ->assertOk();

    $this->get(RestoreRunResource::getUrl('view', [
        'record' => (int) $restoreRun->getKey(),
    ], panel: 'admin', tenant: $tenant))
        ->assertOk();
});

it('keeps recovery summaries cautious while restore-history drillthrough is forbidden for in-scope members without view capability', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $restoreRun = seedRecoveryVisibilityScenario($tenant);

    $this->actingAs($user);

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

    mock(CapabilityResolver::class, function ($mock) use ($tenant): void {
        $mock->shouldReceive('primeMemberships')->andReturnNull();
        $mock->shouldReceive('isMember')
            ->andReturnUsing(static fn ($user, ManagedEnvironment $resolvedTenant): bool => (int) $resolvedTenant->getKey() === (int) $tenant->getKey());

        $mock->shouldReceive('can')
            ->andReturnUsing(static function ($user, ManagedEnvironment $resolvedTenant, string $capability) use ($tenant): bool {
                expect((int) $resolvedTenant->getKey())->toBe((int) $tenant->getKey());

                return match ($capability) {
                    Capabilities::TENANT_VIEW => false,
                    default => true,
                };
            });
    });

    setAdminPanelContext($tenant);

    Livewire::test(NeedsAttention::class)
        ->assertSee('Recent restore failed')
        ->assertSee(UiTooltips::INSUFFICIENT_PERMISSION)
        ->assertSee('Open restore run');

    Livewire::test(RecoveryReadiness::class)
        ->assertSee('Recovery evidence')
        ->assertSee('Weakened')
        ->assertSee(UiTooltips::INSUFFICIENT_PERMISSION);

    $this->get(RestoreRunResource::getUrl('index', tenant: $tenant))
        ->assertForbidden();

    $this->get(RestoreRunResource::getUrl('view', [
        'record' => (int) $restoreRun->getKey(),
    ], panel: 'admin', tenant: $tenant))
        ->assertForbidden();
});

it('keeps dashboard and restore-history recovery surfaces deny-as-not-found for non-members', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    $otherTenant = ManagedEnvironment::factory()->create();
    [$user] = createUserWithTenant($otherTenant, role: 'owner');
    $restoreRun = seedRecoveryVisibilityScenario($tenant);

    $this->actingAs($user);

    $this->get(EnvironmentDashboard::getUrl(tenant: $tenant))
        ->assertNotFound();

    $this->get(RestoreRunResource::getUrl('index', tenant: $tenant))
        ->assertNotFound();

    $this->get(RestoreRunResource::getUrl('view', [
        'record' => (int) $restoreRun->getKey(),
    ], panel: 'admin', tenant: $tenant))
        ->assertNotFound();
});
