<?php

declare(strict_types=1);

use App\Filament\Resources\InventoryItemResource\Pages\ListInventoryItems;
use App\Jobs\RunInventorySyncJob;
use App\Models\OperationRun;
use App\Services\Auth\CapabilityResolver;
use App\Services\Intune\AuditLogger;
use App\Services\Inventory\InventorySyncService;
use App\Services\OperationRunService;
use App\Support\Auth\Capabilities;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;

function runQueuedInventoryJobThroughMiddleware(object $job, Closure $terminal): mixed
{
    $pipeline = array_reduce(
        array_reverse($job->middleware()),
        fn (Closure $next, object $middleware): Closure => fn (object $job): mixed => $middleware->handle($job, $next),
        $terminal,
    );

    return $pipeline($job);
}

it('stores actor-bound execution metadata when inventory sync is queued', function (): void {
    Queue::fake();

    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    Livewire::test(ListInventoryItems::class)
        ->callAction('run_inventory_sync', data: [
            'policy_types' => ['deviceConfiguration'],
            'include_foundations' => false,
            'include_dependencies' => false,
        ]);

    $opRun = OperationRun::query()
        ->where('managed_environment_id', $tenant->getKey())
        ->where('type', 'inventory.sync')
        ->latest('id')
        ->first();

    expect($opRun)->not->toBeNull()
        ->and($opRun?->context)->toMatchArray([
            'execution_authority_mode' => 'actor_bound',
            'required_capability' => Capabilities::TENANT_INVENTORY_SYNC_RUN,
        ]);
});

it('blocks inventory execution when the initiator loses inventory capability before start', function (): void {
    Queue::fake();

    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    Livewire::test(ListInventoryItems::class)
        ->callAction('run_inventory_sync', data: [
            'policy_types' => ['deviceConfiguration'],
            'include_foundations' => false,
            'include_dependencies' => false,
        ]);

    $capturedJob = null;

    Queue::assertPushed(RunInventorySyncJob::class, function (RunInventorySyncJob $job) use (&$capturedJob): bool {
        $capturedJob = $job;

        return true;
    });

    expect($capturedJob)->toBeInstanceOf(RunInventorySyncJob::class);

    $user->workspaces()->updateExistingPivot((int) $tenant->workspace_id, ['role' => 'readonly']);
    app(CapabilityResolver::class)->clearCache();
    app(\App\Services\Auth\WorkspaceCapabilityResolver::class)->clearCache();

    $terminalInvoked = false;

    runQueuedInventoryJobThroughMiddleware(
        $capturedJob,
        function (RunInventorySyncJob $job) use (&$terminalInvoked): mixed {
            $terminalInvoked = true;

            return $job;
        },
    );

    $capturedJob->operationRun?->refresh();

    expect($terminalInvoked)->toBeFalse()
        ->and($capturedJob->operationRun?->outcome?->value ?? $capturedJob->operationRun?->outcome)->toBe('blocked')
        ->and($capturedJob->operationRun?->context['reason_code'] ?? null)->toBe('missing_capability')
        ->and($capturedJob->operationRun?->context['execution_legitimacy']['metadata']['required_capability'] ?? null)->toBe(Capabilities::TENANT_INVENTORY_SYNC_RUN);
});

it('allows inventory execution when legitimacy still holds', function (): void {
    Queue::fake();

    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $this->actingAs($user);

    $tenant->makeCurrent();
    Filament::setTenant($tenant, true);

    Livewire::test(ListInventoryItems::class)
        ->callAction('run_inventory_sync', data: [
            'policy_types' => ['deviceConfiguration'],
            'include_foundations' => false,
            'include_dependencies' => false,
        ]);

    $capturedJob = null;

    Queue::assertPushed(RunInventorySyncJob::class, function (RunInventorySyncJob $job) use (&$capturedJob): bool {
        $capturedJob = $job;

        return true;
    });

    $this->mock(InventorySyncService::class, function ($mock): void {
        $mock->shouldReceive('executeSelection')
            ->once()
            ->andReturn([
                'status' => 'success',
                'had_errors' => false,
                'error_codes' => [],
                'error_context' => [],
                'errors_count' => 0,
                'items_observed_count' => 0,
                'items_upserted_count' => 0,
                'processed_policy_types' => ['deviceConfiguration'],
                'failed_policy_types' => [],
                'skipped_policy_types' => [],
            ]);
    });

    runQueuedInventoryJobThroughMiddleware(
        $capturedJob,
        fn (RunInventorySyncJob $job): mixed => $job->handle(
            app(InventorySyncService::class),
            app(AuditLogger::class),
            app(OperationRunService::class),
        ),
    );

    $capturedJob->operationRun?->refresh();

    expect($capturedJob->operationRun?->outcome?->value ?? $capturedJob->operationRun?->outcome)->toBe('succeeded');
});
