<?php

use App\Console\TickProvisioning;
use App\Models\ProvisioningRun;
use App\Provisioning\Jobs\AdvanceRunJob;
use Illuminate\Support\Facades\Queue;

it('picks up a run that was created but never dispatched', function () {
    Queue::fake();

    $fresh = ProvisioningRun::factory()->create([
        'status' => ProvisioningRun::STATUS_PENDING,
        'next_attempt_at' => null,
    ]);
    $stranded = ProvisioningRun::factory()->create([
        'status' => ProvisioningRun::STATUS_PENDING,
        'next_attempt_at' => null,
        'created_at' => now()->subHour(),
    ]);

    (new TickProvisioning)();

    // The stranded one: a process died between creating the run and dispatching
    // its first job, and nothing else would ever look at it again.
    Queue::assertPushed(AdvanceRunJob::class, fn ($job) => $job->runUuid === $stranded->uuid);

    // The fresh one is left alone — its own job is simply still queued, and a
    // second one would run a duplicate chain beside it for the whole pipeline.
    Queue::assertNotPushed(AdvanceRunJob::class, fn ($job) => $job->runUuid === $fresh->uuid);
});

it('dispatches advance jobs only for due running or waiting runs', function () {
    Queue::fake();

    ProvisioningRun::factory()->create(['status' => 'waiting', 'next_attempt_at' => now()->subMinute()]);
    ProvisioningRun::factory()->create(['status' => 'running', 'next_attempt_at' => null]);
    ProvisioningRun::factory()->create(['status' => 'waiting', 'next_attempt_at' => now()->addHour()]);
    ProvisioningRun::factory()->create(['status' => 'completed']);
    ProvisioningRun::factory()->create(['status' => 'paused']);

    app(TickProvisioning::class)();

    Queue::assertPushed(AdvanceRunJob::class, 2);
});
