<?php

use App\Jobs\Middleware\TrackOperationRun;
use App\Models\OperationRun;
use App\Services\OperationRunService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

it('does not mark an operation run completed when the job is released', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    /** @var OperationRunService $operationRunService */
    $operationRunService = app(OperationRunService::class);
    $operationRun = $operationRunService->ensureRun(
        tenant: $tenant,
        type: 'test.release',
        inputs: ['foo' => 'bar'],
        initiator: $user,
    );

    $job = new class($operationRun) implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

        public function __construct(public OperationRun $operationRun)
        {
            $this->withFakeQueueInteractions();
        }
    };

    $middleware = new TrackOperationRun;

    $middleware->handle($job, function ($job): void {
        $job->release(60);
    });

    $operationRun->refresh();
    expect($operationRun->status)->toBe('running');
    expect($operationRun->outcome)->toBe('pending');
});

it('marks an operation run failed when the wrapped job throws inside middleware execution', function () {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    /** @var OperationRunService $operationRunService */
    $operationRunService = app(OperationRunService::class);
    $operationRun = $operationRunService->ensureRun(
        tenant: $tenant,
        type: 'test.exception',
        inputs: ['foo' => 'bar'],
        initiator: $user,
    );

    $job = new class($operationRun) implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

        public function __construct(public OperationRun $operationRun)
        {
            $this->withFakeQueueInteractions();
        }
    };

    $middleware = new TrackOperationRun;

    expect(fn () => $middleware->handle($job, function (): void {
        throw new RuntimeException('wrapped job failure');
    }))->toThrow(RuntimeException::class);

    $operationRun->refresh();

    expect($operationRun->status)->toBe('completed')
        ->and($operationRun->outcome)->toBe('failed')
        ->and(data_get($operationRun->failure_summary, '0.code'))->toBe('exception.unhandled');
});
