<?php

namespace Tests\Tenant;

use App\Facades\Feature;
use App\Facades\Settings;
use App\Filter\FilterIndex;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\SearchFacet;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Tests\TenantTestCase;

class MakeSitemapQueryParamFiltersTest extends TenantTestCase
{
    private string $sitemapPath;

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

        Storage::fake('file-storage');

        // Enable both flags up-front. Re-calling Feature::setEnabled mid-test
        // can clobber rows created in setUp on the central test connection,
        // so we rely on the SearchFacet table being empty to keep the legacy
        // path active for the non-facet tests.
        Feature::setEnabled(tenant(), ['sitemap', 'search-facets']);

        $this->setSetting('seo-sitemap-include-srp', true);
        $this->setSetting('seo-sitemap-srp-type', 'fixed-path');
        $this->setSetting('seo-sitemap-srp-path', '/used-cars');
        $this->setSetting('automotive-vehicle-filters-colour', true);
        $this->setSetting('seo-sitemap-srp-query-param-filters', "colour\n", 'text');

        $this->sitemapPath = tenant('id') . '/sitemap.xml';
    }

    public function testQueryParamUrlsAreEmittedForDiscreteFilterSlugsWithActiveVehicles(): void
    {
        $ford = VehicleMake::factory()->create(['name' => 'Ford', 'slug' => 'ford']);

        $this->indexFilter('colour', 1, 'red', 'Red');
        $this->indexFilter('colour', 2, 'blue', 'Blue');

        $this->insertVehicle(['make_id' => $ford->id, 'colour' => 'Red']);

        $this->artisan('make:sitemap')->assertExitCode(0);

        $xml = $this->getSitemapContent();

        $this->assertStringContainsString('/used-cars', $xml);
        $this->assertStringContainsString('/used-cars?colour=red', $xml);
        $this->assertStringNotContainsString('colour=blue', $xml);
    }

    public function testQueryParamUrlsAreEmittedAtMakeAndModelLevels(): void
    {
        $this->setSetting('seo-sitemap-include-srp-makes', true);
        $this->setSetting('seo-sitemap-include-srp-models', true);

        $ford = VehicleMake::factory()->create(['name' => 'Ford', 'slug' => 'ford']);
        $focus = VehicleModel::factory()->create([
            'name' => 'Focus',
            'slug' => 'focus',
            'make_id' => $ford->id,
        ]);

        $this->indexFilter('colour', 1, 'red', 'Red');

        $this->insertVehicle([
            'make_id' => $ford->id,
            'model_id' => $focus->id,
            'colour' => 'Red',
        ]);

        $this->artisan('make:sitemap')->assertExitCode(0);

        $xml = $this->getSitemapContent();

        $this->assertStringContainsString('/used-cars?colour=red', $xml);
        $this->assertStringContainsString('/used-cars/ford?colour=red', $xml);
        $this->assertStringContainsString('/used-cars/ford/focus?colour=red', $xml);
    }

    public function testQueryParamFilterIgnoredWhenSearchFacetsHasConfiguredFacets(): void
    {
        $this->setSetting('seo-sitemap-include-srp-facets', true);

        SearchFacet::create([
            'position' => 1,
            'filter_type' => 'make',
            'robots_index' => true,
            'robots_follow' => true,
        ]);

        $ford = VehicleMake::factory()->create(['name' => 'Ford', 'slug' => 'ford']);
        $this->indexFilter('make', $ford->id, 'ford', 'Ford');
        $this->indexFilter('colour', 1, 'red', 'Red');

        $this->insertVehicle(['make_id' => $ford->id, 'colour' => 'Red']);

        $this->artisan('make:sitemap')->assertExitCode(0);

        $xml = $this->getSitemapContent();

        // Faceted hierarchy is used; query params are not appended on top.
        $this->assertStringContainsString('/used-cars/ford', $xml);
        $this->assertStringNotContainsString('colour=red', $xml);
    }

    public function testInvalidFilterTypesInSettingAreIgnored(): void
    {
        // price_min is a range (MinMaxFilter); make is a hierarchy axis. Neither must fan out.
        $this->setSetting('automotive-vehicle-filters-price_min', true);
        $this->setSetting('seo-sitemap-srp-query-param-filters', "price_min\nmake\n", 'text');

        $ford = VehicleMake::factory()->create(['name' => 'Ford', 'slug' => 'ford']);
        $this->indexFilter('make', $ford->id, 'ford', 'Ford');
        $this->indexFilter('price_min', 5000, '5000', '£5,000');

        $this->insertVehicle(['make_id' => $ford->id, 'price' => 7500]);

        $this->artisan('make:sitemap')->assertExitCode(0);

        $xml = $this->getSitemapContent();

        $this->assertStringNotContainsString('price_min=', $xml);
        $this->assertStringNotContainsString('?make=ford', $xml);
    }

    public function testPaginationPreservesQueryParam(): void
    {
        $this->setSetting('seo-sitemap-include-pagination', true);
        $this->setSetting('filter-results-per-page', 1);

        $ford = VehicleMake::factory()->create(['name' => 'Ford', 'slug' => 'ford']);
        $this->indexFilter('colour', 1, 'red', 'Red');

        for ($i = 0; $i < 3; $i++) {
            $this->insertVehicle(['make_id' => $ford->id, 'colour' => 'Red']);
        }

        $this->artisan('make:sitemap')->assertExitCode(0);

        $xml = $this->getSitemapContent();

        $this->assertStringContainsString('/used-cars?colour=red', $xml);
        $this->assertStringContainsString('/used-cars?colour=red&amp;page=2', $xml);
        $this->assertStringContainsString('/used-cars?colour=red&amp;page=3', $xml);
    }

    /**
     * Insert a Vehicle row with raw SQL to bypass VehicleObserver's `creating`
     * hook (which writes a not-yet-migrated `order` column on this branch).
     */
    private function insertVehicle(array $attrs): void
    {
        DB::table('vehicles')->insert(array_merge([
            'uuid' => (string) Str::uuid(),
            'slug' => 'test-' . Str::random(6),
            'is_published' => 1,
            'is_sold' => 0,
            'is_demo' => 0,
            'is_reserved' => 0,
            'is_vat_applicable' => 1,
            'featured' => 0,
            'created_at' => now(),
            'updated_at' => now(),
        ], $attrs));
    }

    private function indexFilter(string $type, int $id, string $slug, string $name): void
    {
        FilterIndex::query()->create([
            'filter_type' => $type,
            'filter_id' => $id,
            'slug' => $slug,
            'name' => $name,
        ]);
    }

    private function setSetting(string $key, mixed $value, ?string $type = null): void
    {
        $resolvedType = $type ?? (is_bool($value) ? 'boolean' : 'string');

        if (Settings::exists($key)) {
            Settings::update($key, $value);
            return;
        }

        Settings::make([
            'tab' => 'Site',
            'section' => 'SEO',
            'group' => 'Sitemap',
            'name' => $key,
            'config_key' => $key,
            'type' => $resolvedType,
            'value' => $value,
        ]);
    }

    private function getSitemapContent(): string
    {
        Storage::disk('file-storage')->assertExists($this->sitemapPath);

        return Storage::disk('file-storage')->get($this->sitemapPath);
    }
}
