<?php

namespace App\Jobs;

use App\Contracts\CreativeBriefResolver;
use App\Contracts\CreativeTitleGenerator;
use App\Contracts\ImageCreativeGenerator;
use App\DTOs\CreativeBrief;
use App\Models\Creative;
use App\Support\ProviderFailure;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\Attributes\FailOnTimeout;
use Throwable;

#[FailOnTimeout]
class GenerateImageCreativeJob implements ShouldQueue
{
    use Queueable;

    /** A retry can trigger a second billable image generation request. */
    public int $tries = 1;

    public int $timeout = 360;

    public function __construct(public int $creativeId) {}

    public function handle(CreativeBriefResolver $briefResolver, ImageCreativeGenerator $generator, CreativeTitleGenerator $titleGenerator): void
    {
        $creative = Creative::findOrFail($this->creativeId);

        if ($creative->status === 'completed') {
            return; // already generated; safe to retry without duplicating work
        }

        $creative->update(['status' => 'generating', 'render_stage' => 'Preparing artwork']);

        try {
            if ($creative->brief) {
                $brief = CreativeBrief::fromArray($creative->brief);
            } else {
                $brief = match ($creative->source) {
                    'product_url' => $briefResolver->fromProductUrl($creative->product_url),
                    default => $briefResolver->fromPrompt($creative->prompt),
                };

                $creative->update(['brief' => $brief->toArray()]);
            }

            if ($creative->project_name && ! $brief->projectName) {
                $brief = new CreativeBrief(
                    productName: $brief->productName,
                    benefits: $brief->benefits,
                    features: $brief->features,
                    images: $brief->images,
                    messaging: $brief->messaging,
                    cta: $brief->cta,
                    projectName: $creative->project_name,
                );
            }

            if (! $creative->title) {
                $creative->update(['title' => $titleGenerator->generate($brief, $creative->type)]);
            }

            $creative->update(['status' => 'processing', 'render_stage' => 'Generating artwork']);

            $result = $generator->generate($brief, $creative->ratio, $creative->style);

            $creative->update([
                'status' => 'completed',
                'asset_path' => $result->path,
                'provider' => [
                    'provider' => $result->provider,
                    'prompt' => $result->prompt,
                ],
                'failure_reason' => null,
                'render_stage' => null,
            ]);
        } catch (Throwable $e) {
            $creative->update([
                'status' => 'failed',
                'failure_reason' => $this->failureReason($e),
                'render_stage' => 'Generation failed',
            ]);

            throw $e;
        }
    }

    public function failed(?Throwable $exception): void
    {
        $creative = Creative::find($this->creativeId);

        if ($creative === null || $creative->status === 'completed') {
            return;
        }

        $creative->update([
            'status' => 'failed',
            'failure_reason' => $exception === null ? 'Generation failed. Please try again.' : $this->failureReason($exception),
            'render_stage' => 'Generation failed',
        ]);
    }

    private function failureReason(Throwable $exception): string
    {
        return ProviderFailure::isRateLimit($exception)
            ? ucfirst(ProviderFailure::rateLimited($exception))
            : 'Generation failed. Please try again.';
    }
}
