<?php

namespace Tests\Unit;

use App\DTOs\CreativeBrief;
use App\Exceptions\VideoDialogueException;
use App\Services\AI\LaravelAiScriptGenerator;
use App\Support\VideoDialogue;
use Laravel\Ai\StructuredAnonymousAgent;
use Tests\TestCase;

class LaravelAiScriptGeneratorTest extends TestCase
{
    public function test_it_rejects_an_ai_spoken_line_that_exceeds_the_duration_budget(): void
    {
        config(['creative.spoken_words_per_second' => 1.7]);

        $overlongScript = $this->scriptWithSpokenLine(implode(' ', array_fill(0, 14, 'word')));
        StructuredAnonymousAgent::fake([$overlongScript, $overlongScript]);

        $brief = $this->brief();

        $this->expectException(VideoDialogueException::class);
        $this->expectExceptionMessage('too long');

        (new LaravelAiScriptGenerator)->generate($brief, durationSeconds: 8);
    }

    public function test_it_retries_an_overlong_line_and_keeps_a_valid_rewrite(): void
    {
        config(['creative.spoken_words_per_second' => 1.7]);
        StructuredAnonymousAgent::fake([
            $this->scriptWithSpokenLine(implode(' ', array_fill(0, 14, 'word'))),
            $this->scriptWithSpokenLine('Browse faster every single day with less clutter and download today.'),
        ]);

        $script = (new LaravelAiScriptGenerator)->generate($this->brief(), durationSeconds: 8);

        $this->assertSame('Browse faster every single day with less clutter and download today.', $script['spoken_line']);
        StructuredAnonymousAgent::assertPrompted(fn ($prompt): bool => str_contains($prompt->prompt, 'previous spoken_line contained 14 words'));
    }

    public function test_one_invalid_variation_does_not_discard_other_valid_scripts(): void
    {
        config(['creative.spoken_words_per_second' => 1.7]);
        $overlongScript = $this->scriptWithSpokenLine(implode(' ', array_fill(0, 14, 'word')));
        StructuredAnonymousAgent::fake([
            $overlongScript,
            $overlongScript,
            $this->scriptWithSpokenLine('Browse faster every single day with less clutter and download today.'),
            $this->scriptWithSpokenLine('Less clutter on every page helps you focus and try it free.'),
            $this->scriptWithSpokenLine('Faster pages each day keep you moving so you get started.'),
        ]);

        $variations = (new LaravelAiScriptGenerator)->generateVariations($this->brief(), 4, durationSeconds: 8);

        $this->assertCount(3, $variations);
        $this->assertSame('Browse faster every single day with less clutter and download today.', $variations[0]['spoken_line']);
    }

    public function test_it_retries_a_short_line_until_it_fills_the_duration(): void
    {
        config(['creative.spoken_words_per_second' => 1.7]);
        StructuredAnonymousAgent::fake([
            $this->scriptWithSpokenLine('Browse faster. Download today.'),
            $this->scriptWithSpokenLine('Browse faster every single day with less clutter and download today.'),
        ]);

        $script = (new LaravelAiScriptGenerator)->generate($this->brief(), durationSeconds: 8);

        $this->assertSame('Browse faster every single day with less clutter and download today.', $script['spoken_line']);
        StructuredAnonymousAgent::assertPrompted(fn ($prompt): bool => str_contains($prompt->prompt, 'which is too short'));
    }

    public function test_a_display_product_tells_the_script_not_to_pick_it_up(): void
    {
        StructuredAnonymousAgent::fake([
            $this->scriptWithSpokenLine('Shop the printer today.'),
        ]);

        $brief = new CreativeBrief(
            productName: 'HP Smart Tank printer',
            benefits: ['Years of ink included'],
            features: ['Refillable tanks'],
            images: [],
            messaging: 'Print without cartridge swaps',
            cta: 'Shop now',
            handling: 'display',
        );

        (new LaravelAiScriptGenerator)->generate($brief);

        StructuredAnonymousAgent::assertPrompted(fn ($prompt): bool => str_contains($prompt->prompt, 'The product is heavy and stays in place.')
            && str_contains($prompt->prompt, 'Never holding, lifting, tossing, or carrying it.'));
    }

    public function test_vertex_dialogue_budget_matches_each_rendered_stage(): void
    {
        config(['creative.spoken_words_per_second' => 2, 'creative.vertex_extend_durations' => [15 => 1, 30 => 3]]);

        $this->assertSame(30, VideoDialogue::wordBudget(15));
        $this->assertSame(58, VideoDialogue::wordBudget(30));
        $this->assertSame(28, VideoDialogue::wordFloor(15));
        $this->assertSame(56, VideoDialogue::wordFloor(30));
    }

    public function test_higgsfield_dialogue_budget_finishes_one_second_before_the_clip_ends(): void
    {
        config(['creative.higgsfield_spoken_words_per_second' => 2.7]);

        $this->assertSame(18, VideoDialogue::wordBudget(8, 'higgsfield-seedance'));
        $this->assertSame(37, VideoDialogue::wordBudget(15, 'higgsfield-seedance'));
        $this->assertSame(78, VideoDialogue::wordBudget(30, 'higgsfield-seedance'));
        $this->assertSame(35, VideoDialogue::wordFloor(15, 'higgsfield-seedance'));
    }

    private function brief(): CreativeBrief
    {
        return new CreativeBrief(
            productName: 'Example Browser',
            benefits: ['Faster pages'],
            features: ['Built-in ad blocker'],
            images: [],
            messaging: 'Simple browser ad',
            cta: 'Download today',
        );
    }

    private function scriptWithSpokenLine(string $spokenLine): array
    {
        return [
            'hook' => 'Discover faster browsing',
            'spoken_line' => $spokenLine,
            'visual_action' => 'Presenter addresses the camera.',
            'problem' => 'Slow pages',
            'product' => 'Example Browser',
            'benefits' => 'Faster pages',
            'cta' => 'Download today',
        ];
    }
}
