<?php

use App\Models\Policy;
use App\Models\PolicyVersion;
use App\Models\ManagedEnvironment;
use App\Services\Graph\AssignmentFetcher;
use App\Services\Graph\ScopeTagResolver;
use App\Services\Intune\PolicySnapshotService;
use App\Services\Intune\VersionService;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('persists metadata-only snapshot metadata on captured versions', function () {
    $tenant = ManagedEnvironment::factory()->create();
    ensureDefaultProviderConnection($tenant, 'microsoft');
    $policy = Policy::factory()->for($tenant)->create([
        'policy_type' => 'mamAppConfiguration',
        'platform' => 'mobile',
        'external_id' => 'A_meta_only',
        'display_name' => 'MAM Config Meta',
    ]);

    $this->mock(PolicySnapshotService::class, function ($mock) {
        $mock->shouldReceive('fetch')
            ->once()
            ->andReturn([
                'payload' => [
                    'id' => 'A_meta_only',
                    'displayName' => 'MAM Config Meta',
                    '@odata.type' => '#microsoft.graph.targetedManagedAppConfiguration',
                ],
                'metadata' => [
                    'source' => 'metadata_only',
                    'original_status' => 500,
                    'original_failure' => 'InternalServerError: upstream',
                ],
                'warnings' => [
                    'Snapshot captured from local metadata only (Graph API returned 500).',
                ],
            ]);
    });

    $this->mock(AssignmentFetcher::class, function ($mock) {
        $mock->shouldReceive('fetch')->never();
    });

    $this->mock(ScopeTagResolver::class, function ($mock) {
        $mock->shouldReceive('resolve')->never();
    });

    $service = app(VersionService::class);

    $version = $service->captureFromGraph(
        tenant: $tenant,
        policy: $policy,
        createdBy: 'tester@example.test',
        includeAssignments: false,
        includeScopeTags: false,
    );

    expect($version->metadata['source'])->toBe('metadata_only');
    expect($version->metadata['original_status'])->toBe(500);
    expect($version->metadata['original_failure'])->toContain('InternalServerError');
    expect($version->metadata['capture_source'])->toBe('version_capture');
    expect($version->metadata['warnings'])->toBeArray();
    expect($version->metadata['warnings'][0])->toContain('metadata only');
});

it('captures and reuses immutable RBAC foundation versions from payload snapshots', function () {
    $tenant = ManagedEnvironment::factory()->create();

    $policy = Policy::factory()->for($tenant)->create([
        'policy_type' => 'intuneRoleDefinition',
        'platform' => 'all',
        'external_id' => 'role-def-1',
        'display_name' => 'Policy and Profile Manager',
        'last_synced_at' => null,
    ]);

    $service = app(VersionService::class);

    $basePayload = [
        'id' => 'role-def-1',
        'displayName' => 'Policy and Profile Manager',
        'isBuiltIn' => true,
        'rolePermissions' => [
            [
                'resourceActions' => [
                    [
                        'allowedResourceActions' => [
                            'Microsoft.Intune/deviceConfigurations/read',
                        ],
                    ],
                ],
            ],
        ],
    ];

    $firstVersion = $service->captureFoundationVersion(
        policy: $policy,
        payload: $basePayload,
        createdBy: 'tester@example.test',
        metadata: [
            'kind' => 'intuneRoleDefinition',
            'graph' => [
                'resource' => 'deviceManagement/roleDefinitions',
                'apiVersion' => 'beta',
            ],
        ],
    );

    $reusedVersion = $service->captureFoundationVersion(
        policy: $policy,
        payload: $basePayload,
        createdBy: 'tester@example.test',
        metadata: [
            'kind' => 'intuneRoleDefinition',
        ],
    );

    $changedVersion = $service->captureFoundationVersion(
        policy: $policy,
        payload: array_merge($basePayload, [
            'description' => 'Updated role description',
        ]),
        createdBy: 'tester@example.test',
        metadata: [
            'kind' => 'intuneRoleDefinition',
        ],
    );

    expect($firstVersion->id)->toBe($reusedVersion->id);
    expect($changedVersion->id)->not->toBe($firstVersion->id);
    expect($changedVersion->version_number)->toBe(2);
    expect($firstVersion->metadata['capture_source'] ?? null)->toBe('foundation_capture');
    expect($firstVersion->metadata['kind'] ?? null)->toBe('intuneRoleDefinition');
    expect(PolicyVersion::query()->where('policy_id', $policy->id)->count())->toBe(2);
});
