<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Tests\TenantTestCase;

class VehicleFilterAttributeSortingTest extends TenantTestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        Queue::fake();
    }

    private function createSortableAttribute(string $name, string $type): VehicleAttribute
    {
        $slug = Str::slug($name);

        $attribute = VehicleAttribute::forceCreate([
            'name' => $name,
            'slug' => $slug,
            'type' => $type,
            'sortable' => 1,
            'filterable' => 0,
            'count' => 1,
            'validation' => '[]',
            'data' => '[]',
        ]);

        // Manually seed sort settings — the observer that creates these lives in backend-api
        Settings::make([
            'tab' => 'Automotive',
            'section' => 'Filter',
            'group' => 'Sorting',
            'name' => "$name (Low > High)",
            'config_key' => "automotive-vehicle-sorting-{$slug}-asc",
            'type' => 'boolean',
            'value' => true,
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'Filter',
            'group' => 'Sorting',
            'name' => "$name (High > Low)",
            'config_key' => "automotive-vehicle-sorting-{$slug}-desc",
            'type' => 'boolean',
            'value' => true,
        ]);

        return $attribute;
    }

    private function createVehicleWithIntegerAttribute(VehicleAttribute $attribute, int $value): Vehicle
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);

        VehicleAttributeValue::forceCreate([
            'owner_id' => $vehicle->id,
            'owner_type' => 'vehicle',
            'attribute_id' => $attribute->id,
            'slug' => $attribute->slug,
            'type' => 'integer',
            'value_integer' => $value,
        ]);

        return $vehicle;
    }

    private function createVehicleWithNumberAttribute(VehicleAttribute $attribute, float $value): Vehicle
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);

        VehicleAttributeValue::forceCreate([
            'owner_id' => $vehicle->id,
            'owner_type' => 'vehicle',
            'attribute_id' => $attribute->id,
            'slug' => $attribute->slug,
            'type' => 'number',
            'value_float' => $value,
        ]);

        return $vehicle;
    }

    private function createVehicleWithBooleanAttribute(VehicleAttribute $attribute, bool $value): Vehicle
    {
        $vehicle = Vehicle::factory()->create(['is_published' => true]);

        VehicleAttributeValue::forceCreate([
            'owner_id' => $vehicle->id,
            'owner_type' => 'vehicle',
            'attribute_id' => $attribute->id,
            'slug' => $attribute->slug,
            'type' => 'boolean',
            'value_integer' => $value ? 1 : 0,
        ]);

        return $vehicle;
    }

    public function testSortByBooleanAttribute()
    {
        $attribute = VehicleAttribute::forceCreate([
            'name' => 'LEZ Compliant',
            'slug' => 'lez-compliant',
            'type' => 'boolean',
            'sortable' => 1,
            'filterable' => 0,
            'count' => 1,
            'validation' => '[]',
            'data' => '[]',
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'Filter',
            'group' => 'Sorting',
            'name' => 'LEZ Compliant',
            'config_key' => 'automotive-vehicle-sorting-lez-compliant',
            'type' => 'boolean',
            'value' => true,
        ]);

        $vehicleTrue1 = $this->createVehicleWithBooleanAttribute($attribute, true);
        $vehicleFalse = $this->createVehicleWithBooleanAttribute($attribute, false);
        $vehicleTrue2 = $this->createVehicleWithBooleanAttribute($attribute, true);

        $response = $this->postJson(route('vehicles.index'), [
            'sort_by' => $attribute->slug,
        ]);

        $response->assertStatus(200);
        $ids = $response->json('results.data.*.id');
        $this->assertContains($vehicleTrue1->id, array_slice($ids, 0, 2));
        $this->assertContains($vehicleTrue2->id, array_slice($ids, 0, 2));
        $this->assertEquals($vehicleFalse->id, $ids[2]);
    }

    public function testSortByIntegerAttributeAscending()
    {
        $attribute = $this->createSortableAttribute('Engine Size', 'integer');

        $vehicle1 = $this->createVehicleWithIntegerAttribute($attribute, 2000);
        $vehicle2 = $this->createVehicleWithIntegerAttribute($attribute, 1600);
        $vehicle3 = $this->createVehicleWithIntegerAttribute($attribute, 3000);

        $response = $this->postJson(route('vehicles.index'), [
            'sort_by' => $attribute->slug . '-asc',
        ]);

        $response->assertStatus(200);
        $this->assertEquals($vehicle2->id, $response->json('results.data.0.id'));
        $this->assertEquals($vehicle1->id, $response->json('results.data.1.id'));
        $this->assertEquals($vehicle3->id, $response->json('results.data.2.id'));
    }

    public function testSortByIntegerAttributeDescending()
    {
        $attribute = $this->createSortableAttribute('Engine Size', 'integer');

        $vehicle1 = $this->createVehicleWithIntegerAttribute($attribute, 2000);
        $vehicle2 = $this->createVehicleWithIntegerAttribute($attribute, 1600);
        $vehicle3 = $this->createVehicleWithIntegerAttribute($attribute, 3000);

        $response = $this->postJson(route('vehicles.index'), [
            'sort_by' => $attribute->slug . '-desc',
        ]);

        $response->assertStatus(200);
        $this->assertEquals($vehicle3->id, $response->json('results.data.0.id'));
        $this->assertEquals($vehicle1->id, $response->json('results.data.1.id'));
        $this->assertEquals($vehicle2->id, $response->json('results.data.2.id'));
    }

    public function testSortByNumberAttributeAscending()
    {
        $attribute = $this->createSortableAttribute('CO2 Emissions', 'number');

        $vehicle1 = $this->createVehicleWithNumberAttribute($attribute, 120.5);
        $vehicle2 = $this->createVehicleWithNumberAttribute($attribute, 89.3);
        $vehicle3 = $this->createVehicleWithNumberAttribute($attribute, 145.0);

        $response = $this->postJson(route('vehicles.index'), [
            'sort_by' => $attribute->slug . '-asc',
        ]);

        $response->assertStatus(200);
        $this->assertEquals($vehicle2->id, $response->json('results.data.0.id'));
        $this->assertEquals($vehicle1->id, $response->json('results.data.1.id'));
        $this->assertEquals($vehicle3->id, $response->json('results.data.2.id'));
    }

    public function testSortByNumberAttributeDescending()
    {
        $attribute = $this->createSortableAttribute('CO2 Emissions', 'number');

        $vehicle1 = $this->createVehicleWithNumberAttribute($attribute, 120.5);
        $vehicle2 = $this->createVehicleWithNumberAttribute($attribute, 89.3);
        $vehicle3 = $this->createVehicleWithNumberAttribute($attribute, 145.0);

        $response = $this->postJson(route('vehicles.index'), [
            'sort_by' => $attribute->slug . '-desc',
        ]);

        $response->assertStatus(200);
        $this->assertEquals($vehicle3->id, $response->json('results.data.0.id'));
        $this->assertEquals($vehicle1->id, $response->json('results.data.1.id'));
        $this->assertEquals($vehicle2->id, $response->json('results.data.2.id'));
    }

    public function testNumericAttributeSortOptionsAppearsInFilterResponse()
    {
        $attribute = $this->createSortableAttribute('Engine Size', 'integer');

        $response = $this->postJson(route('vehicles.index'), []);

        $response->assertStatus(200);
        $sortOptions = collect($response->json('sort_options'));
        $this->assertTrue($sortOptions->contains('code', $attribute->slug . '-asc'));
        $this->assertTrue($sortOptions->contains('code', $attribute->slug . '-desc'));
    }

    public function testNumericAttributeSortOptionLabels()
    {
        $attribute = $this->createSortableAttribute('Engine Size', 'integer');

        $response = $this->postJson(route('vehicles.index'), []);

        $response->assertStatus(200);
        $sortOptions = collect($response->json('sort_options'));

        $ascOption = $sortOptions->firstWhere('code', $attribute->slug . '-asc');
        $descOption = $sortOptions->firstWhere('code', $attribute->slug . '-desc');

        $this->assertEquals('Engine Size (Low > High)', $ascOption['label']);
        $this->assertEquals('Engine Size (High > Low)', $descOption['label']);
    }
}
