<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Imports\AutoTraderApiToVehicleImport;
use App\Services\AutoTraderDealershipResolver;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Franchise;
use Mtc\MercuryDataModels\VehicleMake;
use Tests\TenantTestCase;

class AutoTraderMakeBasedAssignmentTest extends TenantTestCase
{
    public function testResolverAssignsVehicleToDealershipMatchingItsMake(): void
    {
        $ford = VehicleMake::factory()->create(['name' => 'Ford']);
        $bmw = VehicleMake::factory()->create(['name' => 'BMW']);

        $fordDealer = $this->coLocatedDealership('LOC1', $ford->id, ['is_autotrader_catchall' => true]);
        $bmwDealer = $this->coLocatedDealership('LOC1', $bmw->id);

        $resolver = new AutoTraderDealershipResolver();

        $this->assertSame($bmwDealer->id, $resolver->resolve('LOC1', $bmw->id)?->id);
        $this->assertSame($fordDealer->id, $resolver->resolve('LOC1', $ford->id)?->id);
    }

    public function testResolverFallsBackToCatchallForUnmatchedMake(): void
    {
        $ford = VehicleMake::factory()->create(['name' => 'Ford']);
        $audi = VehicleMake::factory()->create(['name' => 'Audi']);

        $fordDealer = $this->coLocatedDealership('LOC1', $ford->id, ['is_autotrader_catchall' => true]);

        $resolver = new AutoTraderDealershipResolver();

        // Audi has no franchise at this rooftop, so it lands on the catchall.
        $this->assertSame($fordDealer->id, $resolver->resolve('LOC1', $audi->id)?->id);
    }

    public function testResolverFallsBackToCatchallWhenMultipleDealershipsMatchTheMake(): void
    {
        $ford = VehicleMake::factory()->create(['name' => 'Ford']);

        $this->coLocatedDealership('LOC1', $ford->id);
        $catchall = $this->coLocatedDealership('LOC1', $ford->id, ['is_autotrader_catchall' => true]);

        $resolver = new AutoTraderDealershipResolver();

        // Ambiguous match (two Ford dealerships) is not confident, so it falls back to the catchall.
        $this->assertSame($catchall->id, $resolver->resolve('LOC1', $ford->id)?->id);
    }

    public function testResolverUsesLowestIdDealershipWhenNoCatchallFlagged(): void
    {
        $ford = VehicleMake::factory()->create(['name' => 'Ford']);
        $audi = VehicleMake::factory()->create(['name' => 'Audi']);

        $first = $this->coLocatedDealership('LOC1', $ford->id);
        $this->coLocatedDealership('LOC1', $ford->id);

        $resolver = new AutoTraderDealershipResolver();

        // No catchall flagged: the deterministic fallback is the lowest-id dealership in the group.
        $this->assertSame($first->id, $resolver->resolve('LOC1', $audi->id)?->id);
    }

    public function testResolverMatchesViaPivotWhenMultiFranchiseEnabled(): void
    {
        $this->makeSetting('dealerships-multiple-franchises', true);

        $bmw = VehicleMake::factory()->create(['name' => 'BMW']);
        $franchise = Franchise::factory()->create(['make_id' => $bmw->id]);

        $catchall = $this->coLocatedDealership('LOC1', null, ['is_autotrader_catchall' => true]);
        $bmwDealer = $this->coLocatedDealership('LOC1', null);
        $bmwDealer->franchises()->attach($franchise->id);

        $resolver = new AutoTraderDealershipResolver();

        $this->assertSame($bmwDealer->id, $resolver->resolve('LOC1', $bmw->id)?->id);
        // A make with no franchise in the pivot still falls back to the catchall.
        $audi = VehicleMake::factory()->create(['name' => 'Audi']);
        $this->assertSame($catchall->id, $resolver->resolve('LOC1', $audi->id)?->id);
    }

    public function testResolverReturnsNullWhenNoDealershipSharesTheLocationId(): void
    {
        $bmw = VehicleMake::factory()->create(['name' => 'BMW']);
        $this->coLocatedDealership('LOC1', $bmw->id, ['is_autotrader_catchall' => true]);

        $resolver = new AutoTraderDealershipResolver();

        $this->assertNull($resolver->resolve('UNKNOWN', $bmw->id));
    }

    public function testImportResolveDealershipIdReturnsNullWhenSettingDisabled(): void
    {
        $bmw = VehicleMake::factory()->create(['name' => 'BMW']);
        $this->coLocatedDealership('LOC1', $bmw->id, ['is_autotrader_catchall' => true]);

        $result = $this->invokeResolveDealershipId(
            new AutoTraderApiToVehicleImport(),
            $bmw->id,
            ['advertiser' => ['advertiserId' => 'LOC1']],
        );

        $this->assertNull($result);
    }

    public function testImportResolvesDealershipByMakeWhenSettingEnabled(): void
    {
        $this->makeSetting('autotrader-make-based-assignment', true);

        $ford = VehicleMake::factory()->create(['name' => 'Ford']);
        $bmw = VehicleMake::factory()->create(['name' => 'BMW']);
        $this->coLocatedDealership('LOC1', $ford->id, ['is_autotrader_catchall' => true]);
        $bmwDealer = $this->coLocatedDealership('LOC1', $bmw->id);

        $result = $this->invokeResolveDealershipId(
            new AutoTraderApiToVehicleImport(),
            $bmw->id,
            ['advertiser' => ['advertiserId' => 'LOC1']],
        );

        $this->assertSame($bmwDealer->id, $result);
    }

    public function testImportResolveDealershipIdReturnsNullWhenPayloadHasNoAdvertiserId(): void
    {
        $this->makeSetting('autotrader-make-based-assignment', true);

        $bmw = VehicleMake::factory()->create(['name' => 'BMW']);
        $this->coLocatedDealership('LOC1', $bmw->id, ['is_autotrader_catchall' => true]);

        $result = $this->invokeResolveDealershipId(new AutoTraderApiToVehicleImport(), $bmw->id, []);

        $this->assertNull($result);
    }

    private function coLocatedDealership(string $locationId, ?int $makeId, array $attributes = []): Dealership
    {
        $franchiseId = $makeId === null
            ? null
            : Franchise::factory()->create(['make_id' => $makeId])->id;

        return Dealership::factory()->create(array_merge([
            'franchise_id' => $franchiseId,
            'data' => ['auto-trader-location-id' => $locationId],
        ], $attributes));
    }

    private function invokeResolveDealershipId(
        AutoTraderApiToVehicleImport $importer,
        ?int $makeId,
        array $vehicleData
    ): ?int {
        $reflection = new \ReflectionMethod($importer, 'resolveDealershipId');
        $reflection->setAccessible(true);

        return $reflection->invoke($importer, $makeId, $vehicleData);
    }

    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,
        ]);
    }
}
