<?php

use App\Jobs\RestoreAssignmentsJob;
use App\Models\BackupSet;
use App\Models\RestoreRun;
use App\Models\ManagedEnvironment;
use App\Services\AssignmentRestoreService;
use App\Services\OperationRunService;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
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('restore assignments job marks run failed when rbac 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::Running->value,
        'requested_items' => null,
        'preview' => [],
        'results' => null,
        'metadata' => [],
    ]);

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

    $operationRun = app(OperationRunService::class)->ensureRun(
        tenant: $tenant,
        type: 'assignments.restore',
        inputs: [
            'restore_run_id' => $restoreRun->id,
            'policy_type' => 'deviceConfiguration',
            'policy_id' => 'test-policy-id',
        ],
    );

    $assignments = [
        ['target' => ['@odata.type' => '#microsoft.graph.allLicensedUsersAssignmentTarget']],
    ];

    $job = new RestoreAssignmentsJob(
        restoreRunId: $restoreRun->id,
        tenantId: (int) $tenant->getKey(),
        policyType: 'deviceConfiguration',
        policyId: 'test-policy-id',
        assignments: $assignments,
        groupMapping: [],
        foundationMapping: [],
        actorEmail: 'actor@example.com',
        actorName: 'Actor',
        operationRun: $operationRun,
    );

    $job->handle(
        app(AssignmentRestoreService::class),
        app(OperationRunService::class),
    );

    $operationRun->refresh();

    expect($operationRun->outcome)->toBe(OperationRunOutcome::Failed->value)
        ->and($operationRun->status)->toBe(OperationRunStatus::Completed->value);

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

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

test('restore assignments job marks run failed when rbac is not configured', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'rbac_status' => null,
        '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::Running->value,
        'requested_items' => null,
        'preview' => [],
        'results' => null,
        'metadata' => [],
    ]);

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

    $operationRun = app(OperationRunService::class)->ensureRun(
        tenant: $tenant,
        type: 'assignments.restore',
        inputs: [
            'restore_run_id' => $restoreRun->id,
            'policy_type' => 'deviceConfiguration',
            'policy_id' => 'another-policy-id',
        ],
    );

    $assignments = [
        ['target' => ['@odata.type' => '#microsoft.graph.allLicensedUsersAssignmentTarget']],
    ];

    $job = new RestoreAssignmentsJob(
        restoreRunId: $restoreRun->id,
        tenantId: (int) $tenant->getKey(),
        policyType: 'deviceConfiguration',
        policyId: 'another-policy-id',
        assignments: $assignments,
        groupMapping: [],
        foundationMapping: [],
        actorEmail: 'actor@example.com',
        actorName: 'Actor',
        operationRun: $operationRun,
    );

    $job->handle(
        app(AssignmentRestoreService::class),
        app(OperationRunService::class),
    );

    $operationRun->refresh();

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

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