<?php

namespace Tests\Tenant;

use Mtc\MercuryDataModels\Media;
use Mtc\MercuryDataModels\MediaUse;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleTrim;
use Tests\TenantTestCase;

class VehicleTrimSearchTest extends TenantTestCase
{
    public function testSearchReturnsActiveTrimsForActiveNewCars()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create(['make_id' => $make->id]);

        $newCar = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'published' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Active Trim',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Inactive Trim',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => false,
        ]);

        $response = $this->postJson(route('trims.search'));

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertEquals('Active Trim', $response->json('data.0.name'));
    }

    public function testSearchExcludesTrimsForInactiveNewCars()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create(['make_id' => $make->id]);

        $activeNewCar = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'published' => true,
        ]);

        $inactiveNewCar = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'published' => false,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim on active car',
            'new_car_id' => $activeNewCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim on inactive car',
            'new_car_id' => $inactiveNewCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        $response = $this->postJson(route('trims.search'));

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertEquals('Trim on active car', $response->json('data.0.name'));
    }

    public function testSearchReturnsTrimsAcrossMultipleNewCars()
    {
        $make = VehicleMake::factory()->create();
        $model1 = VehicleModel::factory()->create(['make_id' => $make->id]);
        $model2 = VehicleModel::factory()->create(['make_id' => $make->id]);

        $newCar1 = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model1->id,
            'published' => true,
        ]);

        $newCar2 = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model2->id,
            'published' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Car 1 Trim A',
            'new_car_id' => $newCar1->id,
            'make_id' => $make->id,
            'model_id' => $model1->id,
            'active' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Car 1 Trim B',
            'new_car_id' => $newCar1->id,
            'make_id' => $make->id,
            'model_id' => $model1->id,
            'active' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Car 2 Trim A',
            'new_car_id' => $newCar2->id,
            'make_id' => $make->id,
            'model_id' => $model2->id,
            'active' => true,
        ]);

        $response = $this->postJson(route('trims.search'));

        $response->assertStatus(200);
        $this->assertCount(3, $response->json('data'));
    }

    public function testSearchFiltersByMake()
    {
        $make1 = VehicleMake::factory()->create();
        $make2 = VehicleMake::factory()->create();
        $model1 = VehicleModel::factory()->create(['make_id' => $make1->id]);
        $model2 = VehicleModel::factory()->create(['make_id' => $make2->id]);

        $newCar1 = NewCar::factory()->create([
            'make_id' => $make1->id,
            'model_id' => $model1->id,
            'published' => true,
        ]);

        $newCar2 = NewCar::factory()->create([
            'make_id' => $make2->id,
            'model_id' => $model2->id,
            'published' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim Make 1',
            'new_car_id' => $newCar1->id,
            'make_id' => $make1->id,
            'model_id' => $model1->id,
            'active' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim Make 2',
            'new_car_id' => $newCar2->id,
            'make_id' => $make2->id,
            'model_id' => $model2->id,
            'active' => true,
        ]);

        $response = $this->postJson(route('trims.search'), [
            'make' => $make1->slug,
        ]);

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertEquals('Trim Make 1', $response->json('data.0.name'));
    }

    public function testSearchFiltersByModel()
    {
        $make = VehicleMake::factory()->create();
        $model1 = VehicleModel::factory()->create(['make_id' => $make->id]);
        $model2 = VehicleModel::factory()->create(['make_id' => $make->id]);

        $newCar1 = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model1->id,
            'published' => true,
        ]);

        $newCar2 = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model2->id,
            'published' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim Model 1',
            'new_car_id' => $newCar1->id,
            'make_id' => $make->id,
            'model_id' => $model1->id,
            'active' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim Model 2',
            'new_car_id' => $newCar2->id,
            'make_id' => $make->id,
            'model_id' => $model2->id,
            'active' => true,
        ]);

        $response = $this->postJson(route('trims.search'), [
            'model' => $model1->slug,
        ]);

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertEquals('Trim Model 1', $response->json('data.0.name'));
    }

    public function testSearchReturnsImagesArray()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create(['make_id' => $make->id]);

        $newCar = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'published' => true,
        ]);

        $trim = VehicleTrim::query()->create([
            'name' => 'Trim With Image',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        $media = Media::factory()->create([
            'src' => 'trim-image.jpg',
            'type' => 'image',
        ]);

        MediaUse::factory()->create([
            'media_id' => $media->id,
            'owner_type' => 'vehicle-trim',
            'owner_id' => $trim->id,
            'primary' => true,
            'allowed_sizes' => [],
        ]);

        $response = $this->postJson(route('trims.search'));

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertArrayHasKey('images', $response->json('data.0'));
        $this->assertArrayHasKey('trim', $response->json('data.0.images'));
        $this->assertArrayHasKey('listing', $response->json('data.0.images'));
        $this->assertNotNull($response->json('data.0.images.trim.src'));
    }

    public function testSearchReturnsNullImageFieldsWhenNoMedia()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create(['make_id' => $make->id]);

        $newCar = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'published' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim Without Image',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        $response = $this->postJson(route('trims.search'));

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertArrayHasKey('images', $response->json('data.0'));
        $this->assertNull($response->json('data.0.images.trim.src'));
        $this->assertNull($response->json('data.0.images.listing.src'));
    }

    public function testSearchReturnsImagesWithTrimAndListingImages()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create(['make_id' => $make->id]);

        $newCar = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'published' => true,
        ]);

        $trim = VehicleTrim::query()->create([
            'name' => 'Trim With Both Images',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        $trimMedia = Media::factory()->create([
            'src' => 'trim-primary.jpg',
            'type' => 'image',
        ]);

        $listingMedia = Media::factory()->create([
            'src' => 'trim-listing.jpg',
            'type' => 'image',
        ]);

        MediaUse::factory()->create([
            'media_id' => $trimMedia->id,
            'owner_type' => 'vehicle-trim',
            'owner_id' => $trim->id,
            'primary' => true,
            'title' => 'Trim Primary Title',
            'alt_text' => 'Trim primary alt',
            'allowed_sizes' => [],
            'flags' => [],
        ]);

        MediaUse::factory()->create([
            'media_id' => $listingMedia->id,
            'owner_type' => 'vehicle-trim',
            'owner_id' => $trim->id,
            'primary' => false,
            'title' => 'Listing Title',
            'alt_text' => 'Listing alt',
            'allowed_sizes' => [],
            'flags' => ['listing' => true],
        ]);

        $response = $this->postJson(route('trims.search'));

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));

        $images = $response->json('data.0.images');

        // Trim image has all expected fields
        $this->assertEquals('Trim Primary Title', $images['trim']['title']);
        $this->assertEquals('Trim primary alt', $images['trim']['alt_text']);
        $this->assertNotNull($images['trim']['src']);
        $this->assertArrayHasKey('sizes', $images['trim']);
        $this->assertArrayHasKey('original', $images['trim']['sizes']);
        $this->assertArrayHasKey('description', $images['trim']);
        $this->assertArrayHasKey('caption', $images['trim']);
        $this->assertArrayHasKey('interior', $images['trim']);
        $this->assertArrayHasKey('exterior', $images['trim']);
        $this->assertArrayHasKey('type', $images['trim']);
        $this->assertArrayHasKey('hex1', $images['trim']);
        $this->assertArrayHasKey('hex2', $images['trim']);

        // Listing image has all expected fields
        $this->assertEquals('Listing Title', $images['listing']['title']);
        $this->assertEquals('Listing alt', $images['listing']['alt_text']);
        $this->assertNotNull($images['listing']['src']);
        $this->assertArrayHasKey('sizes', $images['listing']);
        $this->assertArrayHasKey('original', $images['listing']['sizes']);
    }

    public function testSearchFiltersByBooleanAttribute()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create(['make_id' => $make->id]);

        $newCar = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'published' => true,
        ]);

        $attribute = VehicleAttribute::query()->create([
            'model' => 'vehicle-trim',
            'slug' => '4x4',
            'name' => '4x4',
            'type' => 'boolean',
            'filterable' => 1,
            'validation' => [],
            'data' => [],
        ]);

        $trimWith4x4 = VehicleTrim::query()->create([
            'name' => 'Sport 4x4',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        $trimWithout4x4 = VehicleTrim::query()->create([
            'name' => 'Sport 2WD',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        $trimNoAttribute = VehicleTrim::query()->create([
            'name' => 'Base',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $trimWith4x4->id,
            'owner_type' => 'vehicle-trim',
            'slug' => '4x4',
            'type' => 'boolean',
            'value' => '1',
            'value_integer' => 1,
        ]);

        VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $trimWithout4x4->id,
            'owner_type' => 'vehicle-trim',
            'slug' => '4x4',
            'type' => 'boolean',
            'value' => '0',
            'value_integer' => 0,
        ]);

        // No filter — all 3 trims returned
        $response = $this->postJson(route('trims.search'));
        $response->assertStatus(200);
        $this->assertCount(3, $response->json('data'));

        // Filter 4x4=yes — only the 4x4 trim
        $response = $this->postJson(route('trims.search'), [
            '4x4' => 'yes',
        ]);
        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertEquals('Sport 4x4', $response->json('data.0.name'));

        // Filter 4x4=no — the 2WD trim and the one with no attribute value
        $response = $this->postJson(route('trims.search'), [
            '4x4' => 'no',
        ]);
        $response->assertStatus(200);
        $this->assertCount(2, $response->json('data'));
        $names = collect($response->json('data'))->pluck('name')->sort()->values()->all();
        $this->assertEquals(['Base', 'Sport 2WD'], $names);
    }

    public function testSearchWithNoFiltersReturnsAllActiveTrims()
    {
        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create(['make_id' => $make->id]);

        $newCar = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'published' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim A',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        VehicleTrim::query()->create([
            'name' => 'Trim B',
            'new_car_id' => $newCar->id,
            'make_id' => $make->id,
            'model_id' => $model->id,
            'active' => true,
        ]);

        $response = $this->postJson(route('trims.search'));

        $response->assertStatus(200);
        $this->assertCount(2, $response->json('data'));
    }
}
