<?php

declare(strict_types=1);

use App\Jobs\Enhance\ProcessEnhanceJob;
use App\Models\EnhanceJob;
use App\Models\User;
use App\Services\Enhance\EnhanceProcessorFactory;
use App\Services\Enhance\EnhanceService;
use App\Services\Enhance\EnhanceStorageService;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Storage;

beforeEach(function (): void {
    config()->set('enhance.disk', 'public');
    Storage::fake('public');
});

it('allows an authenticated user to create an enhance job from an upload', function (): void {
    Queue::fake();

    $user = User::factory()->create();
    $file = UploadedFile::fake()->image('wallpaper.png', 1200, 800)->size(1024);

    $response = $this->actingAs($user)->post(route('enhance.store'), [
        'image' => $file,
        'scale' => 2,
        'mode' => 'standard',
    ]);

    $job = EnhanceJob::query()->first();

    $response->assertRedirect(route('enhance.show', ['enhanceJob' => $job]));

    expect($job)->not->toBeNull();
    expect($job->status)->toBe(EnhanceJob::STATUS_QUEUED);
    expect($job->source_path)->not->toBe('');
    Storage::disk('public')->assertExists($job->source_path);

    Queue::assertPushed(ProcessEnhanceJob::class, function (ProcessEnhanceJob $queuedJob) use ($job): bool {
        return true;
    });
});

it('rejects unsupported mime types', function (): void {
    $user = User::factory()->create();
    $file = UploadedFile::fake()->create('vector.svg', 10, 'image/svg+xml');

    $this->actingAs($user)
        ->from(route('enhance.create'))
        ->post(route('enhance.store'), [
            'image' => $file,
            'scale' => 2,
            'mode' => 'standard',
        ])
        ->assertRedirect(route('enhance.create'))
        ->assertSessionHasErrors('image');
});

it('rejects invalid scale and mode values', function (): void {
    $user = User::factory()->create();
    $file = UploadedFile::fake()->image('bad.png', 1200, 800)->size(512);

    $this->actingAs($user)
        ->from(route('enhance.create'))
        ->post(route('enhance.store'), [
            'image' => $file,
            'scale' => 3,
            'mode' => 'broken',
        ])
        ->assertRedirect(route('enhance.create'))
        ->assertSessionHasErrors(['scale', 'mode']);
});

it('enforces the daily enhance limit', function (): void {
    config()->set('enhance.daily_limit', 1);

    $user = User::factory()->create();

    EnhanceJob::query()->create([
        'user_id' => $user->id,
        'status' => EnhanceJob::STATUS_COMPLETED,
        'engine' => EnhanceJob::ENGINE_STUB,
        'mode' => 'standard',
        'scale' => 2,
    ]);

    $file = UploadedFile::fake()->image('wallpaper.png', 1200, 800)->size(512);

    $this->actingAs($user)
        ->from(route('enhance.create'))
        ->post(route('enhance.store'), [
            'image' => $file,
            'scale' => 2,
            'mode' => 'standard',
        ])
        ->assertRedirect(route('enhance.create'))
        ->assertSessionHasErrors('image');
});

it('completes a queued job with the stub processor', function (): void {
    Queue::fake();

    $user = User::factory()->create();
    $file = UploadedFile::fake()->image('art.png', 640, 480)->size(256);

    $job = app(EnhanceService::class)->createFromUpload($user, $file, [
        'scale' => 2,
        'mode' => 'standard',
        'engine' => 'stub',
    ]);

    $processorJob = new ProcessEnhanceJob($job->id);
    $processorJob->handle(app(EnhanceProcessorFactory::class), app(EnhanceStorageService::class));

    $job->refresh();

    expect($job->status)->toBe(EnhanceJob::STATUS_COMPLETED);
    expect($job->output_path)->not->toBeNull();
    expect($job->preview_path)->not->toBeNull();
    Storage::disk('public')->assertExists($job->output_path);
    Storage::disk('public')->assertExists($job->preview_path);
});