<?php

use App\Models\OperationRun;
use App\Models\Policy;
use App\Models\ManagedEnvironment;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use App\Services\Graph\ScopeTagResolver;
use App\Services\Intune\BackupService;
use App\Services\Intune\PolicySnapshotService;
use App\Support\Providers\ProviderReasonCodes;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery\MockInterface;

uses(RefreshDatabase::class);

test('assignment fetch operation run fails safely when graph assignment fetch fails', function () {
    app()->instance(GraphClientInterface::class, new class implements GraphClientInterface
    {
        public function listPolicies(string $policyType, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function getOrganization(array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function request(string $method, string $path, array $options = []): GraphResponse
        {
            return new GraphResponse(
                success: false,
                data: [],
                status: 400,
                errors: [
                    ['code' => 'BadRequest', 'message' => 'Bad request'],
                ],
                warnings: [],
                meta: [
                    'error_code' => 'BadRequest',
                    'error_message' => 'Assignment list request failed',
                ],
            );
        }

        public function getServicePrincipalPermissions(array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }
    });

    $tenant = ManagedEnvironment::factory()->create([
        'managed_environment_id' => 'tenant-assignment-fetch-failure',
        'status' => 'active',
    ]);
    ensureDefaultProviderConnection($tenant);

    $policy = Policy::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'external_id' => 'policy-assignment-fetch-failure',
        '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(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.failure@example.com',
        actorName: 'Assignment Fetch Failure',
        includeAssignments: true,
        includeScopeTags: true,
    );

    $backupItem = $backupSet->items()->first();
    expect($backupItem)->not->toBeNull();
    expect($backupItem?->metadata['assignments_fetch_failed'] ?? false)->toBeTrue();

    $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('failed');
    expect($assignmentFetchRun?->summary_counts ?? [])->toMatchArray([
        'total' => 1,
        'processed' => 0,
        'failed' => 1,
    ]);
    expect($assignmentFetchRun?->failure_summary[0]['code'] ?? null)->toBe('assignments.fetch_failed');
    expect(ProviderReasonCodes::isKnown((string) ($assignmentFetchRun?->failure_summary[0]['reason_code'] ?? '')))->toBeTrue();
});
