<?php

use App\Jobs\SyncPoliciesJob;
use App\Models\OperationRun;
use App\Models\ManagedEnvironment;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use App\Services\Intune\PolicySyncService;
use App\Services\OperationRunService;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;

use function Pest\Laravel\mock;

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

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

it('fails the run when supported policy types are empty', function () {
    config(['graph.enabled' => true]);
    config(['tenantpilot.supported_policy_types' => []]);

    app()->instance(GraphClientInterface::class, new FakeGraphClient);

    $tenant = ManagedEnvironment::factory()->create();
    $run = OperationRun::factory()->for($tenant)->create([
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Queued->value,
        'outcome' => OperationRunOutcome::Pending->value,
    ]);

    $job = new SyncPoliciesJob(
        tenantId: (int) $tenant->getKey(),
        types: null,
        policyIds: null,
        operationRun: $run,
    );

    $service = mock(PolicySyncService::class);
    $service->shouldNotReceive('syncPoliciesWithReport');

    $job->handle($service, app(OperationRunService::class));

    $run->refresh();

    expect($run->status)->toBe(OperationRunStatus::Completed->value)
        ->and($run->outcome)->toBe(OperationRunOutcome::Failed->value)
        ->and($run->failure_summary)->toBeArray()
        ->and($run->failure_summary[0]['code'] ?? null)->toBe('tenantpilot.supported_policy_types.empty');
});

it('accepts supported policy config passed via the types argument', function () {
    config(['graph.enabled' => true]);
    config(['tenantpilot.supported_policy_types' => []]);

    app()->instance(GraphClientInterface::class, new FakeGraphClient);

    $tenant = ManagedEnvironment::factory()->create();
    $run = OperationRun::factory()->for($tenant)->create([
        'type' => 'policy.sync',
        'status' => OperationRunStatus::Queued->value,
        'outcome' => OperationRunOutcome::Pending->value,
    ]);

    $supported = [
        ['type' => 'deviceConfiguration', 'platform' => 'all'],
    ];

    $job = new SyncPoliciesJob(
        tenantId: (int) $tenant->getKey(),
        types: $supported,
        policyIds: null,
        operationRun: $run,
    );

    $service = mock(PolicySyncService::class);
    $service->shouldReceive('syncPoliciesWithReport')
        ->once()
        ->withArgs(function (ManagedEnvironment $tenantArg, array $supportedArg) use ($tenant, $supported) {
            expect($tenantArg->getKey())->toBe($tenant->getKey());
            expect($supportedArg)->toBe($supported);

            return true;
        })
        ->andReturn([
            'synced' => [101, 102, 103],
            'failures' => [],
        ]);

    $job->handle($service, app(OperationRunService::class));

    $run->refresh();

    expect($run->status)->toBe(OperationRunStatus::Completed->value)
        ->and($run->outcome)->toBe(OperationRunOutcome::Succeeded->value)
        ->and($run->summary_counts['succeeded'] ?? null)->toBe(3);
});
