<?php

declare(strict_types=1);

use App\Models\ManagedEnvironment;
use App\Services\EntraAdminRoles\EntraAdminRolesReportService;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('requests principal expansion and uses principal display name when present', function () {
    $tenant = ManagedEnvironment::factory()->create();
    ensureDefaultProviderConnection($tenant, 'microsoft');

    $roleDefinitions = [
        [
            'id' => 'role-def-1',
            'templateId' => '62e90394-69f5-4237-9190-012177145e10',
            'displayName' => 'Global Administrator',
            'isBuiltIn' => true,
        ],
    ];

    $roleAssignments = [
        [
            'id' => 'role-assign-1',
            'roleDefinitionId' => 'role-def-1',
            'principalId' => 'principal-1',
            'directoryScopeId' => '/',
            'principal' => [
                '@odata.type' => '#microsoft.graph.user',
                'displayName' => 'Ada Lovelace',
            ],
        ],
    ];

    $calls = [];

    $this->mock(GraphClientInterface::class, function ($mock) use (&$calls, $roleDefinitions, $roleAssignments) {
        $mock->shouldReceive('listPolicies')
            ->twice()
            ->andReturnUsing(function (string $policyType, array $options) use (&$calls, $roleDefinitions, $roleAssignments): GraphResponse {
                $calls[] = [$policyType, $options];

                if ($policyType === 'entraRoleDefinitions') {
                    return new GraphResponse(true, $roleDefinitions);
                }

                return new GraphResponse(true, $roleAssignments);
            });
    });

    $result = app(EntraAdminRolesReportService::class)->generate($tenant);

    expect($calls)->toHaveCount(2);
    expect($calls[0][0])->toBe('entraRoleDefinitions');
    expect($calls[0][1])->not->toHaveKey('expand');
    expect($calls[1][0])->toBe('entraRoleAssignments');
    expect($calls[1][1]['expand'] ?? null)->toBe('principal');
    expect($calls[1][1])->toMatchArray(array_merge($calls[0][1], [
        'expand' => 'principal',
    ]));

    expect($result->payload['high_privilege'])->toHaveCount(1);
    expect($result->payload['high_privilege'][0]['principal_display_name'])->toBe('Ada Lovelace');
});

it('falls back to Unknown when principal details are missing upstream', function () {
    $tenant = ManagedEnvironment::factory()->create();
    ensureDefaultProviderConnection($tenant, 'microsoft');

    $roleDefinitions = [
        [
            'id' => 'role-def-1',
            'templateId' => '62e90394-69f5-4237-9190-012177145e10',
            'displayName' => 'Global Administrator',
            'isBuiltIn' => true,
        ],
    ];

    $roleAssignments = [
        [
            'id' => 'role-assign-1',
            'roleDefinitionId' => 'role-def-1',
            'principalId' => 'principal-1',
            'directoryScopeId' => '/',
        ],
    ];

    $calls = [];

    $this->mock(GraphClientInterface::class, function ($mock) use (&$calls, $roleDefinitions, $roleAssignments) {
        $mock->shouldReceive('listPolicies')
            ->twice()
            ->andReturnUsing(function (string $policyType, array $options) use (&$calls, $roleDefinitions, $roleAssignments): GraphResponse {
                $calls[] = [$policyType, $options];

                if ($policyType === 'entraRoleDefinitions') {
                    return new GraphResponse(true, $roleDefinitions);
                }

                return new GraphResponse(true, $roleAssignments);
            });
    });

    $result = app(EntraAdminRolesReportService::class)->generate($tenant);

    expect($calls)->toHaveCount(2);
    expect($calls[0][0])->toBe('entraRoleDefinitions');
    expect($calls[0][1])->not->toHaveKey('expand');
    expect($calls[1][0])->toBe('entraRoleAssignments');
    expect($calls[1][1]['expand'] ?? null)->toBe('principal');

    expect($result->payload['high_privilege'])->toHaveCount(1);
    expect($result->payload['high_privilege'][0]['principal_display_name'])->toBe('Unknown');
});
