<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Jobs\ImportImagesFromUrlList;
use App\Modules\Stock\Skoda;
use App\VehicleType;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleOffer;
use Tests\TenantTestCase;

class SkodaTest extends TenantTestCase
{
    private function makeSetting(string $key, mixed $value, string $type = 'boolean'): void
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'foo',
            'group' => 'foo',
            'name' => 'foo',
            'config_key' => $key,
            'value' => $value,
            'type' => $type,
        ]);
    }

    private function setupDefaults(): void
    {
        $this->makeSetting('stock-skoda-enabled', true);
        $this->makeSetting('stock-skoda-sync-type', 'vehicles', 'string');
        $this->makeSetting('stock-skoda-sync-images', false);
        $this->makeSetting('stock-skoda-delivery-price', 0, 'string');
    }

    private function offerPayload(array $overrides = []): array
    {
        return array_merge([
            'id' => 'SKD-001',
            'vin' => 'TMBAG7NE1N0123456',
            'type' => 'N',
            'model' => 'octavia',
            'modelBody' => 'Hatchback',
            'title' => 'SE L 1.5 TSI',
            'modelYear' => '2024',
            'isReserved' => false,
            'salePrice' => ['value' => 28000],
            'colors' => ['exterior' => ['text' => 'Quartz Grey']],
            'technicalData' => [
                'transmissionName' => 'Manual 6-speed',
                'gear' => 'Manual',
                'fuel' => 'Petrol',
                'drive' => 'Front',
                'capacity' => ['value' => '1,498'],
            ],
            'dealer' => ['id' => 'DEALER-1'],
            'mileage' => ['value' => '0', 'unit' => 'km'],
            'images' => [],
            'equipmentGroups' => [],
        ], $overrides);
    }

    public function testEnabled()
    {
        $this->makeSetting('stock-skoda-enabled', false);
        $this->assertFalse((new Skoda())->enabled());

        Settings::update('stock-skoda-enabled', true);
        $this->assertTrue((new Skoda())->enabled());
    }

    public function testName()
    {
        $this->assertEquals('Skoda', (new Skoda())->name());
    }

    public function testDealershipAdditionalDataFields()
    {
        $fields = (new Skoda())->dealershipAdditionalDataFields();
        $this->assertArrayHasKey('skoda-dealer-id', $fields);
    }

    public function testImportVehiclesCreatesRecords()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');

        $this->fakeSkodaApi([
            $this->offerPayload(),
            $this->offerPayload([
                'id' => 'SKD-002',
                'vin' => 'TMBAG7NE1N0654321',
                'model' => 'superb',
                'title' => 'Sportline 2.0 TDI',
                'salePrice' => ['value' => 35000],
            ]),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        $this->assertEquals(2, Vehicle::query()->count());

        $vehicle = Vehicle::query()->where('uuid', 'SKD-001')->first();
        $this->assertNotNull($vehicle);
        $this->assertEquals('skoda', $vehicle->stock_provider);
        $this->assertEquals('TMBAG7NE1N0123456', $vehicle->vin);
        $this->assertEquals(28000, (int) $vehicle->price);
        $this->assertEquals(VehicleType::CAR->value, $vehicle->type);
        $this->assertTrue((bool) $vehicle->is_new);
    }

    public function testDeliveryPriceAddedToVehiclePrice()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');
        Settings::update('stock-skoda-delivery-price', 750);

        $this->fakeSkodaApi([
            $this->offerPayload(['salePrice' => ['value' => 28000]]),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        $this->assertEquals(28750, (int) Vehicle::query()->first()->price);
    }

    public function testOnlyNewVehiclesImported()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');

        // The fetchOffers method filters by type == 'N'
        // Used vehicles (type != 'N') are filtered out in fetchOffers
        $this->fakeSkodaApi([
            $this->offerPayload(['type' => 'N']),
            $this->offerPayload(['id' => 'SKD-002', 'type' => 'U', 'vin' => 'TMBAG7NE1N9999999']),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        // Only the 'N' type vehicle should be imported
        $this->assertEquals(1, Vehicle::query()->count());
        $this->assertTrue(Vehicle::query()->where('uuid', 'SKD-001')->exists());
    }

    public function testRemoveOldVehiclesNotInFeed()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');

        Vehicle::factory()->create([
            'stock_provider' => 'skoda',
            'uuid' => 'OLD-SKD',
        ]);

        $this->fakeSkodaApi([
            $this->offerPayload(),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        $this->assertFalse(Vehicle::query()->where('uuid', 'OLD-SKD')->exists());
        $this->assertTrue(Vehicle::query()->where('uuid', 'SKD-001')->exists());
    }

    public function testImageSyncDispatchedWhenEnabled()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');
        Settings::update('stock-skoda-sync-images', true);

        $this->fakeSkodaApi([
            $this->offerPayload([
                'images' => [
                    'https://images.skoda.com/img1.jpg',
                    'https://images.skoda.com/img2.jpg',
                ],
            ]),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        Queue::assertPushed(ImportImagesFromUrlList::class);
    }

    public function testImageSyncNotDispatchedWhenDisabled()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');
        Settings::update('stock-skoda-sync-images', false);

        $this->fakeSkodaApi([
            $this->offerPayload([
                'images' => ['https://images.skoda.com/img1.jpg'],
            ]),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        Queue::assertNotPushed(ImportImagesFromUrlList::class);
    }

    public function testVehiclesWithoutVinSkipDetailFetch()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');

        $endpoint = config('services.skoda.endpoint') ?: 'https://api.skoda.com/';

        Http::fake([
            $endpoint . 'search?*' => Http::sequence()
                ->push([
                    'results' => [
                        'cars' => [
                            $this->offerPayload(),
                            $this->offerPayload(['id' => 'SKD-002', 'vin' => '']),
                        ],
                    ],
                ])
                ->push([
                    'results' => [
                        'cars' => [],
                    ],
                ]),
            $endpoint . 'getCarDetail?*' => Http::response([]),
            '*' => Http::response([], 400),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        // Only 1 detail fetch (for SKD-001 with VIN), not 2
        // search page1 + search page2 (empty) + 1 detail fetch = 3 requests
        Http::assertSentCount(3);
    }

    public function testMileageConvertedFromKm()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');

        $this->fakeSkodaApi([
            $this->offerPayload([
                'mileage' => ['value' => '16,000', 'unit' => 'km'],
            ]),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        $vehicle = Vehicle::query()->first();
        // 16000 km ≈ 9942 miles
        $this->assertNotNull($vehicle->odometer_mi);
        $this->assertLessThan(16000, (int) $vehicle->odometer_mi);
    }

    public function testEquipmentSynced()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');

        $this->fakeSkodaApi([
            $this->offerPayload([
                'equipmentGroups' => [
                    [
                        'name' => 'Safety',
                        'items' => [
                            ['key' => 'EQ1', 'keytoolCode' => 'SAF01', 'text' => 'ABS brakes'],
                            ['key' => 'EQ2', 'keytoolCode' => 'SAF02', 'text' => 'Lane assist'],
                        ],
                    ],
                ],
            ]),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        $vehicle = Vehicle::query()->first();
        $this->assertEquals(2, $vehicle->equipment()->count());
        $this->assertTrue($vehicle->equipment()->where('description', 'ABS brakes')->exists());
        $this->assertTrue($vehicle->equipment()->where('description', 'Lane assist')->exists());
    }

    public function testPaginatedFetch()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');

        $endpoint = config('services.skoda.endpoint') ?: 'https://api.skoda.com/';

        Http::fake([
            $endpoint . 'search?Dealers=DEALER-1&PageNo=1' => Http::response([
                'results' => [
                    'cars' => [
                        $this->offerPayload(),
                    ],
                ],
            ]),
            $endpoint . 'search?Dealers=DEALER-1&PageNo=2' => Http::response([
                'results' => [
                    'cars' => [],
                ],
            ]),
            $endpoint . 'getCarDetail?*' => Http::response([
                'detailedField' => 'value',
            ]),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        // Should have fetched page 1, page 2 (empty), and detail for 1 vehicle
        Http::assertSentCount(3);
    }

    public function testUpdatesExistingVehicle()
    {
        Queue::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'vehicles');

        Vehicle::factory()->create([
            'stock_provider' => 'skoda',
            'uuid' => 'SKD-001',
            'price' => 25000,
        ]);

        $this->fakeSkodaApi([
            $this->offerPayload(['salePrice' => ['value' => 28000]]),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        $this->assertEquals(1, Vehicle::query()->count());
    }

    public function testSyncTypeBothImportsVehiclesAndOffers()
    {
        Queue::fake();
        Event::fake();
        $this->setupDefaults();
        Settings::update('stock-skoda-sync-type', 'both');

        $this->fakeSkodaApi([
            $this->offerPayload(),
        ]);

        Dealership::factory()->create(['data' => ['skoda-dealer-id' => 'DEALER-1']]);
        (new Skoda())->runScheduledImport();

        // Both vehicle and offer should be created
        $this->assertEquals(1, Vehicle::query()->count());
        $this->assertEquals(1, VehicleOffer::query()->count());
    }

    private function fakeSkodaApi(array $vehicles): void
    {
        $endpoint = config('services.skoda.endpoint') ?: 'https://api.skoda.com/';

        Http::fake([
            $endpoint . 'search?*' => Http::sequence()
                ->push([
                    'results' => [
                        'cars' => $vehicles,
                    ],
                ])
                ->push([
                    'results' => [
                        'cars' => [],
                    ],
                ]),
            $endpoint . 'getCarDetail?*' => Http::response([]),
            '*' => Http::response([], 400),
        ]);
    }
}
