<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\CatalogOffer;
use Mtc\MercuryDataModels\CatalogOfferRule;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleMake;
use Tests\FilterSettingSeed;
use Tests\TenantTestCase;

class CatalogOfferFilterTest extends TenantTestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();
        $this->seed(FilterSettingSeed::class);
        $this->withoutExceptionHandling();

        // Enable catalog offers injection
        Settings::make([
            'tab' => 'filter',
            'section' => 'filter',
            'group' => 'filter',
            'name' => 'Inject offers',
            'config_key' => 'filter-inject-offers-into-used-car-filter',
            'type' => 'boolean',
            'value' => true,
        ]);
    }

    public function testCatalogOfferWithNoRulesIsIncluded()
    {
        Queue::fake();
        Vehicle::factory(5)->create(['is_published' => true]);
        $offer = CatalogOffer::factory()->create(['active' => true]);

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

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

        $catalogOfferInResults = collect($response->json('results.data'))
            ->firstWhere('type', 'catalog-offer');
        $this->assertNotNull($catalogOfferInResults);
        $this->assertEquals($offer->id, $catalogOfferInResults['id']);
    }

    public function testCatalogOfferWithMatchingRulesIsIncluded()
    {
        Queue::fake();
        $make = VehicleMake::factory()->create();
        Vehicle::factory(5)->create([
            'is_published' => true,
            'make_id' => $make->id,
        ]);

        $offer = CatalogOffer::factory()->create(['active' => true]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => $make->id,
        ]);

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

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

        $catalogOfferInResults = collect($response->json('results.data'))
            ->firstWhere('type', 'catalog-offer');
        $this->assertNotNull($catalogOfferInResults);
    }

    public function testCatalogOfferWithNonMatchingRulesIsExcluded()
    {
        Queue::fake();
        $make1 = VehicleMake::factory()->create();
        $make2 = VehicleMake::factory()->create();

        // All vehicles have make1
        Vehicle::factory(5)->create([
            'is_published' => true,
            'make_id' => $make1->id,
        ]);

        // Offer requires make2 which no vehicles have
        $offer = CatalogOffer::factory()->create(['active' => true]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => $make2->id,
        ]);

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

        $response->assertStatus(200);
        // Only 5 vehicles, no catalog offer
        $this->assertEquals(5, $response->json('results.total'));

        $catalogOfferInResults = collect($response->json('results.data'))
            ->firstWhere('type', 'catalog-offer');
        $this->assertNull($catalogOfferInResults);
    }

    public function testCatalogOfferWithPriceRulesIsRespected()
    {
        Queue::fake();
        Vehicle::factory(3)->create([
            'is_published' => true,
            'price' => 15000,
        ]);
        Vehicle::factory(2)->create([
            'is_published' => true,
            'price' => 5000,
        ]);

        // Offer only for vehicles over 10000
        $offer = CatalogOffer::factory()->create(['active' => true]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'price',
            'condition' => '>',
            'value' => '10000',
        ]);

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

        $response->assertStatus(200);
        // 5 vehicles + 1 catalog offer (matches the 3 vehicles with price > 10000)
        $this->assertEquals(6, $response->json('results.total'));
    }

    public function testCatalogOfferWithMultipleRulesRequiresAllToMatch()
    {
        Queue::fake();
        $make = VehicleMake::factory()->create();

        // Vehicle matches both conditions
        Vehicle::factory(2)->create([
            'is_published' => true,
            'make_id' => $make->id,
            'price' => 15000,
        ]);

        // Vehicle matches only make condition
        Vehicle::factory(2)->create([
            'is_published' => true,
            'make_id' => $make->id,
            'price' => 5000,
        ]);

        // Offer requires make_id AND price > 10000
        $offer = CatalogOffer::factory()->create(['active' => true]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => $make->id,
        ]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'price',
            'condition' => '>',
            'value' => '10000',
        ]);

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

        $response->assertStatus(200);
        // 4 vehicles + 1 catalog offer
        $this->assertEquals(5, $response->json('results.total'));
    }

    public function testCatalogOfferExcludedWhenMultipleRulesNotAllMatch()
    {
        Queue::fake();
        $make1 = VehicleMake::factory()->create();
        $make2 = VehicleMake::factory()->create();

        // Vehicles have make1 with high price
        Vehicle::factory(3)->create([
            'is_published' => true,
            'make_id' => $make1->id,
            'price' => 15000,
        ]);

        // Offer requires make2 AND high price - make2 doesn't exist
        $offer = CatalogOffer::factory()->create(['active' => true]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => $make2->id,
        ]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'price',
            'condition' => '>',
            'value' => '10000',
        ]);

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

        $response->assertStatus(200);
        // Only 3 vehicles, no catalog offer
        $this->assertEquals(3, $response->json('results.total'));
    }

    public function testCatalogOfferRespectsFilteredResults()
    {
        Queue::fake();
        $make1 = VehicleMake::factory()->create();
        $make2 = VehicleMake::factory()->create();

        // Vehicles with make1
        Vehicle::factory(3)->create([
            'is_published' => true,
            'make_id' => $make1->id,
        ]);

        // Vehicles with make2
        Vehicle::factory(3)->create([
            'is_published' => true,
            'make_id' => $make2->id,
        ]);

        // Offer matches make1
        $offer = CatalogOffer::factory()->create(['active' => true]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => $make1->id,
        ]);

        // Filter for make2 - catalog offer should not appear since it targets make1
        $response = $this
            ->postJson(route('vehicles.index'), [
                'selections' => [
                    [
                        'type' => 'make',
                        'value' => $make2->slug,
                    ],
                ]
            ]);

        $response->assertStatus(200);
        // Only 3 vehicles (make2), no catalog offer since it requires make1
        $this->assertEquals(3, $response->json('results.total'));

        $catalogOfferInResults = collect($response->json('results.data'))
            ->firstWhere('type', 'catalog-offer');
        $this->assertNull($catalogOfferInResults);
    }

    public function testCatalogOfferAppearsWhenFilterMatchesOfferRules()
    {
        Queue::fake();
        $make = VehicleMake::factory()->create();

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

        // Some other vehicles
        Vehicle::factory(3)->create([
            'is_published' => true,
        ]);

        // Offer matches the make
        $offer = CatalogOffer::factory()->create(['active' => true]);
        CatalogOfferRule::query()->create([
            'catalog_offer_id' => $offer->id,
            'field' => 'make_id',
            'condition' => '=',
            'value' => $make->id,
        ]);

        // Filter for the same make - catalog offer should appear
        $response = $this
            ->postJson(route('vehicles.index'), [
                'selections' => [
                    [
                        'type' => 'make',
                        'value' => $make->slug,
                    ],
                ]
            ]);

        $response->assertStatus(200);
        // 5 vehicles + 1 catalog offer
        $this->assertEquals(6, $response->json('results.total'));

        $catalogOfferInResults = collect($response->json('results.data'))
            ->firstWhere('type', 'catalog-offer');
        $this->assertNotNull($catalogOfferInResults);
    }

    public function testInactiveCatalogOfferIsNotIncluded()
    {
        Queue::fake();
        Vehicle::factory(5)->create(['is_published' => true]);
        CatalogOffer::factory()->create(['active' => false]);

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

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

    public function testCatalogOffersDisabledSetting()
    {
        Queue::fake();
        // Disable catalog offers
        Settings::update('filter-inject-offers-into-used-car-filter', false);

        Vehicle::factory(5)->create(['is_published' => true]);
        CatalogOffer::factory()->create(['active' => true]);

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

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

        $catalogOfferInResults = collect($response->json('results.data'))
            ->firstWhere('type', 'catalog-offer');
        $this->assertNull($catalogOfferInResults);
    }
}
