<?php

namespace Tests\Tenant\Jobs;

use App\Events\AutoTraderIdAssignedToVehicle;
use App\Facades\Feature;
use App\Jobs\SendVehicleToAutotrader;
use App\Services\AutoTraderHub;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Http;
use Mtc\MercuryDataModels\ApiNotification;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;

class SendVehicleToAutotraderTest extends TenantTestCase
{
    #[\Override]
    protected function setUp(): void
    {
        parent::setUp();
        Event::fake([AutoTraderIdAssignedToVehicle::class]);
    }

    private function makeVehicle(array $overrides = []): Vehicle
    {
        $dealership = Dealership::factory()->create([
            'data' => ['auto-trader-location-id' => 'ADV1'],
        ]);

        $vehicle = Vehicle::factory()->create(array_merge([
            'dealership_id' => $dealership->id,
            'registration_number' => 'AB12 CDE',
            'vrm_condensed' => 'AB12CDE',
            'auto_trader_id' => null,
            // Pin lifecycle to FORECOURT so the export payload is deterministic (the factory
            // randomises is_sold/is_reserved, which would otherwise force every send).
            'is_sold' => false,
            'is_reserved' => false,
            'is_published' => true,
        ], $overrides));

        // Pre-set derivative so the job skips the taxonomy lookup HTTP call.
        $vehicle->autoTraderData()->create(['derivative_id' => 'DERIV1']);

        return $vehicle->fresh();
    }

    private function fakeAutoTrader(array $stockResponse = ['metadata' => ['stockId' => 'NEWSTK']], int $status = 200): void
    {
        Http::fake([
            '*authenticate*' => Http::response(['access_token' => 'tok'], 200),
            '*' => Http::response($stockResponse, $status),
        ]);
    }

    private function stockWrites(string $method): \Closure
    {
        return fn (Request $request) => $request->method() === $method
            && str_contains($request->url(), 'autotrader.co.uk/stock');
    }

    public function testPostsNewVehicleAndStoresStockId(): void
    {
        $this->fakeAutoTrader();
        $vehicle = $this->makeVehicle();

        new SendVehicleToAutotrader($vehicle)->handle();

        Http::assertSent($this->stockWrites('POST'));

        $vehicle->refresh();
        $this->assertEquals('NEWSTK', $vehicle->auto_trader_id);
        $this->assertNotNull($vehicle->autoTraderData->last_export_hash);

        Event::assertDispatched(AutoTraderIdAssignedToVehicle::class);

        $log = ApiNotification::query()->where('provider', 'auto-trader-export')->latest('id')->first();
        $this->assertNotNull($log);
        $this->assertEquals('post', $log->data['request_type']);
        $this->assertEquals('AB12CDE', $log->reference);

        $this->assertDatabaseHas('sales_channel_history', [
            'channel' => 'auto-trader',
            'vehicle_id' => $vehicle->id,
            'was_successful' => true,
        ]);
    }

    public function testPatchesExistingVehicle(): void
    {
        $this->fakeAutoTrader(['metadata' => ['stockId' => 'STK1']]);
        $vehicle = $this->makeVehicle(['auto_trader_id' => 'STK1']);

        new SendVehicleToAutotrader($vehicle)->handle();

        Http::assertSent(fn (Request $request) => $request->method() === 'PATCH'
            && str_contains($request->url(), 'autotrader.co.uk/stock/STK1'));
    }

    public function testSkipsExportWhenPayloadUnchanged(): void
    {
        $this->fakeAutoTrader();
        $vehicle = $this->makeVehicle();

        new SendVehicleToAutotrader($vehicle)->handle();

        // Second run with no changes must not call the AutoTrader stock endpoint again.
        new SendVehicleToAutotrader($vehicle->fresh())->handle();

        $stockCalls = Http::recorded(fn (Request $request) => str_contains($request->url(), 'autotrader.co.uk/stock'));
        $this->assertCount(1, $stockCalls);

        $this->assertTrue(
            ApiNotification::query()
                ->where('provider', 'auto-trader-export')
                ->get()
                ->contains(fn (ApiNotification $log) => ($log->data['request_type'] ?? null) === 'skipped-unchanged')
        );
    }

    public function testFeatureFlagRoutesExportToInProcessJob(): void
    {
        Feature::setEnabled(tenant(), ['auto-trader-in-process-export']);
        $this->fakeAutoTrader();
        $vehicle = $this->makeVehicle();

        $result = new AutoTraderHub()->setToken('hub-token')->export($vehicle);

        $this->assertTrue($result);
        Http::assertSent($this->stockWrites('POST'));
        // The microservice forward endpoint must NOT be hit.
        Http::assertNotSent(fn (Request $request) => str_contains($request->url(), 'send-vehicle'));
    }

    public function testRemoveSendsDeletedLifecyclePatch(): void
    {
        $this->fakeAutoTrader(['metadata' => ['stockId' => 'STK9']]);
        $vehicle = $this->makeVehicle(['auto_trader_id' => 'STK9']);

        new SendVehicleToAutotrader($vehicle, true)->handle();

        Http::assertSent(function (Request $request) {
            if ($request->method() !== 'PATCH' || !str_contains($request->url(), 'autotrader.co.uk/stock/STK9')) {
                return false;
            }
            return ($request->data()['metadata']['lifecycleState'] ?? null) === 'DELETED';
        });
    }
}
