<?php

namespace Tests\Unit\Services;

use App\Facades\Settings;
use App\Services\AutoTrader;
use App\Services\AutoTraderAIApi;
use App\Services\AutoTraderApi;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;
use Mockery;
use Mtc\MercuryDataModels\Dealership;

class AutoTraderTest extends TenantTestCase
{
    private AutoTraderApi $api;
    private AutoTrader $service;
    private string $prefix;

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

        $this->api = Mockery::mock(AutoTraderApi::class);
        $this->ai_api = Mockery::mock(AutoTraderAIApi::class);
        $this->service = new AutoTrader($this->api, $this->ai_api);

        $this->prefix = 'https://api-sandbox.autotrader.co.uk';

        // just to be EXTRA careful that no outbound http call would be made
        Http::preventStrayRequests();
    }

    public function testCanGenerateDescriptionOnImportReturnsTrue()
    {
        Settings::shouldReceive('get')
            ->with('ai-content-auto-trader-generate-description-on-vehicle-import')
            ->once()
            ->andReturn(true);

        $this->assertTrue($this->service->canGenerateDescriptionOnImport());
    }

    public function testCanGenerateDescriptionOnImportReturnsFalse()
    {
        Settings::shouldReceive('get')->andReturn(false);
        $this->assertFalse($this->service->canGenerateDescriptionOnImport());
    }

    public function testGetStockWithBadDataReturnsEmptyArray()
    {
        $this->api->shouldReceive('get')
            ->once()
            ->withArgs(function ($url) {
                return str_starts_with($url, 'stock?');
            })
            ->andReturn(['invalid' => 'data']);

        $this->assertSame([], $this->service->getStock(123));
    }

    public function testGetStockReturnsEmptyArrayWhenTotalResultsIsMissing()
    {
        $this->api->shouldReceive('get')
            ->once()
            ->with('stock?advertiserId=123&pageSize=200&responseMetrics=true&vehicleMetrics=true')
            ->andReturn([
                // Simulate a response without the 'totalResults' key
                'results' => [],
            ]);

        $autoTrader = new AutoTrader($this->api, $this->ai_api);
        $result = $autoTrader->getStock(123);

        $this->assertEquals([], $result);
    }

    public function testGetStockWithPaginationMergesResults()
    {
        $this->api->shouldReceive('get')->once()->andReturn([
            'totalResults' => 600,
            'results' => [['id' => 1]],
        ]);

        $this->api->shouldReceive('get')->twice()->andReturn(
            ['results' => [['id' => 2]]],
            ['results' => [['id' => 3]]]
        );

        $results = $this->service->getStock(456);
        $this->assertCount(3, $results);
    }

    public function testGetDescriptionReturnsEmptyIfNoAutoTraderId()
    {
        $vehicle = new Vehicle(['auto_trader_id' => null]);
        $this->assertSame('', $this->service->getDescription($vehicle));
    }

    public function testGetDescriptionReturnsApiDescription()
    {
        $endpoint = $this->prefix . '/co-driver/stock/*';

        $description = fake()->text();
        Http::fake([
            $this->prefix . '/authenticate' => Http::response([
                'access_token' => 'fake-token',
                'expires_in' => 3600,
            ], 200),

            $endpoint => Http::response([
                'adverts' => [
                    'retailAdverts' => [
                        'description' => $description
                    ]
                ]
            ], 200),
        ]);

        $dealership = Dealership::factory()->create([
            'data' => ['auto-trader-location-id' => 100],
        ]);
        /** @var Vehicle $vehicle */
        $vehicle = Vehicle::factory()->create([
            'uuid' => 'abc123',
            'dealership_id' => $dealership->id,
            'auto_trader_id' => 'abc123'
        ]);

        $service = new AutoTrader(
            new AutoTraderApi([
                'api_key' => 'key',
                'api_secret' => 'secret',
                'use_live_api' => false,
            ]),
            new AutoTraderAIApi([
                'api_key' => 'key',
                'api_secret' => 'secret',
                'use_live_api' => false,
            ])
        );

        $response = $service->getDescription($vehicle);

        $this->assertSame($description, $response);
    }

    public function testGetVehicleAdvertiserIdReturnsLocationId()
    {
        $vehicle = new Vehicle(['auto_trader_id' => '1']);

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

        $reflectedMethod = (new \ReflectionClass(AutoTrader::class))->getMethod('getVehicleAdvertiserId');
        $reflectedMethod->setAccessible(true);

        $id = $reflectedMethod->invoke($this->service, $vehicle);
        $this->assertSame(100112, $id);
    }

    public function testGetVehicleAdvertiserIdFallsBackToSettings()
    {
        $vehicle = new Vehicle(['auto_trader_id' => '1']);
        $vehicle->dealership = (object)['data' => []];

        Settings::shouldReceive('get')->once()->with('auto-trader-advertiser-id')->andReturn(1001);

        $reflectedMethod = (new \ReflectionClass(AutoTrader::class))->getMethod('getVehicleAdvertiserId');
        $reflectedMethod->setAccessible(true);

        $id = $reflectedMethod->invoke($this->service, $vehicle);
        $this->assertSame(1001, $id);
    }

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

        Mockery::close();
    }
}
