<?php

declare(strict_types=1);

namespace App\Services\Vision;

use App\Models\Artwork;
use Illuminate\Support\Facades\Http;
use RuntimeException;

final class ArtworkVectorIndexService
{
    public function __construct(
        private readonly VectorGatewayClient $client,
        private readonly ArtworkVisionImageUrl $imageUrl,
        private readonly ArtworkVectorMetadataService $metadata,
    ) {
    }

    public function isConfigured(): bool
    {
        return $this->client->isConfigured();
    }

    /**
     * @return array{url: string, metadata: array<string, mixed>}
     */
    public function payloadForArtwork(Artwork $artwork): array
    {
        $url = $this->imageUrl->fromArtwork($artwork);
        if ($url === null || $url === '') {
            throw new RuntimeException('No vision image URL could be generated for artwork ' . (int) $artwork->id . '.');
        }

        return [
            'url' => $url,
            'metadata' => $this->metadata->forArtwork($artwork),
        ];
    }

    /**
     * @return array{url: string, metadata: array<string, mixed>}
     */
    public function upsertArtwork(Artwork $artwork): array
    {
        $payload = $this->payloadForArtwork($artwork);

        $filePayload = $this->downloadArtworkImage($artwork, $payload['url']);
        if ($filePayload === null) {
            throw new RuntimeException('Unable to download artwork image bytes for vector upsert for artwork ' . (int) $artwork->id . '.');
        }

        $this->client->upsertByFileContents($filePayload['contents'], $filePayload['filename'], (int) $artwork->id, $payload['metadata']);

        $artwork->forceFill([
            'last_vector_indexed_at' => now(),
        ])->save();

        return $payload;
    }

    /**
     * @return array{contents: string, filename: string}|null
     */
    private function downloadArtworkImage(Artwork $artwork, string $url): ?array
    {
        $response = Http::accept('*/*')
            ->connectTimeout(5)
            ->timeout(20)
            ->retry(1, 200, throw: false)
            ->get($url);

        if (! $response->ok()) {
            return null;
        }

        $contents = $response->body();
        if ($contents === '') {
            return null;
        }

        $ext = strtolower(ltrim((string) ($artwork->thumb_ext ?: 'webp'), '.'));

        return [
            'contents' => $contents,
            'filename' => sprintf('artwork-%d.%s', (int) $artwork->id, $ext !== '' ? $ext : 'webp'),
        ];
    }
}
