<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Facades\TaxonomyMapper;
use Database\Seeders\Tenant\VehicleSpecSeeder;
use Illuminate\Support\Facades\Http;
use Mockery;
use Mtc\MercuryDataModels\BodyStyleType;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TenantTestCase;

class BackfillBodyTypeFromCapSectorCommandTest extends TenantTestCase
{
    private const SECTOR_ENDPOINT = 'https://soap.cap.co.uk/vehicles/capvehicles.asmx/GetCapDescriptionFromIdWithSector';
    private const COMMAND = 'cap:backfill-body-type-from-sector';

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed(VehicleSpecSeeder::class);

        Settings::update('vehicle-spec-providers-cap-subscriber_id', 12345);
        Settings::update('vehicle-spec-providers-cap-password', 'test_password');
    }

    public function testSkipsWhenCapIsDisabled(): void
    {
        Settings::update('vehicle-spec-providers-cap-enabled', false);
        Settings::update('vehicle-spec-providers-cap-use-sector-for-body-type', true);

        Http::fake(['*' => Http::response('should-not-be-called', 500)]);

        $this->artisan(self::COMMAND)
            ->expectsOutputToContain('CAP is not enabled')
            ->assertSuccessful();

        Http::assertNothingSent();
    }

    public function testSkipsWhenSectorSettingIsDisabled(): void
    {
        Settings::update('vehicle-spec-providers-cap-enabled', true);
        Settings::update('vehicle-spec-providers-cap-use-sector-for-body-type', false);

        Http::fake(['*' => Http::response('should-not-be-called', 500)]);

        $this->artisan(self::COMMAND)
            ->expectsOutputToContain('CAP sector body type override is not enabled')
            ->assertSuccessful();

        Http::assertNothingSent();
    }

    public function testSkipsVehiclesWithoutCapId(): void
    {
        Settings::update('vehicle-spec-providers-cap-enabled', true);
        Settings::update('vehicle-spec-providers-cap-use-sector-for-body-type', true);

        Vehicle::factory()->create(['cap_id' => null]);
        Vehicle::factory()->create(['cap_id' => '']);

        Http::fake([
            self::SECTOR_ENDPOINT => Http::response('should-not-be-called', 500),
        ]);

        $this->artisan(self::COMMAND)
            ->expectsOutputToContain('Checked 0 vehicles')
            ->assertSuccessful();

        Http::assertNothingSent();
    }

    public function testUpdatesBodyStyleForVehiclesWhereSectorMaps(): void
    {
        Settings::update('vehicle-spec-providers-cap-enabled', true);
        Settings::update('vehicle-spec-providers-cap-use-sector-for-body-type', true);

        $convertible = BodyStyleType::factory()->create(['name' => 'Convertible']);
        $coupe = BodyStyleType::factory()->create(['name' => 'Coupe']);

        $vehicleToFix = Vehicle::factory()->create([
            'cap_id' => '101666',
            'body_style_id' => $coupe->id,
        ]);
        $vehicleAlreadyRight = Vehicle::factory()->create([
            'cap_id' => '101667',
            'body_style_id' => $convertible->id,
        ]);

        Http::fake([
            self::SECTOR_ENDPOINT => $this->sectorResponse('Convertible Small'),
            '*' => Http::response('unexpected', 404),
        ]);

        $this->stubTaxonomyMapperReturns(['Convertible' => $convertible->id]);

        $this->artisan(self::COMMAND)
            ->expectsOutputToContain('Checked 2 vehicles, updated 1 body types from CAP sector.')
            ->assertSuccessful();

        $vehicleToFix->refresh();
        $vehicleAlreadyRight->refresh();
        $this->assertEquals($convertible->id, $vehicleToFix->body_style_id);
        $this->assertEquals($convertible->id, $vehicleAlreadyRight->body_style_id);
    }

    private function stubTaxonomyMapperReturns(array $termToId): void
    {
        $mock = Mockery::mock();
        $mock->shouldReceive('getMappedTaxonomy')
            ->andReturnUsing(function ($provider, $taxonomy, $term) use ($termToId) {
                return $termToId[$term] ?? null;
            });
        $mock->shouldReceive('storeUnmappedTaxonomies')->andReturn(false);
        TaxonomyMapper::swap($mock);
    }

    private function sectorResponse(string $sectorDescription)
    {
        $xml = file_get_contents(base_path('tests/data/cap/GetCapDescriptionFromIdWithSector.xml'));
        $xml = str_replace('{SECTOR_DESCRIPTION}', $sectorDescription, $xml);
        return Http::response($xml, 200);
    }
}
