<?php

namespace Tests\Feature;

use App\Contracts\CatalogPageDataResolver;
use App\Enums\LandingPageLayoutMode;
use App\Enums\LandingPageVersion;
use App\Jobs\GenerateCatalogLandingPagesJob;
use App\Models\LandingPage;
use App\Models\LandingPageGeneration;
use App\Services\CatalogTemplateLocator;
use App\Services\CatalogTemplateRenderer;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Laravel\Ai\StructuredAnonymousAgent;
use Tests\TestCase;

class GenerateCatalogLandingPagesJobTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_wires_catalog_json_into_each_variation_template(): void
    {
        Http::preventStrayRequests();
        Http::fake([
            'https://example.com/can' => Http::response('<html><meta property="og:image" content="https://cdn.example.com/can.png"><body>Watering can</body></html>'),
        ]);

        StructuredAnonymousAgent::fake([
            $this->catalogPayload(),
        ]);

        $generation = $this->queuedGeneration();

        (new GenerateCatalogLandingPagesJob($generation->id))->handle(
            app(CatalogPageDataResolver::class),
            app(CatalogTemplateRenderer::class),
            app(CatalogTemplateLocator::class),
        );

        $generation->refresh()->load('landingPages');

        $this->assertSame('completed', $generation->status);
        $this->assertNotEmpty($generation->catalog);
        $this->assertSame('Hoe', $generation->catalog['Brand']);
        $this->assertSame('https://example.com/can', $generation->catalog['products'][0]['retailer_url']);
        $this->assertSame('https://cdn.example.com/can.png', $generation->catalog['products'][0]['image_url']);
        $this->assertCount(6, $generation->landingPages);
        $this->assertTrue($generation->landingPages->every(fn (LandingPage $page) => $page->isReady()));

        foreach ($generation->landingPages as $page) {
            $this->assertMatchesRegularExpression('/^template-\d+$/', $page->template);
            $this->assertStringContainsString('Watering Can', $page->html);
            $this->assertStringContainsString('https://example.com/can', $page->html);
            $this->assertStringContainsString('https://cdn.example.com/can.png', $page->html);
            $this->assertStringContainsString('href="style.css"', $page->html);
            $this->assertNotSame('', trim((string) $page->css));
        }
    }

    public function test_it_reuses_a_stored_catalog_on_retry(): void
    {
        $generation = $this->queuedGeneration();
        $generation->update([
            'status' => 'completed',
            'catalog' => $this->catalogPayload(),
        ]);

        foreach ($generation->landingPages as $page) {
            $page->update([
                'status' => 'completed',
                'template' => 'template-1',
                'title' => 'Old '.$page->version->value,
                'html' => '<section id="old">old</section>',
                'css' => 'body { color: red; }',
                'js' => '',
            ]);
        }

        $target = $generation->landingPages->first();
        $target->update([
            'status' => 'queued',
            'html' => null,
            'css' => null,
            'js' => null,
        ]);

        $this->mock(CatalogPageDataResolver::class, function ($mock) {
            $mock->shouldReceive('resolve')->never();
        });

        Http::preventStrayRequests();

        (new GenerateCatalogLandingPagesJob($generation->id, $target->id))->handle(
            app(CatalogPageDataResolver::class),
            app(CatalogTemplateRenderer::class),
            app(CatalogTemplateLocator::class),
        );

        $generation->refresh()->load('landingPages');
        $target->refresh();

        $this->assertSame('completed', $generation->status);
        $this->assertSame('completed', $target->status);
        $this->assertSame('template-1', $target->template);
        $this->assertStringContainsString('Watering Can', $target->html);
        $this->assertStringContainsString('https://example.com/can', $target->html);

        foreach ($generation->landingPages->where('id', '!=', $target->id) as $page) {
            $this->assertSame('<section id="old">old</section>', $page->html);
            $this->assertSame('Old '.$page->version->value, $page->title);
        }
    }

    public function test_it_picks_one_template_per_variation_after_the_catalog_json_exists(): void
    {
        config(['landing-page-templates.path' => base_path('tests/Fixtures/catalog-templates')]);

        $generation = LandingPageGeneration::factory()->catalog()->create([
            'status' => 'queued',
            'brand_name' => 'Hoe',
            'product_urls' => ['https://example.com/can'],
            'catalog' => $this->catalogPayload(),
        ]);

        $page = LandingPage::factory()->create([
            'landing_page_generation_id' => $generation->id,
            'version' => LandingPageVersion::Benefits,
            'template' => '',
            'status' => 'queued',
        ]);

        $this->mock(CatalogPageDataResolver::class, function ($mock) {
            $mock->shouldReceive('resolve')->never();
        });

        Http::preventStrayRequests();

        (new GenerateCatalogLandingPagesJob($generation->id))->handle(
            app(CatalogPageDataResolver::class),
            app(CatalogTemplateRenderer::class),
            app(CatalogTemplateLocator::class),
        );

        $page->refresh();

        $this->assertContains($page->template, ['template-1', 'template-2']);
        $this->assertSame(1, $generation->landingPages()->count());

        if ($page->template === 'template-1') {
            $this->assertStringContainsString('class="wired"', $page->html);
        } else {
            $this->assertStringContainsString('class="wired-alt"', $page->html);
        }
    }

    public function test_it_keeps_the_stored_template_on_retry_instead_of_picking_again(): void
    {
        config(['landing-page-templates.path' => base_path('tests/Fixtures/catalog-templates')]);

        $generation = LandingPageGeneration::factory()->catalog()->create([
            'status' => 'queued',
            'brand_name' => 'Hoe',
            'product_urls' => ['https://example.com/can'],
            'catalog' => $this->catalogPayload(),
        ]);

        $page = LandingPage::factory()->create([
            'landing_page_generation_id' => $generation->id,
            'version' => LandingPageVersion::Benefits,
            'template' => 'template-2',
            'status' => 'queued',
        ]);

        $this->mock(CatalogPageDataResolver::class, function ($mock) {
            $mock->shouldReceive('resolve')->never();
        });

        Http::preventStrayRequests();

        (new GenerateCatalogLandingPagesJob($generation->id, $page->id))->handle(
            app(CatalogPageDataResolver::class),
            app(CatalogTemplateRenderer::class),
            app(CatalogTemplateLocator::class),
        );

        $page->refresh();

        $this->assertSame('template-2', $page->template);
        $this->assertStringContainsString('class="wired-alt"', $page->html);
    }

    public function test_it_overwrites_category_and_subcategory_from_research_picks(): void
    {
        $payload = $this->catalogPayload();
        $payload['research'] = [
            'category' => 'Outdoor',
            'subcategory' => 'Tents',
        ];

        $generation = $this->queuedGeneration([
            'catalog' => $payload,
        ]);

        $this->mock(CatalogPageDataResolver::class, function ($mock) {
            $mock->shouldReceive('resolve')->never();
        });

        Http::preventStrayRequests();

        (new GenerateCatalogLandingPagesJob($generation->id))->handle(
            app(CatalogPageDataResolver::class),
            app(CatalogTemplateRenderer::class),
            app(CatalogTemplateLocator::class),
        );

        $generation->refresh();

        $this->assertSame('Outdoor', $generation->catalog['category']);
        $this->assertSame('Tents', $generation->catalog['subcategory']);
        $this->assertSame('Outdoor', $generation->catalog['research']['category']);
    }

    /**
     * @param  array<string, mixed>  $overrides
     */
    private function queuedGeneration(array $overrides = []): LandingPageGeneration
    {
        $generation = LandingPageGeneration::factory()->catalog()->create([
            'status' => 'queued',
            'brand_name' => 'Hoe',
            'product_urls' => ['https://example.com/can'],
            ...$overrides,
        ]);

        foreach (LandingPageVersion::forLayout(LandingPageLayoutMode::Catalog) as $version) {
            LandingPage::factory()->create([
                'landing_page_generation_id' => $generation->id,
                'version' => $version,
                'template' => '',
                'status' => 'queued',
            ]);
        }

        return $generation->load('landingPages');
    }

    /**
     * @return array<string, mixed>
     */
    private function catalogPayload(): array
    {
        return [
            'Brand' => 'garden-tools-v1',
            'advertiser_id' => '15881',
            'campaign_id' => '122609',
            'subcategory' => 'Garden Tools',
            'category' => 'Home',
            'updated' => 'May 2026',
            'hero_title' => 'Find the right watering can.',
            'review_sources' => [],
            'products' => [
                [
                    'name' => 'Watering Can',
                    'brand' => 'Hoe',
                    'best_for' => 'Best Overall',
                    'price' => '$18',
                    'list_price' => null,
                    'discount' => null,
                    'rating' => '4.7',
                    'review_count' => '12',
                    'price_history' => null,
                    'image_url' => 'https://cdn.example.com/can.png',
                    'retailer_url' => 'https://example.com/can',
                    'chips' => ['Galvanized'],
                    'convertibility' => null,
                    'certification' => null,
                    'summary' => 'A steel watering can.',
                    'summary_short' => 'A steel watering can.',
                    'why_it_stands_out' => 'It will not rust.',
                    'why_short' => 'It will not rust.',
                    'pros' => ['Durable'],
                    'cons' => ['Heavy'],
                    'tradeoff_note' => 'Sturdy but heavy.',
                    'sources_note' => 'Shopper favorite.',
                ],
            ],
        ];
    }
}
