<?php

namespace Tests\Unit;

use App\Services\Catalog\CatalogProductImportValidator;
use App\Services\Catalog\CatalogProductJsonFormatter;
use Tests\TestCase;

class CatalogProductImportValidatorTest extends TestCase
{
    public function test_it_accepts_a_products_object_with_required_fields(): void
    {
        $json = json_encode([
            'products' => array_fill(0, 5, [
                'name' => 'Sample Product',
                'url' => 'https://shop.example.com/p/1',
                'price' => '$19.99',
                'image_url' => 'https://cdn.example.com/p/1.jpg',
                'keywords' => [
                    'primary' => 'sample product',
                ],
            ]),
        ]);

        $result = app(CatalogProductImportValidator::class)->validate($json);

        $this->assertTrue($result['valid']);
        $this->assertCount(5, $result['products']);
        $this->assertSame('Sample Product', $result['products'][0]['name']);
        $this->assertSame('json', $result['products'][0]['discovery_source']);
        $this->assertSame('sample product', $result['products'][0]['product_keywords']['primary']);
    }

    public function test_it_accepts_grouped_pricing_ratings_and_media_fields(): void
    {
        $json = json_encode([
            'format_version' => 1,
            'products' => array_fill(0, 5, [
                'name' => 'Sample Product',
                'url' => 'https://shop.example.com/p/1',
                'pricing' => [
                    'price' => '$19.99',
                    'list_price' => '$29.99',
                ],
                'ratings' => [
                    'rating' => '4.8',
                    'review_count' => '764',
                ],
                'media' => [
                    'image_url' => 'https://cdn.example.com/p/1.jpg',
                ],
                'keywords' => [
                    'primary' => 'sample product',
                    'related' => ['related product'],
                ],
            ]),
        ]);

        $result = app(CatalogProductImportValidator::class)->validate($json);

        $this->assertTrue($result['valid']);
        $this->assertSame('764', $result['products'][0]['review_count']);
        $this->assertSame('4.8', $result['products'][0]['rating']);
        $this->assertSame('$29.99', $result['products'][0]['list_price']);
        $this->assertSame('related product', $result['products'][0]['product_keywords']['related'][0]);
    }

    public function test_example_json_includes_retailer_samples_with_review_counts(): void
    {
        $example = app(CatalogProductImportValidator::class)->exampleJson();
        $decoded = json_decode($example, true, flags: JSON_THROW_ON_ERROR);

        $this->assertSame(1, $decoded['format_version']);
        $this->assertSame(['kohls', 'marshalls', 'officedepot'], array_keys($decoded['retailer_examples']));
        $this->assertCount(5, $decoded['products']);
        $this->assertSame('764', $decoded['products'][0]['ratings']['review_count']);
        $this->assertSame('42', $decoded['products'][2]['ratings']['review_count']);
        $this->assertSame('1205', $decoded['products'][4]['ratings']['review_count']);
        $this->assertNotEmpty($decoded['products'][0]['keywords']['primary']);
    }

    public function test_encode_products_uses_grouped_format_without_example_metadata(): void
    {
        $encoded = app(CatalogProductImportValidator::class)->encodeProducts([
            [
                'name' => 'Sample Product',
                'url' => 'https://shop.example.com/p/1',
                'price' => '$19.99',
                'list_price' => null,
                'rating' => '4.5',
                'review_count' => '12',
                'image_url' => 'https://cdn.example.com/p/1.jpg',
                'keyword_primary' => 'sample product',
                'keyword_related' => ['related product'],
                'popularity_note' => '4.5 stars, 12 reviews',
                'discovery_source' => 'json',
            ],
        ]);

        $decoded = json_decode($encoded, true, flags: JSON_THROW_ON_ERROR);

        $this->assertArrayNotHasKey('retailer_examples', $decoded);
        $this->assertSame('$19.99', $decoded['products'][0]['pricing']['price']);
        $this->assertSame('12', $decoded['products'][0]['ratings']['review_count']);
        $this->assertSame('sample product', $decoded['products'][0]['keywords']['primary']);
        $this->assertArrayNotHasKey('discovery_source', $decoded['products'][0]);
    }

    public function test_encode_products_includes_generated_keyword_seeds_in_keyword_research(): void
    {
        $encoded = app(CatalogProductImportValidator::class)->encodeProducts([
            [
                'name' => 'Sample Product',
                'url' => 'https://shop.example.com/p/1',
                'price' => '$19.99',
                'image_url' => 'https://cdn.example.com/p/1.jpg',
                'keyword_primary' => 'sample product',
                'keyword_seeds_generated' => [
                    'user' => ['sample product'],
                    'ai' => ['buy sample product'],
                    'heuristic' => ['sample product deal'],
                ],
                'matched_keyword' => 'sample product',
                'keyword_search_volume' => 1200,
                'keyword_competition' => 'MEDIUM',
                'keyword_match_source' => 'import',
            ],
        ]);

        $decoded = json_decode($encoded, true, flags: JSON_THROW_ON_ERROR);

        $this->assertSame(['sample product'], $decoded['products'][0]['keyword_research']['generated_seeds']['user']);
        $this->assertSame(['buy sample product'], $decoded['products'][0]['keyword_research']['generated_seeds']['ai']);
        $this->assertSame('sample product', $decoded['products'][0]['keyword_research']['matched_keyword']);
    }

    public function test_it_rejects_products_missing_primary_keywords(): void
    {
        $json = json_encode([
            'products' => array_fill(0, 5, [
                'name' => 'Sample Product',
                'url' => 'https://shop.example.com/p/1',
                'price' => '$19.99',
                'image_url' => 'https://cdn.example.com/p/1.jpg',
            ]),
        ]);

        $result = app(CatalogProductImportValidator::class)->validate($json);

        $this->assertFalse($result['valid']);
        $this->assertStringContainsString('keyword primary', strtolower(implode(' ', $result['errors'])));
    }

    public function test_it_accepts_two_valid_products(): void
    {
        $json = json_encode([
            'products' => [
                [
                    'name' => 'Sample Product One',
                    'url' => 'https://shop.example.com/p/1',
                    'price' => '$19.99',
                    'image_url' => 'https://cdn.example.com/p/1.jpg',
                    'keywords' => [
                        'primary' => 'sample product',
                    ],
                ],
                [
                    'name' => 'Sample Product Two',
                    'url' => 'https://shop.example.com/p/2',
                    'price' => '$24.99',
                    'image_url' => 'https://cdn.example.com/p/2.jpg',
                    'keywords' => [
                        'primary' => 'second product',
                    ],
                ],
            ],
        ]);

        $result = app(CatalogProductImportValidator::class)->validate($json);

        $this->assertTrue($result['valid']);
        $this->assertCount(2, $result['products']);
    }

    public function test_it_rejects_fewer_than_two_products(): void
    {
        $json = json_encode([
            'products' => [[
                'name' => 'Sample Product',
                'url' => 'https://shop.example.com/p/1',
                'price' => '$19.99',
                'image_url' => 'https://cdn.example.com/p/1.jpg',
                'keywords' => ['primary' => 'sample product'],
            ]],
        ]);

        $result = app(CatalogProductImportValidator::class)->validate($json);

        $this->assertFalse($result['valid']);
        $this->assertStringContainsString('at least 2', implode(' ', $result['errors']));
    }

    public function test_it_reports_invalid_json(): void
    {
        $result = app(CatalogProductImportValidator::class)->validate('{not-json');

        $this->assertFalse($result['valid']);
        $this->assertStringContainsString('Invalid JSON', $result['errors'][0]);
    }

    public function test_formatter_flattens_nested_rows(): void
    {
        $flat = (new CatalogProductJsonFormatter)->flattenRow([
            'name' => 'Chair',
            'url' => 'https://www.officedepot.com/a/products/254901/chair/',
            'pricing' => ['price' => '$39.99'],
            'ratings' => ['review_count' => '1205'],
            'media' => ['image_url' => 'https://media.officedepot.com/products/254901.jpg'],
            'keywords' => ['primary' => 'office chair'],
        ]);

        $this->assertSame('$39.99', $flat['price']);
        $this->assertSame('1205', $flat['review_count']);
        $this->assertSame('https://media.officedepot.com/products/254901.jpg', $flat['image_url']);
        $this->assertSame('office chair', $flat['keyword_primary']);
    }
}
