<?php

declare(strict_types=1);

use App\Jobs\AutoTagArtworkJob;
use App\Jobs\GenerateArtworkEmbeddingJob;
use App\Models\Artwork;
use App\Models\User;
use App\Repositories\Uploads\UploadSessionRepository;
use App\Services\Uploads\UploadSessionStatus;
use App\Services\Uploads\UploadTokenService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Str;

uses(RefreshDatabase::class);

it('dispatches AI processing jobs after upload finish publishes successfully', function () {
    config()->set('forum_bot_protection.enabled', false);
    config()->set('uploads.queue_derivatives', false);
    config()->set('uploads.storage_root', storage_path('framework/testing/uploads'));

    Queue::fake();
    File::deleteDirectory((string) config('uploads.storage_root'));

    $user = User::factory()->create();
    $artwork = Artwork::factory()->create([
        'user_id' => $user->id,
        'is_public' => false,
        'is_approved' => false,
        'published_at' => null,
    ]);

    $sessionId = (string) Str::uuid();
    $tmpPath = storage_path('framework/testing/uploads/tmp/' . $sessionId . '.png');
    $sourceImage = base_path('public/favicon/favicon-96x96.png');
    File::ensureDirectoryExists(dirname($tmpPath));
    File::copy($sourceImage, $tmpPath);

    app(UploadSessionRepository::class)->create(
        $sessionId,
        $user->id,
        $tmpPath,
        UploadSessionStatus::TMP,
        '127.0.0.1'
    );

    $token = app(UploadTokenService::class)->generate($sessionId, $user->id);

    $response = $this->actingAs($user)
        ->withHeader('X-Upload-Token', $token)
        ->postJson('/api/uploads/finish', [
            'session_id' => $sessionId,
            'artwork_id' => $artwork->id,
            'file_name' => 'example.png',
        ]);

    $response->assertOk();
    $response->assertJsonPath('artwork_id', $artwork->id);
    $response->assertJsonPath('status', UploadSessionStatus::PROCESSED);

    Queue::assertPushed(AutoTagArtworkJob::class, 1);
    Queue::assertPushed(GenerateArtworkEmbeddingJob::class, 1);

    $artwork->refresh();
    expect($artwork->hash)->not->toBe('')
        ->and($artwork->thumb_ext)->toBe('webp')
        ->and($artwork->width)->toBeGreaterThan(0)
        ->and($artwork->height)->toBeGreaterThan(0);

    expect(File::exists((string) $tmpPath))->toBeFalse();
});

it('blocks upload finish only when the hash already belongs to a published artwork', function () {
    config()->set('forum_bot_protection.enabled', false);
    config()->set('uploads.queue_derivatives', false);
    config()->set('uploads.storage_root', storage_path('framework/testing/uploads'));

    File::deleteDirectory((string) config('uploads.storage_root'));

    $user = User::factory()->create();
    $publishedArtwork = Artwork::factory()->create([
        'user_id' => $user->id,
        'hash' => hash_file('sha256', base_path('public/favicon/favicon-96x96.png')),
        'artwork_status' => 'published',
        'published_at' => now()->subMinute(),
        'is_public' => true,
    ]);

    $draftArtwork = Artwork::factory()->create([
        'user_id' => $user->id,
        'is_public' => false,
        'is_approved' => false,
        'published_at' => null,
    ]);

    $sessionId = (string) Str::uuid();
    $tmpPath = storage_path('framework/testing/uploads/tmp/' . $sessionId . '.png');
    $sourceImage = base_path('public/favicon/favicon-96x96.png');
    File::ensureDirectoryExists(dirname($tmpPath));
    File::copy($sourceImage, $tmpPath);

    app(UploadSessionRepository::class)->create(
        $sessionId,
        $user->id,
        $tmpPath,
        UploadSessionStatus::TMP,
        '127.0.0.1'
    );

    $token = app(UploadTokenService::class)->generate($sessionId, $user->id);

    $response = $this->actingAs($user)
        ->withHeader('X-Upload-Token', $token)
        ->postJson('/api/uploads/finish', [
            'session_id' => $sessionId,
            'artwork_id' => $draftArtwork->id,
            'file_name' => 'example.png',
        ]);

    $response->assertStatus(409)
        ->assertJsonPath('reason', 'duplicate_hash');

    expect($publishedArtwork->hash)->not->toBe('');
});

it('allows upload finish when the same hash exists only on an unpublished artwork', function () {
    config()->set('forum_bot_protection.enabled', false);
    config()->set('uploads.queue_derivatives', false);
    config()->set('uploads.storage_root', storage_path('framework/testing/uploads'));

    Queue::fake();
    File::deleteDirectory((string) config('uploads.storage_root'));

    $user = User::factory()->create();
    $hash = hash_file('sha256', base_path('public/favicon/favicon-96x96.png'));

    Artwork::factory()->create([
        'user_id' => $user->id,
        'hash' => $hash,
        'artwork_status' => 'draft',
        'published_at' => null,
        'is_public' => false,
        'is_approved' => false,
    ]);

    $draftArtwork = Artwork::factory()->create([
        'user_id' => $user->id,
        'is_public' => false,
        'is_approved' => false,
        'published_at' => null,
    ]);

    $sessionId = (string) Str::uuid();
    $tmpPath = storage_path('framework/testing/uploads/tmp/' . $sessionId . '.png');
    $sourceImage = base_path('public/favicon/favicon-96x96.png');
    File::ensureDirectoryExists(dirname($tmpPath));
    File::copy($sourceImage, $tmpPath);

    app(UploadSessionRepository::class)->create(
        $sessionId,
        $user->id,
        $tmpPath,
        UploadSessionStatus::TMP,
        '127.0.0.1'
    );

    $token = app(UploadTokenService::class)->generate($sessionId, $user->id);

    $response = $this->actingAs($user)
        ->withHeader('X-Upload-Token', $token)
        ->postJson('/api/uploads/finish', [
            'session_id' => $sessionId,
            'artwork_id' => $draftArtwork->id,
            'file_name' => 'example.png',
        ]);

    $response->assertOk()
        ->assertJsonPath('artwork_id', $draftArtwork->id)
        ->assertJsonPath('status', UploadSessionStatus::PROCESSED);
});
