<?php

namespace App\Jobs;

use App\Contracts\CreativeBriefResolver;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Cache;
use Throwable;

/**
 * Work out the creative brief before the wizard needs it.
 *
 * Resolving a brief is the slow part of the wizard and it used to happen inside
 * whichever click first needed it. A product URL costs a 15-second page fetch, a
 * 20-second screenshot call and then an AI call; the step that asks for it is a
 * Livewire action, so the browser sits on a request for the length of all three.
 *
 * This existed for product URLs only. A prompt and an upload resolve exactly the
 * same way and had no prefetch at all, so those two sources always paid the full
 * cost at the click - which is most of the traffic.
 *
 * Competitor is deliberately not prefetched: resolveBrief() discards the
 * competitor thumbnails once it has used them, so resolving twice would leave the
 * second attempt with no images. Fixing that means not discarding them, which is
 * a change to what the wizard holds rather than to when this runs.
 *
 * Best effort throughout. A failure here is logged and forgotten, and the step
 * that needs the brief resolves it itself - slowly, but correctly.
 */
class PrefetchCreativeBriefJob implements ShouldQueue
{
    use Queueable;

    public int $tries = 1;

    public int $timeout = 120;

    /**
     * @param  'product_url'|'prompt'|'upload'  $source
     * @param  string|list<string>  $payload  the URL, the prompt, or the stored image paths
     */
    public function __construct(
        public string $payload,
        public string $source = 'product_url',
        public array $images = [],
    ) {}

    public function handle(CreativeBriefResolver $briefResolver): void
    {
        try {
            $brief = match ($this->source) {
                'product_url' => $briefResolver->fromProductUrl($this->payload),
                'upload' => $briefResolver->fromImages($this->images),
                default => $briefResolver->fromPrompt($this->payload, []),
            };

            Cache::put(self::cacheKey($this->source, $this->payload, $this->images), $brief->toArray(), now()->addMinutes(30));
        } catch (Throwable $e) {
            logger()->warning('Creative brief prefetch failed, will retry at generation time', [
                'source' => $this->source,
                'exception' => $e,
            ]);
        }
    }

    /**
     * The key both sides agree on.
     *
     * The source is part of it because the same string means different things to
     * different sources: a prompt and a URL can be spelled identically, and reading
     * one brief as the other would describe the wrong product entirely.
     *
     * @param  list<string>  $images
     */
    public static function cacheKey(string $source, string $payload = '', array $images = []): string
    {
        return 'creative-brief:'.$source.':'.hash('sha256', trim($payload).'|'.implode('|', $images));
    }
}
