<?php

declare(strict_types=1);

use App\Models\BackupSet;
use App\Models\RestoreRun;
use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\RestoreSafety\RestoreResultAttention;
use App\Support\RestoreSafety\RestoreSafetyResolver;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('treats preview-only restore runs as not executed', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $backupSet = BackupSet::factory()->create([
        'managed_environment_id' => $tenant->id,
    ]);

    $restoreRun = RestoreRun::factory()->create([
        'managed_environment_id' => $tenant->id,
        'backup_set_id' => $backupSet->id,
        'is_dry_run' => true,
        'status' => 'previewed',
        'results' => [],
    ]);

    $attention = app(RestoreSafetyResolver::class)->resultAttentionForRun($restoreRun);

    expect($attention->state)->toBe(RestoreResultAttention::STATE_NOT_EXECUTED)
        ->and($attention->followUpRequired)->toBeFalse();
});

it('surfaces completed runs with skipped work as follow-up required', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $backupSet = BackupSet::factory()->create([
        'managed_environment_id' => $tenant->id,
    ]);

    $restoreRun = RestoreRun::factory()->create([
        'managed_environment_id' => $tenant->id,
        'backup_set_id' => $backupSet->id,
        'is_dry_run' => false,
        'status' => 'completed',
        'results' => [
            'foundations' => [],
            'items' => [
                9 => [
                    'status' => 'applied',
                    'policy_identifier' => 'policy-9',
                    'assignment_outcomes' => [
                        ['status' => 'skipped', 'assignment' => []],
                    ],
                ],
            ],
        ],
        'metadata' => [
            'non_applied' => 1,
        ],
    ]);

    $attention = app(RestoreSafetyResolver::class)->resultAttentionForRun($restoreRun);

    expect($attention->state)->toBe(RestoreResultAttention::STATE_COMPLETED_WITH_FOLLOW_UP)
        ->and($attention->followUpRequired)->toBeTrue()
        ->and($attention->primaryNextAction)->toBe('review_skipped_items');
});

it('ignores preview-only runs when deriving tenant recovery evidence', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $backupSet = BackupSet::factory()->for($tenant)->create();

    RestoreRun::factory()
        ->for($tenant)
        ->for($backupSet)
        ->previewOnly()
        ->create([
            'completed_at' => now()->subMinutes(5),
        ]);

    $overview = app(RestoreSafetyResolver::class)->dashboardRecoveryEvidence($tenant);

    expect($overview['overview_state'])->toBe('unvalidated')
        ->and($overview['latest_relevant_restore_run_id'])->toBeNull()
        ->and($overview['latest_relevant_attention_state'])->toBeNull()
        ->and($overview['reason'])->toBe('no_history');
});

it('uses the latest relevant restore run when calmer history is newer than older failures', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $backupSet = BackupSet::factory()->for($tenant)->create();

    RestoreRun::factory()
        ->for($tenant)
        ->for($backupSet)
        ->failedOutcome()
        ->create([
            'completed_at' => now()->subHours(2),
        ]);

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

    $overview = app(RestoreSafetyResolver::class)->dashboardRecoveryEvidence($tenant);

    expect($overview['overview_state'])->toBe('no_recent_issues_visible')
        ->and($overview['latest_relevant_restore_run_id'])->toBe((int) $latestCompleted->getKey())
        ->and($overview['latest_relevant_attention_state'])->toBe(RestoreResultAttention::STATE_COMPLETED)
        ->and($overview['reason'])->toBe('no_recent_issues_visible');
});

it('keeps recent weak restore history ahead of older calmer history', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $backupSet = BackupSet::factory()->for($tenant)->create();

    RestoreRun::factory()
        ->for($tenant)
        ->for($backupSet)
        ->completedOutcome()
        ->create([
            'completed_at' => now()->subHours(2),
        ]);

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

    $overview = app(RestoreSafetyResolver::class)->dashboardRecoveryEvidence($tenant);

    expect($overview['overview_state'])->toBe('weakened')
        ->and($overview['latest_relevant_restore_run_id'])->toBe((int) $latestFailed->getKey())
        ->and($overview['latest_relevant_attention_state'])->toBe(RestoreResultAttention::STATE_FAILED)
        ->and($overview['claim_boundary'])->toBe('ManagedEnvironment recovery is not proven.')
        ->and($overview['reason'])->toBe(RestoreResultAttention::STATE_FAILED);
});

it('falls back to calm completed history when no recent weak evidence is present', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
    $this->actingAs($user);

    BackupSet::factory()->for($tenant)->recentCompleted()->create();

    $backupSet = BackupSet::factory()->for($tenant)->create();

    $latestCompleted = RestoreRun::factory()
        ->for($tenant)
        ->for($backupSet)
        ->completedOutcome()
        ->create([
            'completed_at' => now()->subMinutes(15),
        ]);

    $overview = app(RestoreSafetyResolver::class)->dashboardRecoveryEvidence($tenant);

    expect($overview['backup_posture'])->toBe(TenantBackupHealthAssessment::POSTURE_HEALTHY)
        ->and($overview['overview_state'])->toBe('no_recent_issues_visible')
        ->and($overview['latest_relevant_restore_run_id'])->toBe((int) $latestCompleted->getKey())
        ->and($overview['latest_relevant_attention_state'])->toBe(RestoreResultAttention::STATE_COMPLETED)
        ->and($overview['reason'])->toBe('no_recent_issues_visible');
});
