<?php

namespace Tests\Tenant\Services;

use App\Facades\Settings;
use App\Services\AutoTraderHub;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Mtc\MercuryDataModels\Media;
use Mtc\MercuryDataModels\MediaUse;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleFeature;
use Tests\TenantTestCase;

class AutoTraderHubTest extends TenantTestCase
{
    private AutoTraderHub $hub;

    #[\Override]
    protected function setUp(): void
    {
        parent::setUp();
        $this->hub = new AutoTraderHub();
    }

    public function testSetToken()
    {
        $instance = $this->hub->setToken('my-token');
        $this->assertInstanceOf(AutoTraderHub::class, $instance);

        $this->assertEquals('my-token', $this->invokeMethod($this->hub, 'getToken'));
    }

    public function testInitExportSuccess()
    {
        Http::fake([
            '*' => Http::response(['reference' => 'ref-123'], 200),
        ]);

        $this->hub->setToken('my-token');
        $reference = $this->hub->initExport();

        $this->assertEquals('ref-123', $reference);
    }

    public function testInitExportFails()
    {
        Http::fake([
            '*' => Http::response(['error' => 'fail'], 500),
        ]);

        Log::shouldReceive('error')->once();

        $this->hub->setToken('my-token');

        $this->expectException(\Exception::class);
        $this->hub->initExport();
    }

    public function testBulkExport()
    {
        $vehicles = collect([$this->mockVehicle()]);

        Http::fake([
            '*' => Http::response([], 200),
        ]);

        $this->hub->setToken('my-token');
        $result = $this->hub->bulkExport('ref-001', $vehicles);

        $this->assertTrue($result);
    }

    public function testExportSingleVehicle()
    {
        $vehicle = $this->mockVehicle();

        Http::fake([
            '*' => Http::response([], 200),
        ]);

        $this->hub->setToken('my-token');
        $result = $this->hub->export($vehicle);

        $this->assertTrue($result);
    }

    public function testCreateSiteSuccess()
    {
        Settings::shouldReceive('get')->with('auto-trader-advertiser-id')->andReturn('12345');
        Settings::shouldReceive('update')->with('auto-trader-hub-token', 'abc123')->once();

        config(['services.auto-trader-hub.api_key' => 'key']);
        config(['app.url' => 'https://tenant.example.com']);

        Http::fake([
            '*' => Http::response(['api_token' => 'abc123'], 200),
        ]);

        $response = $this->hub->createSite();
        $this->assertNull($response);
    }

    public function testMapVehicleIncludesAllFieldsWhenExportSettingIsUnconfigured()
    {
        $this->mockExportedFieldsSetting(null);

        $payload = $this->invokeMethod($this->hub, 'mapVehicle', [$this->mockVehicle()]);

        foreach (['make', 'model', 'trim', 'body_type', 'fuel_type', 'co2', 'features', 'images'] as $key) {
            $this->assertArrayHasKey($key, $payload, "Expected optional field '{$key}' to be exported");
        }
    }

    public function testMapVehicleFiltersOptionalFieldsToAllowlist()
    {
        $this->mockExportedFieldsSetting(['make', 'model']);

        $payload = $this->invokeMethod($this->hub, 'mapVehicle', [$this->mockVehicle()]);

        $this->assertArrayHasKey('make', $payload);
        $this->assertArrayHasKey('model', $payload);

        foreach (['trim', 'body_type', 'co2', 'features', 'images', 'video_url', 'vat_scheme'] as $key) {
            $this->assertArrayNotHasKey($key, $payload, "Field '{$key}' should be filtered out");
        }
    }

    public function testMapVehicleAlwaysRetainsMandatoryFieldsEvenIfNotInAllowlist()
    {
        $this->mockExportedFieldsSetting(['co2']);

        $payload = $this->invokeMethod($this->hub, 'mapVehicle', [$this->mockVehicle()]);

        $mandatory = [
            'id', 'advertiser_id', 'stock_id', 'condition', 'registration_number',
            'description', 'attention_grabber', 'published', 'publish_advert', 'publish_profile',
            'vin', 'derivative', 'odometer_mi', 'type', 'price',
            'manufacture_year', 'first_registration', 'at_disabled', 'lifecycleState', 'actions',
        ];

        foreach ($mandatory as $key) {
            $this->assertArrayHasKey($key, $payload, "Mandatory field '{$key}' must always be exported");
        }

        $this->assertArrayHasKey('co2', $payload);
        $this->assertArrayNotHasKey('make', $payload);
        $this->assertArrayNotHasKey('features', $payload);
    }

    private function mockExportedFieldsSetting($value): void
    {
        Settings::shouldReceive('get')
            ->andReturnUsing(fn(string $key, $default = null) =>
                $key === 'auto-trader-hub-exported-optional-fields' ? $value : $default);
    }

    public function testCreateSiteWithoutApiToken()
    {
        Settings::shouldReceive('get')->with('auto-trader-advertiser-id')->andReturn('12345');
        Settings::shouldReceive('update')->never();

        config(['services.auto-trader-hub.api_key' => 'key']);
        config(['app.url' => 'https://example.com']);

        Http::fake([
            '*' => Http::response(['data' => 'no-token'], 200),
        ]);

        // Asserts it doesn't break even when token is missing
        $response = $this->hub->createSite();
        $this->assertNull($response);
    }

    private function mockVehicle(): Vehicle
    {
        $vehicle = new Vehicle();
        $vehicle->id = 1;
        $vehicle->auto_trader_id = 'STK123';
        $vehicle->is_new = true;
        $vehicle->registration_number = 'AB12 CDE';
        $vehicle->description = 'Nice car';
        $vehicle->attention_grabber = 'Super quick!';
        $vehicle->is_published = true;
        $vehicle->vin = 'VIN123456';
        $vehicle->make = (object)['name' => 'Ford'];
        $vehicle->model = (object)['name' => 'Fiesta'];
        $vehicle->derivative = 'ST-Line';
        $vehicle->odometer_mi = 12345;
        $vehicle->type = 'car';
        $vehicle->trim = 'Luxury';
        $vehicle->bodyStyle = (object)['name' => 'Hatchback'];
        $vehicle->fuelType = (object)['name' => 'Petrol'];
        $vehicle->transmission = (object)['name' => 'Manual'];
        $vehicle->drivetrain = (object)['name' => 'FWD'];
        $vehicle->seats = 5;
        $vehicle->price = 10995;
        $vehicle->door_count = 5;
        $vehicle->co2 = 99;
        $vehicle->colour = 'Red';
        $vehicle->manufacture_year = 2020;
        $vehicle->first_registration_date = '2020-01-01';
        $vehicle->previous_owner_count = 1;
        $vehicle->engine_size_cc = 1498;
        $vehicle->main_video_url = 'https://video.com/demo';

        $feature1 = new VehicleFeature();
        $feature1->name = 'Air Conditioning';
        $feature1->type = 'comfort';

        $mediaMock = $this->createMock(Media::class);
        $mediaMock->id = 123;
        $mediaMock->auto_trader_id = 'AT456';
        $mediaMock->method('getOriginalUrlAttribute')->willReturn('https://example.com/image.jpg');

        $mediaUseMock = $this->createMock(MediaUse::class);
        $mediaUseMock->method('__get')->with('media')->willReturn($mediaMock);

        $vehicle->features = collect([$feature1]);
        $vehicle->mediaUses = collect([$mediaUseMock]);

        $vehicle->delership = (object)['data' => ['auto-trader-location-id' => 'dealer123']];

        return $vehicle;
    }

    private function invokeMethod(&$object, $methodName, array $parameters = [])
    {
        $reflection = new \ReflectionClass($object::class);
        $method = $reflection->getMethod($methodName);
        return $method->invokeArgs($object, $parameters);
    }
}
