<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Models\Artwork;
use App\Models\Category;
use App\Services\Vision\VectorService;
use Illuminate\Console\Command;

final class SearchArtworkVectorsCommand extends Command
{
    protected $signature = 'artworks:vectors-search
        {artwork_id : Source artwork id}
        {--limit=5 : Number of similar artworks to return}';

    protected $description = 'Search similar artworks through the vector gateway using an artwork image URL';

    public function handle(VectorService $vectors): int
    {
        if (! $vectors->isConfigured()) {
            $this->error('Vision vector gateway is not configured. Set VISION_VECTOR_GATEWAY_URL and VISION_VECTOR_GATEWAY_API_KEY.');
            return self::FAILURE;
        }

        $artworkId = max(1, (int) $this->argument('artwork_id'));
        $limit = max(1, min((int) $this->option('limit'), 100));

        $artwork = Artwork::query()
            ->with(['categories' => fn ($categories) => $categories->with('contentType')->orderBy('sort_order')->orderBy('name')])
            ->find($artworkId);

        if (! $artwork) {
            $this->error("Artwork {$artworkId} was not found.");
            return self::FAILURE;
        }

        try {
            $matches = $vectors->similarToArtwork($artwork, $limit);
        } catch (\Throwable $e) {
            $this->error('Vector search failed: ' . $e->getMessage());
            return self::FAILURE;
        }

        $ids = collect($matches)->pluck('id')->map(fn (mixed $id): int => (int) $id)->filter()->values()->all();

        if ($ids === []) {
            $this->warn('No similar artworks were returned by the vector gateway.');
            return self::SUCCESS;
        }

        $artworks = Artwork::query()
            ->with(['categories' => fn ($categories) => $categories->with('contentType')->orderBy('sort_order')->orderBy('name')])
            ->whereIn('id', $ids)
            ->public()
            ->published()
            ->get()
            ->keyBy('id');

        $rows = [];
        foreach ($matches as $match) {
            $matchId = (int) ($match['id'] ?? 0);
            if ($matchId <= 0) {
                continue;
            }

            /** @var Artwork|null $matchedArtwork */
            $matchedArtwork = $artworks->get($matchId);
            if (! $matchedArtwork) {
                continue;
            }

            $category = $this->primaryCategory($matchedArtwork);
            $rows[] = [
                'id' => $matchId,
                'score' => number_format((float) ($match['score'] ?? 0.0), 4, '.', ''),
                'title' => (string) $matchedArtwork->title,
                'content_type' => (string) ($category?->contentType?->name ?? ''),
                'category' => (string) ($category?->name ?? ''),
            ];

            if (count($rows) >= $limit) {
                break;
            }
        }

        if ($rows === []) {
            $this->warn('The vector gateway returned matches, but none resolved to public published artworks.');
            return self::SUCCESS;
        }

        $this->table(['ID', 'Score', 'Title', 'Content Type', 'Category'], $rows);

        return self::SUCCESS;
    }

    private function primaryCategory(Artwork $artwork): ?Category
    {
        /** @var Category|null $category */
        $category = $artwork->categories->sortBy('sort_order')->first();

        return $category;
    }
}
