<?php

declare(strict_types=1);

use App\Models\ManagedEnvironment;
use App\Models\ProviderConnection;
use App\Models\ManagedEnvironmentPermission;
use App\Support\Providers\Capabilities\ProviderCapabilityEvaluator;
use App\Support\Providers\Capabilities\ProviderCapabilityStatus;
use App\Support\Providers\ProviderReasonCodes;
use App\Support\Verification\ManagedEnvironmentPermissionCheckClusters;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

if (! function_exists('spec283ConfiguredPermissionRows')) {
    function spec283ConfiguredPermissionRows(): array
    {
        return array_merge(
            config('intune_permissions.permissions', []),
            config('entra_permissions.permissions', []),
        );
    }
}

if (! function_exists('spec283SeedRequirementRows')) {
    function spec283SeedRequirementRows(ManagedEnvironment $tenant, array $requirementKeys, array $missingKeys = [], array $errorKeys = []): void
    {
        foreach (spec283ConfiguredPermissionRows() as $permission) {
            if (! is_array($permission)) {
                continue;
            }

            $mappedRequirementKeys = ManagedEnvironmentPermissionCheckClusters::requirementKeysForPermissionRow($permission);

            if (array_intersect($requirementKeys, $mappedRequirementKeys) === []) {
                continue;
            }

            $permissionKey = (string) ($permission['key'] ?? '');

            ManagedEnvironmentPermission::query()->updateOrCreate(
                [
                    'managed_environment_id' => (int) $tenant->getKey(),
                    'permission_key' => $permissionKey,
                    'workspace_id' => (int) $tenant->workspace_id,
                ],
                [
                    'status' => in_array($permissionKey, $errorKeys, true)
                        ? 'error'
                        : (in_array($permissionKey, $missingKeys, true) ? 'missing' : 'granted'),
                    'details' => ['source' => 'spec-283-test'],
                    'last_checked_at' => now(),
                ],
            );
        }
    }
}

it('evaluates supported provider capabilities from stored permission evidence', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => '11111111-1111-1111-1111-111111111111',
    ]);
    $connection = ProviderConnection::factory()->withCredential()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'entra_tenant_id' => '11111111-1111-1111-1111-111111111111',
        'provider' => 'microsoft',
        'verification_status' => 'healthy',
    ]);

    spec283SeedRequirementRows($tenant, ['permissions.intune_configuration', 'permissions.intune_apps']);

    $result = app(ProviderCapabilityEvaluator::class)->evaluate($tenant, $connection, 'inventory_read');

    expect($result->status)->toBe(ProviderCapabilityStatus::Supported)
        ->and($result->missingRequirementKeys)->toBe([])
        ->and($result->blocksExecution())->toBeFalse();
});

it('returns capability-first missing and blocked states', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => '22222222-2222-2222-2222-222222222222',
    ]);
    $connection = ProviderConnection::factory()->withCredential()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'entra_tenant_id' => '22222222-2222-2222-2222-222222222222',
        'provider' => 'microsoft',
        'verification_status' => 'healthy',
    ]);

    $missing = app(ProviderCapabilityEvaluator::class)->evaluate($tenant, $connection, 'directory_groups_read');

    expect($missing->status)->toBe(ProviderCapabilityStatus::Missing)
        ->and($missing->reasonCode)->toBe(ProviderReasonCodes::ProviderPermissionMissing)
        ->and($missing->missingRequirementKeys)->toContain('permissions.directory_groups');

    $connection->forceFill(['is_enabled' => false])->save();

    $blocked = app(ProviderCapabilityEvaluator::class)->evaluate($tenant, $connection->fresh(), 'directory_groups_read');

    expect($blocked->status)->toBe(ProviderCapabilityStatus::Blocked)
        ->and($blocked->reasonCode)->toBe(ProviderReasonCodes::ProviderConnectionInvalid);
});

it('treats admin consent as the provider connection check prerequisite', function (): void {
    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => '33333333-3333-3333-3333-333333333333',
    ]);
    $connection = ProviderConnection::factory()->withCredential()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'managed_environment_id' => (int) $tenant->getKey(),
        'entra_tenant_id' => '33333333-3333-3333-3333-333333333333',
        'provider' => 'microsoft',
        'consent_status' => 'required',
    ]);

    $result = app(ProviderCapabilityEvaluator::class)->evaluate($tenant, $connection, 'provider_connection_check');

    expect($result->status)->toBe(ProviderCapabilityStatus::Missing)
        ->and($result->reasonCode)->toBe(ProviderReasonCodes::ProviderConsentMissing)
        ->and($result->providerRequirementKeys)->toBe(['permissions.admin_consent']);
});
