<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\OfferType;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\MercuryDataModels\VehicleFinance;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleOffer;
use Mtc\MercuryDataModels\VehicleOfferFinance;
use Tests\FilterSettingSeed;
use Tests\OfferFilterSettingSeed;
use Tests\SortingSettingSeed;
use Tests\TenantTestCase;

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

    public function testStockResultCount()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'filter-results-per-page',
            'value' => '20',
            'type' => 'string',
        ]);

        Vehicle::factory(50)->create([
            'is_published' => true,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(50, $response->json('results.total'));
        $this->assertCount(20, $response->json('results.data'));
    }

    public function testOfferResultCount()
    {
        Config::set('filter.result_page_limit', '20');

        VehicleOffer::factory(50)->create([
            'published' => true,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(50, $response->json('results.total'));
        $this->assertCount(20, $response->json('results.data'));
    }

    public function testResultCount()
    {
        Config::set('filter.result_page_limit', '20');

        Vehicle::factory(7)->create([
            'is_published' => true,
        ]);

        VehicleOffer::factory(5)->create([
            'published' => true,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertCount(12, $response->json('results.data'));
    }

    public function testStockAndOfferSearch()
    {
        Config::set('filter.result_page_limit', '20');

        $make_for_vehicle = VehicleMake::factory()->create();
        $make_for_offer = VehicleMake::factory()->create();

        Vehicle::factory(50)->create([
            'is_published' => true,
            'make_id' => $make_for_vehicle->id,
        ]);

        VehicleOffer::factory(30)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(80, $response->json('results.total'));
        $this->assertEquals((80 / Config::get('filter.result_page_limit')), $response->json('results.last_page'));
        $this->assertCount(20, $response->json('results.data'));
    }

    public function testCombinedSearchData()
    {
        Queue::fake();
        Config::set('filter.result_page_limit', '20');

        $this->seed(FilterSettingSeed::class);
        $this->seed(OfferFilterSettingSeed::class);
        $this->seed(SortingSettingSeed::class);

        $make_for_vehicle = VehicleMake::factory()->create([
            'name' => 'example stock make'
        ]);
        $make_for_offer = VehicleMake::factory()->create([
            'name' => 'example offer make'
        ]);

        Vehicle::factory(50)->create([
            'is_published' => true,
            'make_id' => $make_for_vehicle->id,
        ]);

        VehicleOffer::factory(30)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertArrayHasKey('filters', $response->json());
        $this->assertArrayHasKey('make', $response->json('filters'));
        $this->assertArrayHasKey('results', $response->json('filters.make'));
        $this->assertCount(2, $response->json('filters.make.results'));

        $make_filter_options = collect($response->json('filters.make.results'))
            ->mapWithKeys(fn ($result) => [$result['name'] => $result['name']]);

        $this->assertArrayHasKey($make_for_vehicle->name, $make_filter_options);
        $this->assertArrayHasKey($make_for_offer->name, $make_filter_options);

        $this->assertArrayHasKey('sort_options', $response->json());
        $this->assertCount(10, $response->json('sort_options'));
    }

    public function testFilterResultListData()
    {
        Queue::fake();
        Config::set('filter.result_page_limit', '20');

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'vehicle-list-load-finance-example',
            'value' => true,
            'type' => 'bool',
        ]);

        $this->seed(FilterSettingSeed::class);
        $this->seed(OfferFilterSettingSeed::class);
        $this->seed(SortingSettingSeed::class);

        $dealership = Dealership::factory()->create();

        $vehicle = Vehicle::factory()->create([
            'is_published' => true,
            'dealership_id' => $dealership->id,
            'colour' => 'red',
            'trim' => 'foo',
            'is_vat_applicable' => true,
            'title' => 'bar',
        ]);

        $vehicle_offer = VehicleOffer::factory()->create([
            'published' => true,
            'dealership_id' => $dealership->id,
            'colour' => 'red',
            'trim' => 'foo',
            'name' => 'bar',
        ]);

        VehicleFinance::factory()->create([
            'vehicle_id' => $vehicle->id,
            'finance_type' => 'PCP',
        ]);

        VehicleOfferFinance::query()->create([
            'offer_id' => $vehicle_offer->id,
            'finance_type' => 'PCP',
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);

        $response->assertStatus(200);

        $this->assertEquals(2, $response->json('results.total'));

        foreach ($response->json('results.data') as $vehicle) {
            $this->assertArrayHasKey('colour', $vehicle);
            $this->assertArrayHasKey('dealership', $vehicle);
            $this->assertArrayHasKey('trim', $vehicle);
            $this->assertArrayHasKey('is_vat_applicable', $vehicle);
            $this->assertArrayHasKey('title', $vehicle);
            $this->assertArrayHasKey('original_price', $vehicle);
            $this->assertArrayHasKey('previous_price', $vehicle);
            $this->assertArrayHasKey('rrp_price', $vehicle);
            $this->assertArrayHasKey('monthly_cost_type', $vehicle);
            $this->assertArrayHasKey('finance_example', $vehicle);

            $this->assertEquals($dealership->name, $vehicle['dealership']['name']);
            $this->assertEquals('foo', $vehicle['trim']);
            $this->assertEquals('red', $vehicle['colour']);
            $this->assertEquals(true, $vehicle['is_vat_applicable']);
            $this->assertEquals('bar', $vehicle['title']);
            $this->assertEquals('PCP', $vehicle['monthly_cost_type']);
            $this->assertNotNull($vehicle['finance_example']);
        }
    }

    public function testOrderingAscending()
    {
        Config::set('filter.result_page_limit', '20');

        $this->seed(SortingSettingSeed::class);

        Vehicle::factory()->create([
            'is_published' => true,
            'price' => 10
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'price' => 30
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'price' => 50
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 20
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 40
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 60
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
                'sort_by' => 'price-asc',
            ]);

        $response->assertStatus(200);

        $this->assertEquals(6, $response->json('results.total'));
        $this->assertCount(6, $response->json('results.data'));

        $this->assertEquals(10, $response->json('results.data.0.price'));
        $this->assertEquals(20, $response->json('results.data.1.price'));
        $this->assertEquals(30, $response->json('results.data.2.price'));
        $this->assertEquals(40, $response->json('results.data.3.price'));
        $this->assertEquals(50, $response->json('results.data.4.price'));
        $this->assertEquals(60, $response->json('results.data.5.price'));
    }

    public function testOrderingDescending()
    {
        Config::set('filter.result_page_limit', '20');

        $this->seed(SortingSettingSeed::class);

        Vehicle::factory()->create([
            'is_published' => true,
            'price' => 10
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'price' => 30
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'price' => 50
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 20
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 40
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 60
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
                'sort_by' => 'price-desc',
            ]);

        $response->assertStatus(200);

        $this->assertEquals(6, $response->json('results.total'));
        $this->assertCount(6, $response->json('results.data'));

        $this->assertEquals(60, $response->json('results.data.0.price'));
        $this->assertEquals(50, $response->json('results.data.1.price'));
        $this->assertEquals(40, $response->json('results.data.2.price'));
        $this->assertEquals(30, $response->json('results.data.3.price'));
        $this->assertEquals(20, $response->json('results.data.4.price'));
        $this->assertEquals(10, $response->json('results.data.5.price'));
    }

    public function testOrderingMileage()
    {
        Config::set('filter.result_page_limit', '20');

        $this->seed(SortingSettingSeed::class);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'automotive-distance_measurement',
            'value' => 'mi',
            'type' => 'string',
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'odometer_mi' => 10
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'odometer_mi' => 30
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'odometer_mi' => 50
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
                'sort_by' => 'mileage-asc',
            ]);

        $response->assertStatus(200);

        $this->assertEquals(6, $response->json('results.total'));
        $this->assertCount(6, $response->json('results.data'));

        $this->assertEquals(0, $response->json('results.data.0.odometer_mi'));
        $this->assertEquals(0, $response->json('results.data.1.odometer_mi'));
        $this->assertEquals(0, $response->json('results.data.2.odometer_mi'));
        $this->assertEquals(10, $response->json('results.data.3.odometer_mi'));
        $this->assertEquals(30, $response->json('results.data.4.odometer_mi'));
        $this->assertEquals(50, $response->json('results.data.5.odometer_mi'));
    }

    public function testNewAdditionSorting()
    {
        $this->seed(SortingSettingSeed::class);

        Vehicle::factory()->create([
            'is_published' => true,
            'slug' => '1',
            'created_at' => '2024-01-01 00:00:00'
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'slug' => '5',
            'created_at' => '2024-01-05 00:00:00'
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'slug' => '7',
            'created_at' => '2024-01-07 00:00:00'
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'slug' => '6',
            'created_at' => '2024-01-06 00:00:00'
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'slug' => '4',
            'created_at' => '2024-01-04 00:00:00'
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'slug' => '2',
            'created_at' => '2024-01-02 00:00:00'
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
                'sort_by' => 'latest',
            ]);

        $response->assertStatus(200);

        $this->assertEquals(6, $response->json('results.total'));
        $this->assertCount(6, $response->json('results.data'));

        $this->assertEquals('7', $response->json('results.data.0.slug'));
        $this->assertEquals('6', $response->json('results.data.1.slug'));
        $this->assertEquals('5', $response->json('results.data.2.slug'));
        $this->assertEquals('4', $response->json('results.data.3.slug'));
        $this->assertEquals('2', $response->json('results.data.4.slug'));
        $this->assertEquals('1', $response->json('results.data.5.slug'));
    }

    public function testAgeSorting()
    {
        $this->seed(SortingSettingSeed::class);

        Vehicle::factory()->create([
            'is_published' => true,
            'manufacture_year' => '2020',
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'manufacture_year' => '2023',
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'manufacture_year' => '2021',
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
                'sort_by' => 'age-asc',
            ]);

        $response->assertStatus(200);

        $this->assertEquals(6, $response->json('results.total'));
        $this->assertCount(6, $response->json('results.data'));

        $this->assertEquals('2020', $response->json('results.data.0.manufacture_year'));
        $this->assertEquals('2021', $response->json('results.data.1.manufacture_year'));
        $this->assertEquals('2023', $response->json('results.data.2.manufacture_year'));
        $this->assertEquals(date('Y'), $response->json('results.data.3.manufacture_year'));
        $this->assertEquals(date('Y'), $response->json('results.data.4.manufacture_year'));
        $this->assertEquals(date('Y'), $response->json('results.data.5.manufacture_year'));
    }

    public function testMonthlyPriceSorting()
    {
        Config::set('filter.result_page_limit', '20');

        $this->seed(SortingSettingSeed::class);

        Vehicle::factory()->create([
            'is_published' => true,
            'monthly_price' => 10
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'monthly_price' => 30
        ]);

        Vehicle::factory()->create([
            'is_published' => true,
            'monthly_price' => 50
        ]);

        $offer1 = VehicleOffer::factory()->create([
            'published' => true,
        ]);

        $offer2 = VehicleOffer::factory()->create([
            'published' => true,
        ]);

        $offer3 = VehicleOffer::factory()->create([
            'published' => true,
        ]);

        VehicleOfferFinance::query()->create([
            'offer_id' => $offer1->id,
            'monthly_price' => 80
        ]);

        VehicleOfferFinance::query()->create([
            'offer_id' => $offer2->id,
            'monthly_price' => 40
        ]);

        VehicleOfferFinance::query()->create([
            'offer_id' => $offer3->id,
            'monthly_price' => 20
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
                'sort_by' => 'monthly-price-asc',
            ]);

        $response->assertStatus(200);

        $this->assertEquals(6, $response->json('results.total'));
        $this->assertCount(6, $response->json('results.data'));

        $this->assertEquals(10, $response->json('results.data.0.monthly_price'));
        $this->assertEquals(20, $response->json('results.data.1.monthly_price'));
        $this->assertEquals(30, $response->json('results.data.2.monthly_price'));
        $this->assertEquals(40, $response->json('results.data.3.monthly_price'));
        $this->assertEquals(50, $response->json('results.data.4.monthly_price'));
        $this->assertEquals(80, $response->json('results.data.5.monthly_price'));
    }

    public function testStockIsNewFalse()
    {
        Config::set('filter.result_page_limit', '20');

        Vehicle::factory()->create([
            'is_published' => true,
            'is_new' => false,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertCount(1, $response->json('results.data'));
        $this->assertArrayHasKey('is_new', $response->json('results.data.0'));
        $this->assertFalse($response->json('results.data.0.is_new'));
    }

    public function testStockIsNewTrue()
    {
        Config::set('filter.result_page_limit', '20');

        Vehicle::factory()->create([
            'is_published' => true,
            'is_new' => true,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertCount(1, $response->json('results.data'));
        $this->assertArrayHasKey('is_new', $response->json('results.data.0'));
        $this->assertTrue($response->json('results.data.0.is_new'));
    }

    public function testOfferIsNewTrue()
    {
        Config::set('filter.result_page_limit', '20');

        VehicleOffer::factory()->create([
            'published' => true,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertCount(1, $response->json('results.data'));
        $this->assertArrayHasKey('is_new', $response->json('results.data.0'));
        $this->assertTrue($response->json('results.data.0.is_new'));
    }

    public function testStockStatusOffersOnly()
    {
        Config::set('filter.result_page_limit', '20');
        $make_for_vehicle = VehicleMake::factory()->create();
        $make_for_offer = VehicleMake::factory()->create();
        Vehicle::factory(50)->create([
            'is_published' => true,
            'make_id' => $make_for_vehicle->id,
        ]);
        VehicleOffer::factory(10)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);
        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'stock_status',
                        'value' => 'available-to-order',
                    ]
                ],
            ]);
        $response->assertStatus(200);
        $this->assertEquals(10, $response->json('results.total'));
        $this->assertCount(10, $response->json('results.data'));
    }

    public function testStockStatusStockOnly()
    {
        Config::set('filter.result_page_limit', '20');
        $make_for_vehicle = VehicleMake::factory()->create();
        $make_for_offer = VehicleMake::factory()->create();
        Vehicle::factory(50)->create([
            'is_published' => true,
            'make_id' => $make_for_vehicle->id,
        ]);
        VehicleOffer::factory(10)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);
        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'stock_status',
                        'value' => 'available-now',
                    ]
                ],
            ]);
        $response->assertStatus(200);
        $this->assertEquals(50, $response->json('results.total'));
        $this->assertCount(20, $response->json('results.data'));
    }

    public function testStockStatusAll()
    {
        Config::set('filter.result_page_limit', '20');
        $make_for_vehicle = VehicleMake::factory()->create();
        $make_for_offer = VehicleMake::factory()->create();
        Vehicle::factory(50)->create([
            'is_published' => true,
            'make_id' => $make_for_vehicle->id,
        ]);
        VehicleOffer::factory(10)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);
        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'stock_status',
                        'value' => 'available-now',
                    ],
                    [
                        'type' => 'stock_status',
                        'value' => 'available-to-order',
                    ]
                ],
            ]);
        $response->assertStatus(200);
        $this->assertEquals(60, $response->json('results.total'));
        $this->assertCount(20, $response->json('results.data'));
    }

    public function testStockStatusNone()
    {
        Config::set('filter.result_page_limit', '20');
        $make_for_vehicle = VehicleMake::factory()->create();
        $make_for_offer = VehicleMake::factory()->create();
        Vehicle::factory(50)->create([
            'is_published' => true,
            'make_id' => $make_for_vehicle->id,
        ]);
        VehicleOffer::factory(10)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);
        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);
        $this->assertEquals(60, $response->json('results.total'));
        $this->assertCount(20, $response->json('results.data'));
    }

    public function testFilterDataAll()
    {
        Queue::fake();
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'filter-apply-selections-to-results',
            'value' => true,
            'type' => 'bool',
        ]);

        Config::set('filter.result_page_limit', '20');

        $this->seed();
        $this->seed(FilterSettingSeed::class);
        $this->seed(OfferFilterSettingSeed::class);

        $make_for_new = VehicleMake::factory()->create([
            'name' => 'foo',
        ]);

        $make_for_used = VehicleMake::factory()->create([
            'name' => 'bar',
        ]);

        $make_for_offer = VehicleMake::factory()->create([
            'name' => 'baz',
        ]);

        Vehicle::factory(5)->create([
            'is_published' => true,
            'is_new' => true,
            'make_id' => $make_for_new->id,
        ]);

        Vehicle::factory(3)->create([
            'is_published' => true,
            'is_new' => false,
            'make_id' => $make_for_used->id,
        ]);

        VehicleOffer::factory(2)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(10, $response->json('results.total'));
        $this->assertCount(3, $response->json('filters.make.results'));
    }

    public function testFilterDataUsedOnly()
    {
        Queue::fake();
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'filter-apply-selections-to-results',
            'value' => true,
            'type' => 'bool',
        ]);

        Config::set('filter.result_page_limit', '20');

        $this->seed();
        $this->seed(FilterSettingSeed::class);

        $make_for_new = VehicleMake::factory()->create([
            'name' => 'foo',
        ]);

        $make_for_used = VehicleMake::factory()->create([
            'name' => 'bar',
        ]);

        $make_for_offer = VehicleMake::factory()->create([
            'name' => 'baz',
        ]);

        Vehicle::factory(5)->create([
            'is_published' => true,
            'is_new' => true,
            'make_id' => $make_for_new->id,
        ]);

        Vehicle::factory(3)->create([
            'is_published' => true,
            'is_new' => false,
            'is_demo' => false,
            'make_id' => $make_for_used->id,
        ]);

        VehicleOffer::factory(2)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'is_new',
                        'value' => 'used',
                    ],
                ],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(3, $response->json('results.total'));
        $this->assertCount(1, $response->json('filters.make.results'));
        $this->assertEquals('bar', $response->json('filters.make.results.0.slug'));
    }

    public function testFilterDataOffersOnly()
    {
        Queue::fake();
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'filter-apply-selections-to-results',
            'value' => true,
            'type' => 'bool',
        ]);

        Config::set('filter.result_page_limit', '20');

        $this->seed();
        $this->seed(FilterSettingSeed::class);
        $this->seed(OfferFilterSettingSeed::class);

        $make_for_new = VehicleMake::factory()->create([
            'name' => 'foo',
        ]);

        $make_for_used = VehicleMake::factory()->create([
            'name' => 'bar',
        ]);

        $make_for_offer = VehicleMake::factory()->create([
            'name' => 'baz',
        ]);

        Vehicle::factory(5)->create([
            'is_published' => true,
            'is_new' => true,
            'make_id' => $make_for_new->id,
        ]);

        Vehicle::factory(3)->create([
            'is_published' => true,
            'is_new' => false,
            'make_id' => $make_for_used->id,
        ]);

        VehicleOffer::factory(2)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'stock_status',
                        'value' => 'available-to-order',
                    ],
                ],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(2, $response->json('results.total'));
        $this->assertCount(1, $response->json('filters.make.results'));
        $this->assertEquals('baz', $response->json('filters.make.results.0.slug'));
    }

    public function testFilterDataNew()
    {
        Queue::fake();
        Config::set('filter.result_page_limit', '20');

        $this->seed();
        $this->seed(FilterSettingSeed::class);
        $this->seed(OfferFilterSettingSeed::class);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'filter-apply-selections-to-results',
            'value' => true,
            'type' => 'bool',
        ]);

        $make_for_new = VehicleMake::factory()->create([
            'name' => 'foo',
        ]);

        $make_for_used = VehicleMake::factory()->create([
            'name' => 'bar',
        ]);

        $make_for_offer = VehicleMake::factory()->create([
            'name' => 'baz',
        ]);

        Vehicle::factory(5)->create([
            'is_published' => true,
            'is_new' => true,
            'make_id' => $make_for_new->id,
        ]);

        Vehicle::factory(3)->create([
            'is_published' => true,
            'is_new' => false,
            'make_id' => $make_for_used->id,
        ]);

        VehicleOffer::factory(2)->create([
            'published' => true,
            'make_id' => $make_for_offer->id,
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'is_new',
                        'value' => 'new',
                    ],
                ],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(7, $response->json('results.total'));
        $this->assertCount(2, $response->json('filters.make.results'));
    }

    public function testOfferTypeFilter()
    {
        Queue::fake();
        Config::set('filter.result_page_limit', '20');

        $this->seed(FilterSettingSeed::class);
        $this->seed(OfferFilterSettingSeed::class);
        $this->seed(SortingSettingSeed::class);

        $offer_type_1 = OfferType::factory()->create([
            'slug' => 'type_one',
            'name' => 'One',
        ]);

        $offer_type_2 = OfferType::factory()->create([
            'slug' => 'type_two',
            'name' => 'Two',
        ]);

        Vehicle::factory(7)->create([
            'is_published' => true
        ]);

        VehicleOffer::factory(3)->create([
            'published' => true,
            'type' => 'type_one',
        ]);

        VehicleOffer::factory(5)->create([
            'published' => true,
            'type' => 'type_two',
        ]);

        $this->assertCount(8, VehicleOffer::all());
        $this->assertCount(3, VehicleOffer::query()->where('type', '=', $offer_type_1->slug)->get());
        $this->assertCount(5, VehicleOffer::query()->where('type', '=', $offer_type_2->slug)->get());

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'));
        $response->assertStatus(200);

        $this->assertEquals(15, $response->json('results.total'));

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'stock_status',
                        'value' => 'available-to-order',
                    ],
                    [
                        'type' => 'offer_type',
                        'value' => $offer_type_1->slug,
                    ],
                ],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(3, $response->json('results.total'));

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'stock_status',
                        'value' => 'available-to-order',
                    ],
                    [
                        'type' => 'offer_type',
                        'value' => $offer_type_2->slug
                    ],
                ],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(5, $response->json('results.total'));

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'stock_status',
                        'value' => 'available-to-order',
                    ],
                    [
                        'type' => 'offer_type',
                        'value' => $offer_type_1->slug,
                    ],
                    [
                        'type' => 'offer_type',
                        'value' => $offer_type_2->slug,
                    ],
                ],
            ]);
        $response->assertStatus(200);

        $this->assertEquals(8, $response->json('results.total'));
    }

    public function testStockOfferOrderingEnabled()
    {
        Config::set('filter.result_page_limit', '20');

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'filter-results-order-by-vehicle-type',
            'type' => 'boolean',
            'value' => true,
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'New vehicle ordering by status',
            'config_key' => 'filter-results-status-order-values',
            'type' => 'text',
            'value' => 'offer:0,available now:1,in stock:1,coming soon:2,default:3',
        ]);

        $this->seed(SortingSettingSeed::class);

        // set some vehicles with a range of prices
        $vehicle_coming_soon_one = Vehicle::factory()->create([
            'is_published' => true,
            'price' => 10
        ]);

        $vehicle_coming_soon_two = Vehicle::factory()->create([
            'is_published' => true,
            'price' => 30
        ]);

        $vehicle_in_stock_one = Vehicle::factory()->create([
            'is_published' => true,
            'price' => 99
        ]);

        $vehicle_in_stock_two = Vehicle::factory()->create([
            'is_published' => true,
            'price' => 50
        ]);

        VehicleAttribute::query()
            ->firstOrCreate(
                [
                    'model' => 'vehicle',
                    'name' => 'stock_status',
                ],
                [
                    'slug' => 'stock_status',
                    'type' => 'text',
                    'validation' => [],
                    'data' => []
                ]
            );

        // set vehicle stock statuses to allow us to test our ordering
        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_in_stock_one,
            'slug' => 'stock_status',
            'value' => 'available now',
        ]);

        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_in_stock_two,
            'slug' => 'stock_status',
            'value' => 'in stock',
        ]);

        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_coming_soon_one,
            'slug' => 'stock_status',
            'value' => 'coming soon',
        ]);

        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_coming_soon_two,
            'slug' => 'stock_status',
            'value' => 'coming soon',
        ]);

        // set some vehicle offers
        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 20
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 40
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 60
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'is_new',
                        'value' => 'new',
                    ],
                    [
                        'type' => 'use_vehicle_type_sorting',
                        'value' => 'true',
                    ],
                ],
                'sort_by' => 'price-asc',
            ]);

        $response->assertStatus(200);

        $this->assertEquals(7, $response->json('results.total'));
        $this->assertCount(7, $response->json('results.data'));

        // assert that the vehicles are returned in the expected order
        $this->assertEquals(20, $response->json('results.data.0.price'));
        $this->assertEquals(40, $response->json('results.data.1.price'));
        $this->assertEquals(60, $response->json('results.data.2.price'));
        $this->assertEquals(50, $response->json('results.data.3.price'));
        $this->assertEquals(99, $response->json('results.data.4.price'));
        $this->assertEquals(10, $response->json('results.data.5.price'));
        $this->assertEquals(30, $response->json('results.data.6.price'));
    }

    public function testStockOfferOrderingDisabled()
    {
        Config::set('filter.result_page_limit', '20');

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'filter-results-order-by-vehicle-type',
            'type' => 'boolean',
            'value' => false,
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'New vehicle ordering by status',
            'config_key' => 'filter-results-status-order-values',
            'type' => 'text',
            'value' => 'offer:0,available now:1,coming soon:2,default:3',
        ]);

        $this->seed(SortingSettingSeed::class);

        // set some vehicles with a range of prices
        $vehicle_coming_soon_one = Vehicle::factory()->create([
            'is_published' => true,
            'price' => 10
        ]);

        $vehicle_coming_soon_two = Vehicle::factory()->create([
            'is_published' => true,
            'price' => 30
        ]);

        $vehicle_in_stock_one = Vehicle::factory()->create([
            'is_published' => true,
            'price' => 99
        ]);

        $vehicle_in_stock_two = Vehicle::factory()->create([
            'is_published' => true,
            'price' => 50
        ]);

        VehicleAttribute::query()
            ->firstOrCreate(
                [
                    'model' => 'vehicle',
                    'name' => 'stock_status',
                ],
                [
                    'slug' => 'stock_status',
                    'type' => 'text',
                    'validation' => [],
                    'data' => []
                ]
            );

        // set vehicle stock statuses to allow us to test our ordering
        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_in_stock_one,
            'slug' => 'stock_status',
            'value' => 'available now',
        ]);

        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_in_stock_two,
            'slug' => 'stock_status',
            'value' => 'available now',
        ]);

        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_coming_soon_one,
            'slug' => 'stock_status',
            'value' => 'coming soon',
        ]);

        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_coming_soon_two,
            'slug' => 'stock_status',
            'value' => 'coming soon',
        ]);

        // set some vehicle offers
        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 20
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 40
        ]);

        VehicleOffer::factory()->create([
            'published' => true,
            'price' => 60
        ]);

        $response = $this
            ->postJson(route('vehicles.stock-and-offers'), [
                'selections' => [
                    [
                        'type' => 'is_new',
                        'value' => 'new',
                    ],
                    [
                        'type' => 'use_vehicle_type_sorting',
                        'value' => 'true',
                    ],
                ],
                'sort_by' => 'price-asc',
            ]);

        $response->assertStatus(200);

        $this->assertEquals(7, $response->json('results.total'));
        $this->assertCount(7, $response->json('results.data'));

        // assert that the vehicles are returned in the expected order
        $this->assertEquals(10, $response->json('results.data.0.price'));
        $this->assertEquals(20, $response->json('results.data.1.price'));
        $this->assertEquals(30, $response->json('results.data.2.price'));
        $this->assertEquals(40, $response->json('results.data.3.price'));
        $this->assertEquals(50, $response->json('results.data.4.price'));
        $this->assertEquals(60, $response->json('results.data.5.price'));
        $this->assertEquals(99, $response->json('results.data.6.price'));
    }
}
