<?php

use App\Models\Policy;
use App\Models\PolicyVersion;
use App\Models\ManagedEnvironment;
use App\Services\Graph\AssignmentFetcher;
use App\Services\Graph\AssignmentFilterResolver;
use App\Services\Graph\GroupResolver;
use App\Services\Graph\ScopeTagResolver;
use App\Services\Intune\AuditLogger;
use App\Services\Intune\PolicySnapshotRedactor;
use App\Services\Intune\PolicySnapshotService;
use App\Services\Intune\VersionService;
use App\Services\Providers\MicrosoftGraphOptionsResolver;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('retries and succeeds after a policy_versions unique collision during capture', function () {
    $tenant = ManagedEnvironment::factory()->create();
    $policy = Policy::factory()->for($tenant)->create();
    $policy->load('tenant');

    $service = new VersionService(
        auditLogger: app(AuditLogger::class),
        snapshotService: Mockery::mock(PolicySnapshotService::class),
        snapshotRedactor: new PolicySnapshotRedactor,
        assignmentFetcher: Mockery::mock(AssignmentFetcher::class),
        groupResolver: Mockery::mock(GroupResolver::class),
        assignmentFilterResolver: Mockery::mock(AssignmentFilterResolver::class),
        scopeTagResolver: Mockery::mock(ScopeTagResolver::class),
        graphOptionsResolver: app(MicrosoftGraphOptionsResolver::class),
    );

    $fired = false;
    $collisionInserted = false;
    $dispatcher = PolicyVersion::getEventDispatcher();

    PolicyVersion::creating(function (PolicyVersion $model) use (&$fired, &$collisionInserted): void {
        if ($fired) {
            return;
        }

        $fired = true;

        PolicyVersion::withoutEvents(function () use ($model, &$collisionInserted): void {
            PolicyVersion::query()->create([
                'managed_environment_id' => $model->managed_environment_id,
                'policy_id' => $model->policy_id,
                'version_number' => $model->version_number,
                'policy_type' => $model->policy_type,
                'platform' => $model->platform,
                'created_by' => $model->created_by,
                'captured_at' => now(),
                'snapshot' => $model->snapshot,
                'metadata' => $model->metadata,
                'assignments' => $model->assignments,
                'scope_tags' => $model->scope_tags,
                'assignments_hash' => $model->assignments_hash,
                'scope_tags_hash' => $model->scope_tags_hash,
            ]);

            $collisionInserted = true;
        });
    });

    try {
        $version = $service->captureVersion(
            policy: $policy,
            payload: ['id' => 'p-1'],
            createdBy: 'tester@example.com',
            metadata: ['source' => 'test'],
            assignments: null,
            scopeTags: null,
        );
    } finally {
        PolicyVersion::flushEventListeners();
        PolicyVersion::setEventDispatcher($dispatcher);
    }

    expect($fired)->toBeTrue();
    expect($collisionInserted)->toBeTrue();
    expect($version->policy_id)->toBe($policy->getKey());
    expect($version->version_number)->toBe(1);
    expect(PolicyVersion::query()->where('policy_id', $policy->getKey())->count())->toBe(1);
});
