<?php

use App\Models\OperationRun;
use App\Models\Policy;
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\BackupService;
use App\Services\Intune\PolicySnapshotService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery\MockInterface;

uses(RefreshDatabase::class);

test('backup capture with assignments writes an assignment fetch operation run keyed by backup item', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => 'tenant-assignment-fetch-run',
        'status' => 'active',
    ]);
    ensureDefaultProviderConnection($tenant);

    $policy = Policy::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'external_id' => 'policy-assignment-fetch-run',
        'policy_type' => 'settingsCatalogPolicy',
        'platform' => 'windows',
    ]);

    $this->mock(PolicySnapshotService::class, function (MockInterface $mock) use ($policy): void {
        $mock->shouldReceive('fetch')
            ->once()
            ->andReturn([
                'payload' => [
                    '@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
                    'id' => (string) $policy->external_id,
                    'name' => 'Policy snapshot',
                    'roleScopeTagIds' => ['0'],
                ],
                'metadata' => [],
                'warnings' => [],
            ]);
    });

    $this->mock(AssignmentFetcher::class, function (MockInterface $mock): void {
        $mock->shouldReceive('fetch')
            ->once()
            ->andReturn([
                [
                    'id' => 'assignment-1',
                    'target' => [
                        '@odata.type' => '#microsoft.graph.groupAssignmentTarget',
                        'groupId' => 'group-1',
                    ],
                ],
            ]);
    });

    $this->mock(GroupResolver::class, function (MockInterface $mock): void {
        $mock->shouldReceive('resolveGroupIds')
            ->once()
            ->andReturn([
                'group-1' => [
                    'id' => 'group-1',
                    'displayName' => 'Group One',
                    'orphaned' => false,
                ],
            ]);
    });

    $this->mock(AssignmentFilterResolver::class, function (MockInterface $mock): void {
        $mock->shouldReceive('resolve')
            ->once()
            ->andReturn([]);
    });

    $this->mock(ScopeTagResolver::class, function (MockInterface $mock) use ($tenant): void {
        $mock->shouldReceive('resolve')
            ->once()
            ->with(['0'], $tenant)
            ->andReturn([
                ['id' => '0', 'displayName' => 'Default'],
            ]);
    });

    $backupSet = app(BackupService::class)->createBackupSet(
        tenant: $tenant,
        policyIds: [(int) $policy->getKey()],
        actorEmail: 'assignment.fetch.run@example.com',
        actorName: 'Assignment Fetch',
        includeAssignments: true,
        includeScopeTags: true,
    );

    $backupItem = $backupSet->items()->first();
    expect($backupItem)->not->toBeNull();

    $assignmentFetchRun = OperationRun::query()
        ->where('managed_environment_id', (int) $tenant->getKey())
        ->where('type', 'assignments.fetch')
        ->latest('id')
        ->first();

    expect($assignmentFetchRun)->not->toBeNull();
    expect($assignmentFetchRun?->status)->toBe('completed');
    expect($assignmentFetchRun?->outcome)->toBe('succeeded');
    expect($assignmentFetchRun?->context['backup_item_id'] ?? null)->toBe((int) $backupItem?->getKey());
    expect($assignmentFetchRun?->summary_counts ?? [])->toMatchArray([
        'total' => 1,
        'processed' => 1,
        'failed' => 0,
    ]);
});
