<?php

use App\Jobs\SyncPoliciesJob;
use App\Models\Policy;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use App\Services\OperationRunService;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('policy sync updates selected policies from graph and updates the operation run', function () {
    $tenant = ManagedEnvironment::factory()->create([
        'status' => 'active',
    ]);
    $tenant->makeCurrent();

    $user = User::factory()->create();
    createUserWithTenant(tenant: $tenant, user: $user, role: 'owner');

    ensureDefaultProviderConnection($tenant);

    $policies = Policy::factory()
        ->count(3)
        ->create([
            'managed_environment_id' => $tenant->id,
            'policy_type' => 'deviceConfiguration',
            'platform' => 'windows10AndLater',
            'last_synced_at' => null,
            'ignored_at' => null,
        ]);

    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, [
                'payload' => [
                    'id' => $policyId,
                    'displayName' => "Synced {$policyId}",
                    'platform' => $options['platform'] ?? null,
                    'example' => 'value',
                ],
            ]);
        }

        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 getServicePrincipalPermissions(array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }

        public function request(string $method, string $path, array $options = []): GraphResponse
        {
            return new GraphResponse(true, []);
        }
    });

    /** @var OperationRunService $runs */
    $runs = app(OperationRunService::class);

    $selectedIds = $policies
        ->pluck('id')
        ->map(static fn ($id): int => (int) $id)
        ->sort()
        ->values()
        ->all();

    $opRun = $runs->ensureRun(
        tenant: $tenant,
        type: 'policy.sync',
        inputs: [
            'scope' => 'subset',
            'policy_ids' => $selectedIds,
        ],
        initiator: $user,
    );

    SyncPoliciesJob::dispatchSync(
        tenantId: (int) $tenant->getKey(),
        types: null,
        policyIds: $selectedIds,
        operationRun: $opRun,
    );

    $opRun->refresh();

    expect($opRun->status)->toBe('completed');
    expect($opRun->outcome)->toBe('succeeded');
    expect($opRun->summary_counts)->toMatchArray([
        'total' => 3,
        'processed' => 3,
        'succeeded' => 3,
        'failed' => 0,
        'skipped' => 0,
    ]);

    $policies->each(function (Policy $policy) {
        $policy->refresh();

        expect($policy->last_synced_at)->not->toBeNull();
        expect($policy->display_name)->toBe("Synced {$policy->external_id}");
        expect($policy->metadata)->toMatchArray([
            'example' => 'value',
        ]);
    });
});
