<?php

namespace Tests\Tenant;

use App\Events\AutoTraderIdAssignedToVehicle;
use App\Facades\Settings;
use App\Jobs\ExportVehicleToAutoTrader;
use App\Jobs\HandleAutoTraderHubNotification;
use App\Jobs\RemoveAutoTraderReferences;
use App\Services\AutoTraderHub;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Http;
use Mtc\MercuryDataModels\ApiNotification;
use Mtc\MercuryDataModels\SalesChannelHistory;
use Mtc\MercuryDataModels\SalesChannelRule;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;

class AutoTraderRemoveUnmatchedVehicleTest extends TenantTestCase
{
    #[\Override]
    protected function setUp(): void
    {
        parent::setUp();
        $this->makeSetting('auto-trader-hub-token', 'test-token', 'string');
        Http::fake([
            '*remove-vehicle' => Http::response(['status' => true], 200),
            '*send-vehicle' => Http::response(['status' => true], 200),
            '*' => Http::response([], 200),
        ]);
    }

    // --- Fix 1: ExportVehicleToAutoTrader de-lists excluded vehicles -------------------

    public function testExcludedVehicleWithAutoTraderIdIsRemovedWhenSettingEnabled(): void
    {
        $this->makeSetting('auto-trader-hub-remove-unmatched-vehicles', true);
        $this->excludeRegistrationRule('111');

        $vehicle = Vehicle::factory()->create([
            'registration_number' => '111',
            'auto_trader_id' => 'STK1',
        ]);

        Bus::fake([RemoveAutoTraderReferences::class]);

        (new ExportVehicleToAutoTrader($vehicle))->handle(app(AutoTraderHub::class));

        $this->assertHttpSent('remove-vehicle');
        $this->assertHttpNotSent('send-vehicle');
        Bus::assertDispatched(RemoveAutoTraderReferences::class);
    }

    public function testExcludedVehicleIsNotRemovedWhenSettingDisabled(): void
    {
        // Setting left disabled (not created).
        $this->excludeRegistrationRule('111');

        $vehicle = Vehicle::factory()->create([
            'registration_number' => '111',
            'auto_trader_id' => 'STK1',
        ]);

        Bus::fake([RemoveAutoTraderReferences::class]);

        (new ExportVehicleToAutoTrader($vehicle))->handle(app(AutoTraderHub::class));

        $this->assertHttpNotSent('remove-vehicle');
        $this->assertHttpNotSent('send-vehicle');
        Bus::assertNotDispatched(RemoveAutoTraderReferences::class);
    }

    public function testExcludedVehicleWithoutAutoTraderIdIsNotRemoved(): void
    {
        $this->makeSetting('auto-trader-hub-remove-unmatched-vehicles', true);
        $this->excludeRegistrationRule('111');

        $vehicle = Vehicle::factory()->create([
            'registration_number' => '111',
            'auto_trader_id' => null,
        ]);

        Bus::fake([RemoveAutoTraderReferences::class]);

        (new ExportVehicleToAutoTrader($vehicle))->handle(app(AutoTraderHub::class));

        $this->assertHttpNotSent('remove-vehicle');
        Bus::assertNotDispatched(RemoveAutoTraderReferences::class);
    }

    public function testMatchingVehicleIsStillExported(): void
    {
        $this->makeSetting('auto-trader-hub-remove-unmatched-vehicles', true);
        $this->excludeRegistrationRule('111');

        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'AB12CDE',
            'auto_trader_id' => 'STK1',
        ]);

        (new ExportVehicleToAutoTrader($vehicle))->handle(app(AutoTraderHub::class));

        $this->assertHttpSent('send-vehicle');
        $this->assertHttpNotSent('remove-vehicle');
    }

    // --- Fix 2: upsert-return notification skips + removes excluded vehicles -----------

    public function testUpsertReturnRemovesAndSkipsExcludedVehicle(): void
    {
        $this->makeSetting('auto-trader-hub-remove-unmatched-vehicles', true);
        $this->excludeRegistrationRule('111');

        $vehicle = Vehicle::factory()->create([
            'registration_number' => '111',
            'auto_trader_id' => null,
        ]);

        Bus::fake([RemoveAutoTraderReferences::class]);

        $this->makeUpsertJob($vehicle->id, 'STK-NEW')->handle();

        $this->assertHttpSent('remove-vehicle');
        Bus::assertDispatched(RemoveAutoTraderReferences::class);
        // The stale ack must NOT link the now-excluded vehicle to AutoTrader.
        $this->assertNull($vehicle->fresh()->auto_trader_id);
        $this->assertDatabaseHas((new SalesChannelHistory())->getTable(), [
            'vehicle_id' => $vehicle->id,
            'channel' => 'auto-trader',
        ]);
    }

    public function testUpsertReturnProceedsForMatchingVehicle(): void
    {
        $this->makeSetting('auto-trader-hub-remove-unmatched-vehicles', true);
        $this->excludeRegistrationRule('111');
        Event::fake([AutoTraderIdAssignedToVehicle::class]);

        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'AB12CDE',
            'auto_trader_id' => null,
        ]);

        $this->makeUpsertJob($vehicle->id, 'STK-NEW')->handle();

        $this->assertHttpNotSent('remove-vehicle');
        // Matching vehicle is linked as normal.
        $this->assertEquals('STK-NEW', $vehicle->fresh()->auto_trader_id);
    }

    public function testUpsertReturnIgnoresExclusionWhenSettingDisabled(): void
    {
        // Setting left disabled (not created).
        $this->excludeRegistrationRule('111');
        Event::fake([AutoTraderIdAssignedToVehicle::class]);

        $vehicle = Vehicle::factory()->create([
            'registration_number' => '111',
            'auto_trader_id' => null,
        ]);

        Bus::fake([RemoveAutoTraderReferences::class]);

        $this->makeUpsertJob($vehicle->id, 'STK-NEW')->handle();

        $this->assertHttpNotSent('remove-vehicle');
        Bus::assertNotDispatched(RemoveAutoTraderReferences::class);
        // Existing behaviour preserved: the vehicle is still linked.
        $this->assertEquals('STK-NEW', $vehicle->fresh()->auto_trader_id);
    }

    // --- Helpers -----------------------------------------------------------------------

    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 excludeRegistrationRule(string $registration): void
    {
        SalesChannelRule::query()->create([
            'channel' => 'auto-trader-sales',
            'conditions' => [
                [
                    'value' => [
                        'type' => 'and',
                        'column' => 'registration_number',
                        'operator' => '!=',
                        'value' => $registration,
                    ],
                ],
            ],
        ]);
    }

    private function makeUpsertJob(int $vehicleId, string $stockId): HandleAutoTraderHubNotification
    {
        $input = [
            'type' => 'stock-upsert',
            'result' => 'success',
            'vehicle_id' => $vehicleId,
            'stock_id' => $stockId,
            'data' => ['metadata' => ['stockId' => $stockId]],
        ];

        $notification = ApiNotification::query()->create([
            'provider' => 'auto-trader-hub',
            'data' => $input,
            'data_model' => 'vehicle',
        ]);

        return new HandleAutoTraderHubNotification($input, $notification);
    }

    private function assertHttpSent(string $needle): void
    {
        Http::assertSent(fn ($request) => str_contains($request->url(), $needle));
    }

    private function assertHttpNotSent(string $needle): void
    {
        Http::assertNotSent(fn ($request) => str_contains($request->url(), $needle));
    }
}
