<?php

namespace Tests\Tenant;

use App\Console\Commands\AutoTraderDataFetch;
use App\Facades\Settings;
use App\Jobs\FetchAutoTraderPerformanceData;
use Database\Seeders\Tenant\AutoTraderEnrichedDataSeeder;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;

class AutoTraderEnrichedDataFetchTest extends TenantTestCase
{
    private string $prefix;
    private string $prefixLive;

    #[\Override]
    protected function setUp(): void
    {
        parent::setUp();

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

        $this->seed(AutoTraderEnrichedDataSeeder::class);
        Settings::update('autotrader-advert-performance', true);
    }

    public function testSendsJob()
    {
        Queue::fake();
        $this->artisan(AutoTraderDataFetch::class)->assertExitCode(0);
        Queue::assertPushed(FetchAutoTraderPerformanceData::class);
    }

    public function testRunCommand()
    {
        /** @var Vehicle $vehicle */
        $vehicle = $this->createDealershipAndVehicle(uuid: "100");

        $this->mockHttpRequest();
        Queue::fake();

        $this->artisan(AutoTraderDataFetch::class)->assertExitCode(0);
        Queue::assertPushed(FetchAutoTraderPerformanceData::class);
    }


    public function testRunJob()
    {
        /** @var Vehicle $vehicle */
        $vehicle = $this->createDealershipAndVehicle(uuid: "100");

        $this->mockHttpRequest();

        new FetchAutoTraderPerformanceData()->handle();

        $atData = $vehicle->autoTraderData;

        $this->assertNotNull($atData);
        $this->assertEquals('GOOD', $atData->price_point);
        $this->assertEquals(5000, $atData->valuation);
        $this->assertEquals(123, $atData->search_results_7d);
        $this->assertEquals(5, $atData->ad_views);
        $this->assertEquals(23, $atData->ad_views_7d);
        $this->assertEquals('ABOVE AVERAGE', $atData->performance_rating);
        $this->assertEquals('HIGH', $atData->lead_count_rating);
    }

    /**
     * Ensures Autotrader service correctly uses the fallback stock ID when the vehicle is not found by UUID.
     */
    public function testJobUsesFallbackStockIdWhenVehicleNotFoundByUuid()
    {
        /** @var Vehicle $vehicle */
        $vehicle = $this->createDealershipAndVehicle(uuid: "abc123");

        $this->mockHttpRequest();

        new FetchAutoTraderPerformanceData()->handle();

        $atData = $vehicle->autoTraderData;

        $this->assertNotNull($atData);
        $this->assertEquals('GOOD', $atData->price_point);
        $this->assertEquals(5000, $atData->valuation);
        $this->assertEquals(123, $atData->search_results_7d);
        $this->assertEquals(5, $atData->ad_views);
        $this->assertEquals(23, $atData->ad_views_7d);
        $this->assertEquals('ABOVE AVERAGE', $atData->performance_rating);
        $this->assertEquals('HIGH', $atData->lead_count_rating);
    }

    public function testValuationAndPricePositionStoredCorrectly()
    {
        /** @var Vehicle $vehicle */
        $vehicle = $this->createDealershipAndVehicle(uuid: "100");

        $this->mockHttpRequest();

        new FetchAutoTraderPerformanceData()->handle();

        $atData = $vehicle->autoTraderData;

        $this->assertNotNull($atData);
        $this->assertEquals(5000, $atData->valuation);
        $this->assertEquals(89.61, $atData->price_position);
    }

    public function testStockRequestIncludesValuationsParam()
    {
        $this->createDealershipAndVehicle(uuid: "100");

        $this->mockHttpRequest();

        new FetchAutoTraderPerformanceData()->handle();

        $recorded = Http::recorded();
        $stockRequest = collect($recorded)
            ->first(fn ($pair) => str_contains((string) $pair[0]->url(), '/stock'));

        $this->assertNotNull($stockRequest);
        $this->assertStringContainsString('valuations=true', (string) $stockRequest[0]->url());
    }

    public function testBadResponse()
    {
        Dealership::factory()->create(['data' => ['auto-trader-location-id' => 100]]);

        /** @var Vehicle $vehicle */
        $vehicle = Vehicle::factory()->create(['uuid' => 100]);
        Http::fake([
            $this->prefix . '/stock*' => $this->badResponse(),
            '*' => Http::response(null, 400),
        ]);

        new FetchAutoTraderPerformanceData()->handle();
        $this->assertFalse($vehicle->autoTraderData()->exists());
    }


    private function stockResponse(): \GuzzleHttp\Promise\PromiseInterface
    {
        return Http::response([
            'results' => [
                [
                    'metadata' => [
                        'externalStockId' => 100,
                        'stockId' => 'abc123',
                    ],
                    'adverts' => [
                        'retailAdverts' => [
                            'priceIndicatorRating' => 'GOOD',
                        ]
                    ],
                    'vehicle' => [],
                    'valuations' => [
                        'marketAverage' => [
                            'retail' => [
                                'amountGBP' => 5000,
                            ]
                        ]
                    ],
                    'vehicleMetrics' => [
                        'local' => [
                            'retail' => [
                                'rating' => [
                                    'value' => 89.61,
                                ]
                            ]
                        ]
                    ],
                    'responseMetrics' => [
                        'yesterday' => [
                            'advertViews' => 5,
                        ],
                        'lastWeek' => [
                            'searchViews' => 123,
                            'advertViews' => 23,
                        ],
                        'performanceRating' => [
                            'rating' => 'ABOVE AVERAGE',
                        ],
                        'leadCountRating' => [
                            'rating' => 'HIGH',
                        ],
                    ]
                ],
            ],
            'totalResults' => 230
        ]);
    }

    private function badResponse(): \GuzzleHttp\Promise\PromiseInterface
    {
        return Http::response([
            'results' => [],
        ]);
    }

    public function testMetricsParamsAreKeptOnFollowUpPages()
    {
        $this->createDealershipAndVehicle(uuid: "100");

        // totalResults above the page size forces a second page request
        Http::fake([
            $this->prefix . '/stock*' => Http::response([
                'totalResults' => 201,
                'results' => [
                    [
                        'metadata' => ['externalStockId' => 100, 'stockId' => 'abc123'],
                        'adverts' => [],
                        'vehicle' => [],
                    ],
                ],
            ]),
            '*' => Http::response(null, 400),
        ]);

        new FetchAutoTraderPerformanceData()->handle();

        $stockRequests = collect(Http::recorded())
            ->filter(fn ($pair) => str_contains((string) $pair[0]->url(), '/stock'))
            ->values();

        $this->assertCount(2, $stockRequests);
        $secondPageUrl = (string) $stockRequests[1][0]->url();
        $this->assertStringContainsString('page=2', $secondPageUrl);
        $this->assertStringContainsString('responseMetrics=true', $secondPageUrl);
        $this->assertStringContainsString('vehicleMetrics=true', $secondPageUrl);
        $this->assertStringContainsString('valuations=true', $secondPageUrl);
    }

    private function mockHttpRequest(): void
    {
        Http::fake([
            $this->prefix . '/stock*' => $this->stockResponse(),
            $this->prefixLive . '/stock*' => $this->stockResponse(),
            '*' => Http::response(null, 400),
        ]);
    }

    private function createDealershipAndVehicle(string $uuid): Vehicle
    {
        $dealership = Dealership::factory()->create([
            'data' => ['auto-trader-location-id' => 100],
        ]);

        return Vehicle::factory()->create([
            'uuid' => $uuid,
            'dealership_id' => $dealership->id,
        ]);
    }
}
