<?php

use App\Jobs\ExecuteRestoreRunJob;
use App\Models\BackupSet;
use App\Models\RestoreRun;
use App\Models\ManagedEnvironment;
use App\Services\Intune\AuditLogger;
use App\Services\Intune\RestoreService;
use App\Services\OperationRunService;
use App\Support\OperationRunOutcome;
use App\Support\RestoreRunStatus;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery\MockInterface;

uses(RefreshDatabase::class);

beforeEach(function () {
    config()->set('tenantpilot.hardening.intune_write_gate.enabled', true);
    config()->set('tenantpilot.hardening.intune_write_gate.freshness_threshold_hours', 24);
});

test('execute restore run job marks run failed when rbac_status is not_configured', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'rbac_status' => 'not_configured',
        'rbac_last_checked_at' => null,
    ]);

    $backupSet = BackupSet::create([
        'managed_environment_id' => $tenant->id,
        'name' => 'Backup',
        'status' => 'completed',
        'item_count' => 0,
    ]);

    $restoreRun = RestoreRun::create([
        'managed_environment_id' => $tenant->id,
        'backup_set_id' => $backupSet->id,
        'requested_by' => 'actor@example.com',
        'is_dry_run' => false,
        'status' => RestoreRunStatus::Queued->value,
        'requested_items' => null,
        'preview' => [],
        'results' => null,
        'metadata' => [],
    ]);

    $this->mock(RestoreService::class, function (MockInterface $mock) {
        $mock->shouldNotReceive('executeForRun');
    });

    $operationRun = app(OperationRunService::class)->ensureRun(
        tenant: $tenant,
        type: 'restore.execute',
        inputs: [
            'restore_run_id' => $restoreRun->id,
            'backup_set_id' => $backupSet->id,
            'is_dry_run' => false,
        ],
    );

    $job = new ExecuteRestoreRunJob($restoreRun->id, 'actor@example.com', 'Actor', $operationRun);
    $job->handle(app(RestoreService::class), app(AuditLogger::class));

    $restoreRun->refresh();
    $operationRun->refresh();

    expect($restoreRun->status)->toBe(RestoreRunStatus::Failed->value)
        ->and($restoreRun->failure_reason)->toContain('not configured')
        ->and($operationRun->outcome)->toBe(OperationRunOutcome::Failed->value);

    $failures = is_array($operationRun->failure_summary) ? $operationRun->failure_summary : [];
    $reasonCodes = array_column($failures, 'reason_code');

    expect($reasonCodes)->toContain('intune_rbac.not_configured');
});

test('execute restore run job marks run failed when rbac_status is stale', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'rbac_status' => 'ok',
        'rbac_last_checked_at' => now()->subHours(48),
    ]);

    $backupSet = BackupSet::create([
        'managed_environment_id' => $tenant->id,
        'name' => 'Backup',
        'status' => 'completed',
        'item_count' => 0,
    ]);

    $restoreRun = RestoreRun::create([
        'managed_environment_id' => $tenant->id,
        'backup_set_id' => $backupSet->id,
        'requested_by' => 'actor@example.com',
        'is_dry_run' => false,
        'status' => RestoreRunStatus::Queued->value,
        'requested_items' => null,
        'preview' => [],
        'results' => null,
        'metadata' => [],
    ]);

    $this->mock(RestoreService::class, function (MockInterface $mock) {
        $mock->shouldNotReceive('executeForRun');
    });

    $operationRun = app(OperationRunService::class)->ensureRun(
        tenant: $tenant,
        type: 'restore.execute',
        inputs: [
            'restore_run_id' => $restoreRun->id,
            'backup_set_id' => $backupSet->id,
            'is_dry_run' => false,
        ],
    );

    $job = new ExecuteRestoreRunJob($restoreRun->id, 'actor@example.com', 'Actor', $operationRun);
    $job->handle(app(RestoreService::class), app(AuditLogger::class));

    $operationRun->refresh();

    $failures = is_array($operationRun->failure_summary) ? $operationRun->failure_summary : [];
    $reasonCodes = array_column($failures, 'reason_code');

    expect($reasonCodes)->toContain('intune_rbac.stale');
});
