<?php

declare(strict_types=1);

use App\Filament\Pages\CrossEnvironmentComparePage;
use App\Jobs\Operations\CrossEnvironmentPromotionExecutionJob;
use App\Models\AuditLog;
use App\Models\BackupSet;
use App\Models\OperationRun;
use App\Models\PolicyVersion;
use App\Models\RestoreRun;
use App\Services\Audit\WorkspaceAuditLogger;
use App\Services\Intune\RestoreService;
use App\Services\OperationRunService;
use App\Services\Operations\TargetScopeConcurrencyLimiter;
use App\Support\Audit\AuditActionId;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;
use Tests\Feature\Concerns\BuildsPortfolioCompareFixtures;

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

it('audits queued promotion execution without creating restore-side writes before the worker starts', function (): void {
    Queue::fake();

    $fixture = $this->makeCrossEnvironmentCompareFixture();

    $this->createPortfolioCompareSubject(
        tenant: $fixture['sourceEnvironment'],
        displayName: 'Audit Queue Policy',
        snapshot: ['settings' => [['key' => 'audit-queue', 'value' => 1]]],
    );

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

    $policyVersionCount = PolicyVersion::query()->count();

    Livewire::withQueryParams([
        'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
        'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
        'policy_type' => ['deviceConfiguration'],
    ])
        ->actingAs($fixture['user'])
        ->test(CrossEnvironmentComparePage::class)
        ->call('generatePromotionPreflight')
        ->mountAction('executePromotion')
        ->callMountedAction()
        ->assertHasNoActionErrors();

    $run = OperationRun::query()->latest('id')->first();

    $audit = AuditLog::query()
        ->where('workspace_id', (int) $fixture['workspace']->getKey())
        ->where('action', AuditActionId::CrossEnvironmentPromotionExecutionQueued->value)
        ->latest('id')
        ->first();

    expect($run)->not->toBeNull()
        ->and($audit)->not->toBeNull()
        ->and($audit?->status)->toBe('info')
        ->and($audit?->resource_type)->toBe('operation_run')
        ->and((int) ($audit?->operation_run_id ?? 0))->toBe((int) $run?->getKey())
        ->and(data_get($audit?->metadata, 'source_environment_id'))->toBe((int) $fixture['sourceEnvironment']->getKey())
        ->and(data_get($audit?->metadata, 'target_environment_id'))->toBe((int) $fixture['targetEnvironment']->getKey())
        ->and(data_get($audit?->metadata, 'ready_count'))->toBe(1)
        ->and(data_get($audit?->metadata, 'excluded_count'))->toBe(0)
        ->and(BackupSet::query()->count())->toBe(0)
        ->and(RestoreRun::query()->count())->toBe(0)
        ->and(PolicyVersion::query()->count())->toBe($policyVersionCount);
});

it('audits terminal promotion execution truth after the queued worker completes', function (): void {
    Queue::fake();

    $fixture = $this->makeCrossEnvironmentCompareFixture();

    $this->createPortfolioCompareSubject(
        tenant: $fixture['sourceEnvironment'],
        displayName: 'Audit Completion Policy',
        snapshot: ['settings' => [['key' => 'audit-complete', 'value' => 1]]],
    );

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

    Livewire::withQueryParams([
        'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
        'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
        'policy_type' => ['deviceConfiguration'],
    ])
        ->actingAs($fixture['user'])
        ->test(CrossEnvironmentComparePage::class)
        ->call('generatePromotionPreflight')
        ->mountAction('executePromotion')
        ->callMountedAction()
        ->assertHasNoActionErrors();

    $run = OperationRun::query()->latest('id')->firstOrFail();

    $restoreService = \Mockery::mock(RestoreService::class);
    $restoreService->shouldReceive('execute')
        ->once()
        ->andReturnUsing(function ($tenant, $backupSet, array $selectedItemIds) {
            return RestoreRun::factory()->create([
                'managed_environment_id' => (int) $tenant->getKey(),
                'backup_set_id' => (int) $backupSet->getKey(),
                'requested_items' => $selectedItemIds,
                'results' => [
                    'items' => [[
                        'status' => 'applied',
                        'policy_identifier' => 'audit-complete-policy',
                    ]],
                ],
                'metadata' => [
                    'succeeded' => count($selectedItemIds),
                    'failed' => 0,
                    'partial' => 0,
                    'skipped' => 0,
                ],
            ]);
        });

    app()->instance(RestoreService::class, $restoreService);

    $job = new CrossEnvironmentPromotionExecutionJob($run);
    $job->handle(
        app(OperationRunService::class),
        $restoreService,
        app(TargetScopeConcurrencyLimiter::class),
        app(WorkspaceAuditLogger::class),
    );

    $completedAudit = AuditLog::query()
        ->where('workspace_id', (int) $fixture['workspace']->getKey())
        ->where('action', AuditActionId::CrossEnvironmentPromotionExecutionCompleted->value)
        ->latest('id')
        ->first();

    $completedRun = $run->fresh();
    $restoreRun = RestoreRun::query()->latest('id')->first();

    expect($completedRun)->not->toBeNull()
        ->and($completedRun?->status)->toBe('completed')
        ->and($completedRun?->outcome)->toBe('succeeded')
        ->and($completedAudit)->not->toBeNull()
        ->and($completedAudit?->status)->toBe('success')
        ->and($completedAudit?->resource_type)->toBe('operation_run')
        ->and((int) ($completedAudit?->operation_run_id ?? 0))->toBe((int) $completedRun?->getKey())
        ->and(data_get($completedAudit?->metadata, 'source_environment_id'))->toBe((int) $fixture['sourceEnvironment']->getKey())
        ->and(data_get($completedAudit?->metadata, 'target_environment_id'))->toBe((int) $fixture['targetEnvironment']->getKey())
        ->and(data_get($completedAudit?->metadata, 'summary_counts.created'))->toBe(1)
        ->and(data_get($completedAudit?->metadata, 'summary_counts.succeeded'))->toBe(1)
        ->and(data_get($completedAudit?->metadata, 'restore_run_id'))->toBe((int) $restoreRun?->getKey())
        ->and(BackupSet::query()->count())->toBe(1)
        ->and(RestoreRun::query()->count())->toBe(1);
});