<?php

namespace Tests\Tenant;

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

class VehicleOfferFilterTest extends TenantTestCase
{
    #[\Override]
    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();
        $this->seed(FilterSettingSeed::class);
        $this->withoutExceptionHandling();
    }

    public function testFeatureOffNoInjection(): void
    {
        Queue::fake();
        Vehicle::factory(5)->create(['is_published' => true]);
        VehicleOffer::factory()->create(['published' => true]);

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

        $response->assertStatus(200);
        $vehicleOffer = collect($response->json('results.data'))->firstWhere('type', 'vehicle-offer');
        $this->assertNull($vehicleOffer);
    }

    public function testFeatureOnButStockTypeNotMatchingDoesNotInject(): void
    {
        Queue::fake();
        $this->enableVehicleOffersFeature(stockType: 'new', maxPerPage: 2);

        // SRP context is used (is_new=0)
        Vehicle::factory(5)->create(['is_published' => true, 'is_new' => false]);
        VehicleOffer::factory()->create(['published' => true]);

        $response = $this->postJson(route('vehicles.index'), [
            'selections' => [
                ['type' => 'is_new', 'value' => '0'],
            ],
        ]);

        $response->assertStatus(200);
        $vehicleOffer = collect($response->json('results.data'))->firstWhere('type', 'vehicle-offer');
        $this->assertNull($vehicleOffer);
    }

    public function testFeatureOnStockTypeBothInjectsOffer(): void
    {
        Queue::fake();
        $this->enableVehicleOffersFeature(stockType: 'both', maxPerPage: 2);

        Vehicle::factory(10)->create(['is_published' => true]);
        $offer = VehicleOffer::factory()->create(['published' => true]);

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

        $response->assertStatus(200);
        $data = $response->json('results.data');

        $vehicleOffer = collect($data)->firstWhere('type', 'vehicle-offer');
        $this->assertNotNull($vehicleOffer);
        $this->assertEquals($offer->id, $vehicleOffer['id']);

        // Never at position 0
        $this->assertNotEquals('vehicle-offer', $data[0]['type']);
    }

    public function testMakeFilterRespectedOnVehicleOffer(): void
    {
        Queue::fake();
        $this->enableVehicleOffersFeature(stockType: 'both', maxPerPage: 5);

        $ford = VehicleMake::factory()->create();
        $other = VehicleMake::factory()->create();

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

        VehicleOffer::factory()->create(['published' => true, 'make_id' => $ford->id, 'name' => 'matching']);
        VehicleOffer::factory()->create(['published' => true, 'make_id' => $other->id, 'name' => 'other']);

        $response = $this->postJson(route('vehicles.index'), [
            'selections' => [
                ['type' => 'make', 'value' => $ford->slug],
            ],
        ]);

        $response->assertStatus(200);
        $offers = collect($response->json('results.data'))->where('type', 'vehicle-offer')->values();
        $this->assertCount(1, $offers);
        $this->assertEquals('matching', $offers->first()['name']);
    }

    public function testWeightedOffersOrderedByWeightOnPageOne(): void
    {
        Queue::fake();
        $this->enableVehicleOffersFeature(stockType: 'both', maxPerPage: 5, maxWeighted: 2);

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

        $low = VehicleOffer::factory()->create(['published' => true, 'weight' => 1, 'name' => 'low']);
        $high = VehicleOffer::factory()->create(['published' => true, 'weight' => 5, 'name' => 'high']);
        $zero = VehicleOffer::factory()->create(['published' => true, 'weight' => 0, 'name' => 'zero']);

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

        $response->assertStatus(200);
        $offers = collect($response->json('results.data'))->where('type', 'vehicle-offer')->values();

        $this->assertCount(2, $offers);
        $names = $offers->pluck('name')->toArray();
        $this->assertContains('low', $names);
        $this->assertContains('high', $names);
        $this->assertNotContains('zero', $names);
    }

    public function testNoAdjacencyWithOtherInjectedOffers(): void
    {
        Queue::fake();
        $this->enableVehicleOffersFeature(stockType: 'both', maxPerPage: 2);

        Vehicle::factory(20)->create(['is_published' => true]);
        VehicleOffer::factory(2)->create(['published' => true]);

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

        $response->assertStatus(200);
        $data = $response->json('results.data');

        // Find positions of all vehicle-offer items
        $positions = collect($data)
            ->keys()
            ->filter(fn ($key) => $data[$key]['type'] === 'vehicle-offer')
            ->values()
            ->toArray();

        $this->assertCount(2, $positions);
        $this->assertNotContains(0, $positions);

        // No two offers adjacent
        $this->assertGreaterThan(1, abs($positions[0] - $positions[1]));
    }

    public function testPageTwoShowsRandomOffer(): void
    {
        Queue::fake();
        $this->enableVehicleOffersFeature(stockType: 'both', maxPerPage: 3);

        Vehicle::factory(30)->create(['is_published' => true]);
        VehicleOffer::factory(3)->create(['published' => true]);

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

        $response->assertStatus(200);
        $offers = collect($response->json('results.data'))->where('type', 'vehicle-offer')->values();

        // Page 2+ shows only 1 random offer regardless of max-per-page
        $this->assertCount(1, $offers);
    }

    private function enableVehicleOffersFeature(string $stockType, int $maxPerPage, int $maxWeighted = 0): void
    {
        Settings::make([
            'tab' => 'Automotive',
            'section' => 'SRP',
            'group' => 'Vehicle Offers',
            'name' => 'Enabled',
            'config_key' => 'automotive-srp-vehicle-offers-enabled',
            'type' => 'boolean',
            'value' => true,
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'SRP',
            'group' => 'Vehicle Offers',
            'name' => 'Stock type',
            'config_key' => 'automotive-srp-vehicle-offers-stock-type',
            'type' => 'string',
            'value' => $stockType,
        ]);

        Settings::make([
            'tab' => 'Automotive',
            'section' => 'SRP',
            'group' => 'Vehicle Offers',
            'name' => 'Max per page',
            'config_key' => 'automotive-srp-vehicle-offers-max-per-page',
            'type' => 'integer',
            'value' => $maxPerPage,
        ]);

        if ($maxWeighted > 0) {
            Settings::make([
                'tab' => 'Automotive',
                'section' => 'SRP',
                'group' => 'Vehicle Offers',
                'name' => 'Max weighted',
                'config_key' => 'vehicle-offer-max-weighted',
                'type' => 'integer',
                'value' => $maxWeighted,
            ]);
        }
    }
}
