<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Observers\VehicleObserver;
use Mtc\MercuryDataModels\BodyStyleType;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Tests\TenantTestCase;

class SearchContentTest extends TenantTestCase
{
    private VehicleObserver $observer;

    protected function setUp(): void
    {
        parent::setUp();
        $this->observer = app(VehicleObserver::class);
    }

    public function testSearchContentIncludesAttributeValuesWhenEnabled(): void
    {
        $vehicle = $this->createVehicleWithStockNumber('STK12345');

        Settings::update('search-include-vehicle-attributes', true);
        Settings::update('search-vehicle-attribute-slugs', ['stock-number']);

        $this->observer->setSearchableContent($vehicle, true);

        $this->assertStringContainsString('STK12345', $vehicle->search_content);
    }

    public function testSearchContentExcludesAttributesWhenSettingDisabled(): void
    {
        $vehicle = $this->createVehicleWithStockNumber('STK99999');

        Settings::update('search-include-vehicle-attributes', false);
        Settings::update('search-vehicle-attribute-slugs', ['stock-number']);

        $this->observer->setSearchableContent($vehicle, true);

        $this->assertStringNotContainsString('STK99999', $vehicle->search_content);
    }

    public function testSearchContentExcludesAttributesWhenNoSlugsSelected(): void
    {
        $vehicle = $this->createVehicleWithStockNumber('STK77777');

        Settings::update('search-include-vehicle-attributes', true);
        Settings::update('search-vehicle-attribute-slugs', []);

        $this->observer->setSearchableContent($vehicle, true);

        $this->assertStringNotContainsString('STK77777', $vehicle->search_content);
    }

    public function testSearchContentIncludesMultipleAttributes(): void
    {
        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'AB12CDE',
        ]);

        $stockAttr = VehicleAttribute::query()->firstOrCreate(
            ['model' => 'vehicle', 'name' => 'Stock Number'],
            ['slug' => 'stock-number', 'type' => 'text', 'validation' => [], 'data' => []]
        );

        $refAttr = VehicleAttribute::query()->firstOrCreate(
            ['model' => 'vehicle', 'name' => 'Dealer Ref'],
            ['slug' => 'dealer-ref', 'type' => 'text', 'validation' => [], 'data' => []]
        );

        VehicleAttributeValue::create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'attribute_id' => $stockAttr->id,
            'slug' => 'stock-number',
            'type' => 'text',
            'value_text' => 'STK-MULTI',
        ]);

        VehicleAttributeValue::create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'attribute_id' => $refAttr->id,
            'slug' => 'dealer-ref',
            'type' => 'text',
            'value_text' => 'REF-ABC',
        ]);

        $vehicle->load('attributeValues');

        Settings::update('search-include-vehicle-attributes', true);
        Settings::update('search-vehicle-attribute-slugs', ['stock-number', 'dealer-ref']);

        $this->observer->setSearchableContent($vehicle, true);

        $this->assertStringContainsString('STK-MULTI', $vehicle->search_content);
        $this->assertStringContainsString('REF-ABC', $vehicle->search_content);
    }

    public function testSearchContentOnlyIncludesSelectedSlugs(): void
    {
        $vehicle = Vehicle::factory()->create();

        $stockAttr = VehicleAttribute::query()->firstOrCreate(
            ['model' => 'vehicle', 'name' => 'Stock Number'],
            ['slug' => 'stock-number', 'type' => 'text', 'validation' => [], 'data' => []]
        );

        $otherAttr = VehicleAttribute::query()->firstOrCreate(
            ['model' => 'vehicle', 'name' => 'Internal Code'],
            ['slug' => 'internal-code', 'type' => 'text', 'validation' => [], 'data' => []]
        );

        VehicleAttributeValue::create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'attribute_id' => $stockAttr->id,
            'slug' => 'stock-number',
            'type' => 'text',
            'value_text' => 'SELECTED-VAL',
        ]);

        VehicleAttributeValue::create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'attribute_id' => $otherAttr->id,
            'slug' => 'internal-code',
            'type' => 'text',
            'value_text' => 'UNSELECTED-VAL',
        ]);

        $vehicle->load('attributeValues');

        Settings::update('search-include-vehicle-attributes', true);
        Settings::update('search-vehicle-attribute-slugs', ['stock-number']);

        $this->observer->setSearchableContent($vehicle, true);

        $this->assertStringContainsString('SELECTED-VAL', $vehicle->search_content);
        $this->assertStringNotContainsString('UNSELECTED-VAL', $vehicle->search_content);
    }

    public function testExistingSearchContentStillPresent(): void
    {
        $make = VehicleMake::factory()->create(['name' => 'BMW']);
        $model = VehicleModel::factory()->create(['name' => 'X5']);

        $vehicle = Vehicle::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'registration_number' => 'XY67ZZZ',
            'vin' => 'WBAPH5C55BA123456',
        ]);

        $vehicle->load('make', 'model');

        $stockAttr = VehicleAttribute::query()->firstOrCreate(
            ['model' => 'vehicle', 'name' => 'Stock Number'],
            ['slug' => 'stock-number', 'type' => 'text', 'validation' => [], 'data' => []]
        );

        VehicleAttributeValue::create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'attribute_id' => $stockAttr->id,
            'slug' => 'stock-number',
            'type' => 'text',
            'value_text' => 'STK-REGRESS',
        ]);

        $vehicle->load('attributeValues');

        Settings::update('search-include-vehicle-attributes', true);
        Settings::update('search-vehicle-attribute-slugs', ['stock-number']);

        $this->observer->setSearchableContent($vehicle, true);

        $this->assertStringContainsString('STK-REGRESS', $vehicle->search_content);
        $this->assertStringContainsString('XY67ZZZ', $vehicle->search_content);
        $this->assertStringContainsString('WBAPH5C55BA123456', $vehicle->search_content);
    }

    public function testSearchContentIncludesUuidAndRegistrationNumber(): void
    {
        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'AB12CDE',
        ]);

        $vehicle->load('make', 'model');

        $this->observer->setSearchableContent($vehicle, true);

        $this->assertStringContainsString($vehicle->uuid, $vehicle->search_content);
        $this->assertStringContainsString('AB12CDE', $vehicle->search_content);
    }

    public function testSearchContentIncludesStemmedVrmWhenDifferentFromRaw(): void
    {
        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'LL17 SNY',
            'vrm_condensed' => 'LL17SNY',
        ]);

        $vehicle->load('make', 'model');

        $this->observer->setSearchableContent($vehicle, true);

        // Raw vrm_condensed should be present
        $this->assertStringContainsString('LL17SNY', $vehicle->search_content);
        // Stemmed version (ll17sni) should also be present because the stemmer
        // changes Y to I, and the search query will use the stemmed version
        $this->assertStringContainsString('ll17sni', $vehicle->search_content);
    }

    public function testSearchContentDoesNotDuplicateVrmWhenStemmedMatchesRaw(): void
    {
        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'LC25 OKH',
            'vrm_condensed' => 'LC25OKH',
        ]);

        $vehicle->load('make', 'model');

        $this->observer->setSearchableContent($vehicle, true);

        // Raw vrm_condensed should be present
        $this->assertStringContainsString('LC25OKH', $vehicle->search_content);
        // Stemmed version is the same as raw (lc25okh), so it should only appear once
        $occurrences = substr_count(strtolower($vehicle->search_content), 'lc25okh');
        $this->assertEquals(1, $occurrences);
    }

    private function createVehicleWithStockNumber(string $stockNumber): Vehicle
    {
        $vehicle = Vehicle::factory()->create();

        $attribute = VehicleAttribute::query()->firstOrCreate(
            ['model' => 'vehicle', 'name' => 'Stock Number'],
            ['slug' => 'stock-number', 'type' => 'text', 'validation' => [], 'data' => []]
        );

        VehicleAttributeValue::create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'attribute_id' => $attribute->id,
            'slug' => 'stock-number',
            'type' => 'text',
            'value_text' => $stockNumber,
        ]);

        $vehicle->load('attributeValues');

        return $vehicle;
    }
}
