<?php

use App\Jobs\RunInventorySyncJob;
use App\Models\InventorySyncRun;
use App\Services\BulkOperationService;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use App\Services\Intune\AuditLogger;
use App\Services\Inventory\InventorySyncService;
use Mockery\MockInterface;

it('executes a pending inventory sync run and updates bulk progress + initiator attribution', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->mock(GraphClientInterface::class, function (MockInterface $mock) {
        $mock->shouldReceive('listPolicies')
            ->atLeast()
            ->once()
            ->andReturn(new GraphResponse(true, [], 200));
    });

    $sync = app(InventorySyncService::class);
    $selectionPayload = $sync->defaultSelectionPayload();
    $computed = $sync->normalizeAndHashSelection($selectionPayload);
    $policyTypes = $computed['selection']['policy_types'];
    $run = $sync->createPendingRunForUser($tenant, $user, $computed['selection']);

    $bulkRun = app(BulkOperationService::class)->createRun(
        tenant: $tenant,
        user: $user,
        resource: 'inventory',
        action: 'sync',
        itemIds: $policyTypes,
        totalItems: count($policyTypes),
    );

    $job = new RunInventorySyncJob(
        tenantId: (int) $tenant->getKey(),
        userId: (int) $user->getKey(),
        bulkRunId: (int) $bulkRun->getKey(),
        inventorySyncRunId: (int) $run->getKey(),
    );

    $job->handle(app(BulkOperationService::class), $sync, app(AuditLogger::class));

    $run->refresh();
    $bulkRun->refresh();

    expect($run->user_id)->toBe($user->id);
    expect($run->status)->toBe(InventorySyncRun::STATUS_SUCCESS);
    expect($run->started_at)->not->toBeNull();
    expect($run->finished_at)->not->toBeNull();

    expect($bulkRun->status)->toBe('completed');
    expect($bulkRun->failed)->toBe(0);
    expect($bulkRun->skipped)->toBe(0);
    expect($bulkRun->processed_items)->toBeGreaterThan(0);
    expect($bulkRun->processed_items)->toBe($bulkRun->succeeded);
});

it('maps skipped inventory sync runs to bulk progress as skipped with reason', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $sync = app(InventorySyncService::class);
    $selectionPayload = $sync->defaultSelectionPayload();
    $run = $sync->createPendingRunForUser($tenant, $user, $selectionPayload);

    $computed = $sync->normalizeAndHashSelection($selectionPayload);
    $policyTypes = $computed['selection']['policy_types'];

    $run->update(['selection_payload' => $computed['selection']]);

    $bulkRun = app(BulkOperationService::class)->createRun(
        tenant: $tenant,
        user: $user,
        resource: 'inventory',
        action: 'sync',
        itemIds: $policyTypes,
        totalItems: count($policyTypes),
    );

    $mockSync = \Mockery::mock(InventorySyncService::class);
    $mockSync
        ->shouldReceive('executePendingRun')
        ->once()
        ->andReturnUsing(function (InventorySyncRun $inventorySyncRun) {
            $inventorySyncRun->forceFill([
                'status' => InventorySyncRun::STATUS_SKIPPED,
                'error_codes' => ['locked'],
                'selection_payload' => $inventorySyncRun->selection_payload ?? [],
                'started_at' => now(),
                'finished_at' => now(),
            ])->save();

            return $inventorySyncRun;
        });

    $job = new RunInventorySyncJob(
        tenantId: (int) $tenant->getKey(),
        userId: (int) $user->getKey(),
        bulkRunId: (int) $bulkRun->getKey(),
        inventorySyncRunId: (int) $run->getKey(),
    );

    $job->handle(app(BulkOperationService::class), $mockSync, app(AuditLogger::class));

    $run->refresh();
    $bulkRun->refresh();

    expect($run->status)->toBe(InventorySyncRun::STATUS_SKIPPED);

    expect($bulkRun->status)->toBe('completed')
        ->and($bulkRun->processed_items)->toBe(count($policyTypes))
        ->and($bulkRun->skipped)->toBe(count($policyTypes))
        ->and($bulkRun->succeeded)->toBe(0)
        ->and($bulkRun->failed)->toBe(0);

    expect($bulkRun->failures)->toBeArray();
    expect($bulkRun->failures[0]['type'] ?? null)->toBe('skipped');
    expect($bulkRun->failures[0]['reason'] ?? null)->toBe('locked');
});
