<?php

declare(strict_types=1);

use App\Filament\Resources\RestoreRunResource\Pages\ListRestoreRuns;
use App\Filament\Widgets\Dashboard\RecoveryReadiness;
use App\Models\BackupItem;
use App\Models\BackupSet;
use App\Models\RestoreRun;
use App\Support\RestoreSafety\RestoreSafetyResolver;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\DB;
use Livewire\Livewire;

function makeHealthyBackupForRecoveryPerformance(\App\Models\ManagedEnvironment $tenant): BackupSet
{
    $backupSet = BackupSet::factory()->for($tenant)->recentCompleted()->create([
        'name' => 'Performance healthy backup',
        'item_count' => 1,
    ]);

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

    return $backupSet;
}

it('caps dashboard recovery evidence derivation to the latest 10 restore-run candidates', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
    $this->actingAs($user);

    makeHealthyBackupForRecoveryPerformance($tenant);

    $historyBackupSet = BackupSet::factory()->for($tenant)->create([
        'name' => 'Candidate cap backup',
    ]);

    foreach (range(1, 10) as $minutesAgo) {
        RestoreRun::factory()
            ->for($tenant)
            ->for($historyBackupSet)
            ->previewOnly()
            ->create([
                'created_at' => now()->subMinutes($minutesAgo),
                'started_at' => now()->subMinutes($minutesAgo),
                'completed_at' => null,
            ]);
    }

    RestoreRun::factory()
        ->for($tenant)
        ->for($historyBackupSet)
        ->failedOutcome()
        ->create([
            'created_at' => now()->subMinutes(11),
            'started_at' => now()->subMinutes(11),
            'completed_at' => now()->subMinutes(11),
        ]);

    setAdminPanelContext($tenant);

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

it('keeps the latest-10 restore-history cap when recovery evidence is derived for multiple tenants in batch', function (): void {
    [$user, $tenantA] = createUserWithTenant(role: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    $tenantB = \App\Models\ManagedEnvironment::factory()->create([
        'status' => 'active',
        'workspace_id' => (int) $tenantA->workspace_id,
        'name' => 'Second batch tenant',
    ]);
    createUserWithTenant($tenantB, $user, role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);

    makeHealthyBackupForRecoveryPerformance($tenantA);
    makeHealthyBackupForRecoveryPerformance($tenantB);

    $tenantABackup = BackupSet::factory()->for($tenantA)->create([
        'name' => 'ManagedEnvironment A candidate cap backup',
    ]);

    foreach (range(1, 10) as $minutesAgo) {
        RestoreRun::factory()
            ->for($tenantA)
            ->for($tenantABackup)
            ->previewOnly()
            ->create([
                'created_at' => now()->subMinutes($minutesAgo),
                'started_at' => now()->subMinutes($minutesAgo),
                'completed_at' => null,
            ]);
    }

    RestoreRun::factory()
        ->for($tenantA)
        ->for($tenantABackup)
        ->failedOutcome()
        ->create([
            'created_at' => now()->subMinutes(11),
            'started_at' => now()->subMinutes(11),
            'completed_at' => now()->subMinutes(11),
        ]);

    $tenantBBackup = BackupSet::factory()->for($tenantB)->create([
        'name' => 'ManagedEnvironment B weakened backup',
    ]);

    RestoreRun::factory()
        ->for($tenantB)
        ->for($tenantBBackup)
        ->completedWithFollowUp()
        ->create([
            'completed_at' => now()->subMinutes(5),
        ]);

    $evidence = app(RestoreSafetyResolver::class)->dashboardRecoveryEvidenceForTenants([
        (int) $tenantA->getKey(),
        (int) $tenantB->getKey(),
    ]);

    expect($evidence[(int) $tenantA->getKey()]['overview_state'])->toBe('unvalidated')
        ->and($evidence[(int) $tenantB->getKey()]['overview_state'])->toBe('weakened');
});

it('renders dashboard recovery posture and restore-history list with bounded query volume', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
    $this->actingAs($user);

    makeHealthyBackupForRecoveryPerformance($tenant);

    $historyBackupSet = BackupSet::factory()->for($tenant)->create([
        'name' => 'Query-shape backup',
    ]);

    foreach (range(1, 5) as $offset) {
        RestoreRun::factory()
            ->for($tenant)
            ->for($historyBackupSet)
            ->failedOutcome()
            ->create([
                'completed_at' => now()->subMinutes($offset),
            ]);
    }

    foreach (range(6, 10) as $offset) {
        RestoreRun::factory()
            ->for($tenant)
            ->for($historyBackupSet)
            ->completedWithFollowUp()
            ->create([
                'completed_at' => now()->subMinutes($offset),
            ]);
    }

    foreach (range(11, 15) as $offset) {
        RestoreRun::factory()
            ->for($tenant)
            ->for($historyBackupSet)
            ->completedOutcome()
            ->create([
                'completed_at' => now()->subMinutes($offset),
            ]);
    }

    setAdminPanelContext($tenant);

    DB::flushQueryLog();
    DB::enableQueryLog();

    assertNoOutboundHttp(function (): void {
        Livewire::test(RecoveryReadiness::class)
            ->assertSee('Recovery evidence')
            ->assertSee('Weakened');
    });

    $dashboardQueries = count(DB::getQueryLog());

    DB::flushQueryLog();
    DB::enableQueryLog();

    assertNoOutboundHttp(function () use ($user): void {
        Livewire::actingAs($user)
            ->test(ListRestoreRuns::class)
            ->assertSee('Result attention')
            ->assertSee('The restore did not complete successfully. Follow-up is still required.');
    });

    $listQueries = count(DB::getQueryLog());

    expect($dashboardQueries)->toBeLessThanOrEqual(24)
        ->and($listQueries)->toBeLessThanOrEqual(400);
});
