<?php

namespace Tests\Tenant;

use Carbon\Carbon;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Tests\TenantTestCase;

class NewCarAttributeFilterTest extends TenantTestCase
{
    private VehicleMake $make;
    private VehicleModel $model;

    protected function setUp(): void
    {
        parent::setUp();

        $this->make = VehicleMake::factory()->create();
        $this->model = VehicleModel::factory()->create(['make_id' => $this->make->id]);
    }

    private function makeNewCar(array $overrides = []): NewCar
    {
        return NewCar::factory()->create(array_merge([
            'make_id' => $this->make->id,
            'model_id' => $this->model->id,
            'published' => true,
            'published_at' => Carbon::now()->subDay(),
        ], $overrides));
    }

    private function makeBooleanAttribute(string $slug = 'heated-seats'): VehicleAttribute
    {
        return VehicleAttribute::query()->firstOrCreate(
            ['model' => 'new-car', 'slug' => $slug],
            [
                'name' => ucwords(str_replace('-', ' ', $slug)),
                'type' => 'boolean',
                'filterable' => 1,
                'validation' => [],
                'data' => [],
            ]
        );
    }

    private function makeIntegerAttribute(string $slug = 'horsepower'): VehicleAttribute
    {
        return VehicleAttribute::query()->firstOrCreate(
            ['model' => 'new-car', 'slug' => $slug],
            [
                'name' => ucwords(str_replace('-', ' ', $slug)),
                'type' => 'integer',
                'filterable' => 1,
                'validation' => [],
                'data' => [],
            ]
        );
    }

    public function testFilterByBooleanAttributeYes(): void
    {
        $attribute = $this->makeBooleanAttribute('heated-seats');

        $carWithFeature = $this->makeNewCar();
        $carWithoutFeature = $this->makeNewCar();
        $this->makeNewCar(); // no attribute value at all

        VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $carWithFeature->id,
            'owner_type' => 'new-car',
            'slug' => 'heated-seats',
            'type' => 'boolean',
            'value' => '1',
            'value_integer' => 1,
        ]);

        VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $carWithoutFeature->id,
            'owner_type' => 'new-car',
            'slug' => 'heated-seats',
            'type' => 'boolean',
            'value' => '0',
            'value_integer' => 0,
        ]);

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

        // Filter by heated-seats=yes — only carWithFeature
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'heated-seats' => 'yes',
        ]);
        $response->assertStatus(200);
        $this->assertCount(1, $response->json('offers.data'));
        $this->assertEquals($carWithFeature->slug, $response->json('offers.data.0.slug'));
    }

    public function testFilterByBooleanAttributeNo(): void
    {
        $attribute = $this->makeBooleanAttribute('heated-seats');

        $carWithFeature = $this->makeNewCar();
        $carWithoutFeature = $this->makeNewCar();

        VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $carWithFeature->id,
            'owner_type' => 'new-car',
            'slug' => 'heated-seats',
            'type' => 'boolean',
            'value' => '1',
            'value_integer' => 1,
        ]);

        VehicleAttributeValue::query()->create([
            'attribute_id' => $attribute->id,
            'owner_id' => $carWithoutFeature->id,
            'owner_type' => 'new-car',
            'slug' => 'heated-seats',
            'type' => 'boolean',
            'value' => '0',
            'value_integer' => 0,
        ]);

        // Filter by heated-seats=no — only carWithoutFeature
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'heated-seats' => 'no',
        ]);
        $response->assertStatus(200);
        $this->assertCount(1, $response->json('offers.data'));
        $this->assertEquals($carWithoutFeature->slug, $response->json('offers.data.0.slug'));
    }

    public function testFilterByIntegerAttributeMin(): void
    {
        $attribute = $this->makeIntegerAttribute('horsepower');

        $car100 = $this->makeNewCar();
        $car250 = $this->makeNewCar();
        $car400 = $this->makeNewCar();

        foreach ([[$car100, 100], [$car250, 250], [$car400, 400]] as [$car, $hp]) {
            VehicleAttributeValue::query()->create([
                'attribute_id' => $attribute->id,
                'owner_id' => $car->id,
                'owner_type' => 'new-car',
                'slug' => 'horsepower',
                'type' => 'integer',
                'value' => $hp,
                'value_integer' => $hp,
            ]);
        }

        // No filter — all 3
        $response = $this->postJson(route('new-cars.search', $this->make->slug));
        $response->assertStatus(200);
        $this->assertCount(3, $response->json('offers.data'));

        // Min 250 — car250 and car400
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'horsepower_min' => 250,
        ]);
        $response->assertStatus(200);
        $this->assertCount(2, $response->json('offers.data'));

        // Min 400 — only car400
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'horsepower_min' => 400,
        ]);
        $response->assertStatus(200);
        $this->assertCount(1, $response->json('offers.data'));
        $this->assertEquals($car400->slug, $response->json('offers.data.0.slug'));
    }

    public function testFilterByIntegerAttributeMax(): void
    {
        $attribute = $this->makeIntegerAttribute('horsepower');

        $car100 = $this->makeNewCar();
        $car250 = $this->makeNewCar();
        $car400 = $this->makeNewCar();

        foreach ([[$car100, 100], [$car250, 250], [$car400, 400]] as [$car, $hp]) {
            VehicleAttributeValue::query()->create([
                'attribute_id' => $attribute->id,
                'owner_id' => $car->id,
                'owner_type' => 'new-car',
                'slug' => 'horsepower',
                'type' => 'integer',
                'value' => $hp,
                'value_integer' => $hp,
            ]);
        }

        // Max 250 — car100 and car250
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'horsepower_max' => 250,
        ]);
        $response->assertStatus(200);
        $this->assertCount(2, $response->json('offers.data'));

        // Max 100 — only car100
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'horsepower_max' => 100,
        ]);
        $response->assertStatus(200);
        $this->assertCount(1, $response->json('offers.data'));
        $this->assertEquals($car100->slug, $response->json('offers.data.0.slug'));
    }

    public function testFilterByIntegerAttributeRange(): void
    {
        $attribute = $this->makeIntegerAttribute('horsepower');

        $car100 = $this->makeNewCar();
        $car250 = $this->makeNewCar();
        $car400 = $this->makeNewCar();

        foreach ([[$car100, 100], [$car250, 250], [$car400, 400]] as [$car, $hp]) {
            VehicleAttributeValue::query()->create([
                'attribute_id' => $attribute->id,
                'owner_id' => $car->id,
                'owner_type' => 'new-car',
                'slug' => 'horsepower',
                'type' => 'integer',
                'value' => $hp,
                'value_integer' => $hp,
            ]);
        }

        // Range 100–250 — car100 and car250
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'horsepower_min' => 100,
            'horsepower_max' => 250,
        ]);
        $response->assertStatus(200);
        $this->assertCount(2, $response->json('offers.data'));

        // Range 250–250 — only car250
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'horsepower_min' => 250,
            'horsepower_max' => 250,
        ]);
        $response->assertStatus(200);
        $this->assertCount(1, $response->json('offers.data'));
        $this->assertEquals($car250->slug, $response->json('offers.data.0.slug'));
    }

    public function testAttributeFilterNotAppliedWhenNoFilterableAttributeExists(): void
    {
        // Create a non-filterable attribute — should be ignored
        VehicleAttribute::query()->create([
            'model' => 'new-car',
            'slug' => 'hidden-attr',
            'name' => 'Hidden Attr',
            'type' => 'boolean',
            'filterable' => 0,
            'validation' => [],
            'data' => [],
        ]);

        $this->makeNewCar();
        $this->makeNewCar();

        // Passing the param should be a no-op — both cars returned
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'hidden-attr' => 'yes',
        ]);
        $response->assertStatus(200);
        $this->assertCount(2, $response->json('offers.data'));
    }

    public function testVehicleAttributeDoesNotFilterNewCarsWhenScopedToVehicleModel(): void
    {
        // Attribute scoped to 'vehicle', not 'new-car' — should not affect new car results
        VehicleAttribute::query()->create([
            'model' => 'vehicle',
            'slug' => 'horsepower',
            'name' => 'Horsepower',
            'type' => 'integer',
            'filterable' => 1,
            'validation' => [],
            'data' => [],
        ]);

        $this->makeNewCar();
        $this->makeNewCar();
        $this->makeNewCar();

        // Passing horsepower_min should be a no-op since attribute is scoped to 'vehicle'
        $response = $this->postJson(route('new-cars.search', $this->make->slug), [
            'horsepower_min' => 999,
        ]);
        $response->assertStatus(200);
        $this->assertCount(3, $response->json('offers.data'));
    }
}
