<?php

use App\Models\ManagedEnvironment;
use App\Support\Links\RequiredPermissionsLinks;
use App\Support\Verification\ManagedEnvironmentPermissionCheckClusters;
use App\Support\Verification\VerificationCheckStatus;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('marks a cluster as failed and blocking when an application permission is missing', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['external_id' => 'tenant-a']);

    $checks = ManagedEnvironmentPermissionCheckClusters::buildChecks($tenant, [
        [
            'key' => 'Directory.Read.All',
            'type' => 'application',
            'description' => null,
            'features' => [],
            'status' => 'granted',
            'details' => null,
        ],
        [
            'key' => 'Group.Read.All',
            'type' => 'application',
            'description' => null,
            'features' => [],
            'status' => 'missing',
            'details' => null,
        ],
    ]);

    $directoryCheck = collect($checks)->firstWhere('key', 'permissions.directory_groups');

    expect($directoryCheck)->toBeArray();
    expect($directoryCheck['status'] ?? null)->toBe(VerificationCheckStatus::Fail->value);
    expect($directoryCheck['blocking'] ?? null)->toBeTrue();

    expect($directoryCheck['next_steps'][0]['url'] ?? null)
        ->toBe(RequiredPermissionsLinks::requiredPermissions($tenant));
});

it('marks a cluster as warn and non-blocking when only delegated permissions are missing', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['external_id' => 'tenant-b']);

    $checks = ManagedEnvironmentPermissionCheckClusters::buildChecks($tenant, [
        [
            'key' => 'DeviceManagementApps.Read.All',
            'type' => 'delegated',
            'description' => null,
            'features' => [],
            'status' => 'missing',
            'details' => null,
        ],
    ]);

    $appsCheck = collect($checks)->firstWhere('key', 'permissions.intune_apps');

    expect($appsCheck)->toBeArray();
    expect($appsCheck['status'] ?? null)->toBe(VerificationCheckStatus::Warn->value);
    expect($appsCheck['blocking'] ?? null)->toBeFalse();
});

it('marks a cluster as skipped when no mapped permissions are present', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['external_id' => 'tenant-c']);

    $checks = ManagedEnvironmentPermissionCheckClusters::buildChecks($tenant, []);

    $rbacCheck = collect($checks)->firstWhere('key', 'permissions.intune_rbac_assignments');

    expect($rbacCheck)->toBeArray();
    expect($rbacCheck['status'] ?? null)->toBe(VerificationCheckStatus::Skip->value);
});

it('marks a cluster as passed when all mapped permissions are granted', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['external_id' => 'tenant-d']);

    $checks = ManagedEnvironmentPermissionCheckClusters::buildChecks($tenant, [
        [
            'key' => 'Directory.Read.All',
            'type' => 'application',
            'description' => null,
            'features' => [],
            'status' => 'granted',
            'details' => null,
        ],
        [
            'key' => 'Group.Read.All',
            'type' => 'application',
            'description' => null,
            'features' => [],
            'status' => 'granted',
            'details' => null,
        ],
    ]);

    $directoryCheck = collect($checks)->firstWhere('key', 'permissions.directory_groups');

    expect($directoryCheck)->toBeArray();
    expect($directoryCheck['status'] ?? null)->toBe(VerificationCheckStatus::Pass->value);
    expect($directoryCheck['next_steps'] ?? null)->toBeArray()->toBeEmpty();
});

it('degrades permission clusters to warnings when inventory is not fresh', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['external_id' => 'tenant-e']);

    $checks = ManagedEnvironmentPermissionCheckClusters::buildChecks(
        tenant: $tenant,
        permissions: [
            [
                'key' => 'Directory.Read.All',
                'type' => 'application',
                'description' => null,
                'features' => [],
                'status' => 'missing',
                'details' => null,
            ],
        ],
        inventory: [
            'fresh' => false,
            'reason_code' => 'throttled',
            'message' => 'Unable to refresh observed permissions inventory during this run. Retry verification.',
        ],
    );

    $adminConsentCheck = collect($checks)->firstWhere('key', 'permissions.admin_consent');

    expect($adminConsentCheck)->toBeArray();
    expect($adminConsentCheck['status'] ?? null)->toBe(VerificationCheckStatus::Warn->value);
    expect($adminConsentCheck['blocking'] ?? null)->toBeFalse();
    expect($adminConsentCheck['reason_code'] ?? null)->toBe('rate_limited');
    expect($adminConsentCheck['next_steps'] ?? [])->not->toBeEmpty();
    expect((string) ($adminConsentCheck['message'] ?? ''))->toContain('Unable to refresh observed permissions inventory');
});
