<?php

declare(strict_types=1);

use App\Models\Artwork;
use App\Models\User;
use App\Services\Vision\AiArtworkVectorSearchService;
use App\Services\Vision\ArtworkVectorIndexService;
use App\Services\Vision\ArtworkVectorMetadataService;
use App\Services\Vision\ArtworkVisionImageUrl;
use App\Services\Vision\VectorGatewayClient;
use App\Services\Vision\VectorService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Str;

uses(RefreshDatabase::class);

function bindVectorService(): void
{
    $imageUrl = new ArtworkVisionImageUrl();

    app()->instance(VectorService::class, new VectorService(
        new AiArtworkVectorSearchService(new VectorGatewayClient(), $imageUrl),
        new ArtworkVectorIndexService(new VectorGatewayClient(), $imageUrl, new ArtworkVectorMetadataService()),
    ));
}

it('indexes artworks by latest updated_at descending by default', function (): void {
    $user = User::factory()->create();

    $oldest = Artwork::factory()->for($user)->create([
        'title' => 'Oldest artwork',
        'slug' => 'oldest-artwork',
        'hash' => str_repeat('a', 32),
        'is_public' => true,
        'is_approved' => true,
        'published_at' => now()->subDays(3),
        'updated_at' => now()->subDays(3),
    ]);

    $middle = Artwork::factory()->for($user)->create([
        'title' => 'Middle artwork',
        'slug' => 'middle-artwork',
        'hash' => str_repeat('b', 32),
        'is_public' => true,
        'is_approved' => true,
        'published_at' => now()->subDays(2),
        'updated_at' => now()->subDays(2),
    ]);

    $latest = Artwork::factory()->for($user)->create([
        'title' => 'Latest artwork',
        'slug' => 'latest-artwork',
        'hash' => str_repeat('c', 32),
        'is_public' => true,
        'is_approved' => true,
        'published_at' => now()->subDay(),
        'updated_at' => now()->subHour(),
    ]);

    bindVectorService();

    $code = Artisan::call('artworks:vectors-index', [
        '--dry-run' => true,
        '--public-only' => true,
        '--limit' => 3,
        '--batch' => 3,
    ]);

    $output = Artisan::output();

    expect($code)->toBe(0);

    $latestPos = strpos($output, 'Processing artwork=' . $latest->id);
    $middlePos = strpos($output, 'Processing artwork=' . $middle->id);
    $oldestPos = strpos($output, 'Processing artwork=' . $oldest->id);

    expect($latestPos)->not->toBeFalse()
        ->and($middlePos)->not->toBeFalse()
        ->and($oldestPos)->not->toBeFalse()
        ->and($latestPos)->toBeLessThan($middlePos)
        ->and($middlePos)->toBeLessThan($oldestPos);
});

it('supports legacy id ascending order when explicitly requested', function (): void {
    $user = User::factory()->create();

    $first = Artwork::factory()->for($user)->create([
        'title' => 'First artwork',
        'slug' => 'first-artwork-' . Str::lower(Str::random(4)),
        'hash' => str_repeat('d', 32),
        'is_public' => true,
        'is_approved' => true,
        'published_at' => now()->subDay(),
        'updated_at' => now(),
    ]);

    $second = Artwork::factory()->for($user)->create([
        'title' => 'Second artwork',
        'slug' => 'second-artwork-' . Str::lower(Str::random(4)),
        'hash' => str_repeat('e', 32),
        'is_public' => true,
        'is_approved' => true,
        'published_at' => now()->subDays(2),
        'updated_at' => now()->subDays(2),
    ]);

    bindVectorService();

    $code = Artisan::call('artworks:vectors-index', [
        '--dry-run' => true,
        '--public-only' => true,
        '--limit' => 2,
        '--batch' => 2,
        '--order' => 'id-asc',
    ]);

    $output = Artisan::output();

    expect($code)->toBe(0);

    $firstPos = strpos($output, 'Processing artwork=' . $first->id);
    $secondPos = strpos($output, 'Processing artwork=' . $second->id);

    expect($firstPos)->not->toBeFalse()
        ->and($secondPos)->not->toBeFalse()
        ->and($firstPos)->toBeLessThan($secondPos);
});