<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Modules\Valuation\Config\AutoTrader as AutoTraderConfig;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use App\Modules\Valuation\AutoTrader as AppAutoTraderDriver;
use Mtc\VehicleValuation\AutoTrader as AutoTraderDriver;
use Mtc\VehicleValuation\Facades\Valuation;
use Mtc\VehicleValuation\Models\VehicleValuation;
use Tests\TenantTestCase;
use Tests\TestValuationRepository;

class ValuationTest extends TenantTestCase
{
    public function testNewRequest()
    {
        $this->app->bind('valuation-repository', TestValuationRepository::class);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-trader-advertiser-id',
            'value' => 'abc-123',
            'type' => 'string',
        ]);

        $response = $this
            ->postJson(route('valuations.get'));

        $response->assertStatus(422);
        $this->assertArrayHasKey('registration_number', $response->json('errors'));
        $this->assertArrayHasKey('mileage', $response->json('errors'));

        $response = $this
            ->postJson(route('valuations.get'), [
                'registration_number' => 'FOO11BAZ',
                'mileage' => 60123
            ]);

        $response->assertStatus(201);
        $this->assertArrayHasKey('id', $response->json());
        $this->assertArrayHasKey('make', $response->json());
        $this->assertArrayHasKey('model', $response->json());
        $this->assertArrayHasKey('retailPrice', $response->json());

        $prices = $response->json('prices');
        $this->assertIsArray($prices);
        $this->assertCount(4, $prices);
        $this->assertSame(
            ['retailPrice', 'cleanPrice', 'averagePrice', 'belowPrice'],
            array_column($prices, 'key')
        );
        $this->assertSame(
            ['Retail Price', 'Clean Price', 'Average Price', 'Below Average Price'],
            array_column($prices, 'label')
        );
        $this->assertSame($response->json('retailPrice'), $prices[0]['price']);
        $this->assertSame($response->json('cleanPrice'), $prices[1]['price']);
        $this->assertSame($response->json('averagePrice'), $prices[2]['price']);
        $this->assertSame($response->json('belowPrice'), $prices[3]['price']);
    }

    public function testAutoTraderVatQualifyingValuationUsesConfiguredField()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => true,
            'type' => 'bool',
        ]);
        // AutoTrader credentials are global (env/config), not per-tenant. Set
        // them here so the test does not depend on a developer's local .env,
        // which is unset in CI.
        config()->set('valuation.drivers.auto-trader.api_key', 'test-key');
        config()->set('valuation.drivers.auto-trader.api_secret', 'test-secret');
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-trader-advertiser-id',
            'value' => 'abc-123',
            'type' => 'string',
        ]);

        // VAT-qualifying vehicle (e.g. an LCV): AutoTrader returns a null
        // amountGBP and splits the figure into the ex-VAT / no-VAT fields.
        Http::fake([
            '*autotrader.co.uk/authenticate' => Http::response(['access_token' => 'test-token']),
            '*autotrader.co.uk/vehicles*' => Http::response([
                'vehicle' => [
                    'derivativeId' => 'DERIV123',
                    'firstRegistrationDate' => '2022-03-01',
                    'make' => 'Ford',
                    'model' => 'Transit',
                    'vehicleType' => 'Van',
                    'vin' => 'VIN123',
                    'owners' => 1,
                ],
            ]),
            '*autotrader.co.uk/valuations*' => Http::response([
                'valuations' => [
                    'retail' => ['amountGBP' => null, 'amountExcludingVatGBP' => 16751, 'amountNoVatGBP' => 18588],
                    'partExchange' => ['amountGBP' => null, 'amountExcludingVatGBP' => 12914, 'amountNoVatGBP' => 14723],
                    'trade' => ['amountGBP' => null, 'amountExcludingVatGBP' => 12982, 'amountNoVatGBP' => 14800],
                    'private' => ['amountGBP' => null],
                ],
            ]),
        ]);

        $driver = new AutoTraderDriver(App::make(AutoTraderConfig::class));

        // Defaults to the no-VAT figure so the valuation is no longer empty.
        $default = $driver->getValuation('FOO11BAZ', 60123)->toArray();
        $this->assertEquals(18588, $default['retail_price']);
        $this->assertEquals(14723, $default['clean_price']);

        // Per-site setting can switch to the ex-VAT figure.
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-vat-price-field',
            'value' => 'amountExcludingVatGBP',
            'type' => 'string',
        ]);

        $exVat = $driver->getValuation('FOO11BAZ', 60123)->toArray();
        $this->assertEquals(16751, $exVat['retail_price']);
        $this->assertEquals(12914, $exVat['clean_price']);
    }

    public function testProvidingCosmeticConditionMakesSingleAutoTraderCall()
    {
        $this->configureAutoTraderDriver();

        $driver = new AppAutoTraderDriver(App::make(AutoTraderConfig::class));
        $result = $driver->getValuation('FOO11BAZ', 60123, null, 'good')->toArray();

        $valuationCalls = Http::recorded(
            fn (Request $request) => str_contains($request->url(), '/valuations')
        );

        $this->assertCount(1, $valuationCalls);
        $this->assertEquals('Good', $valuationCalls->first()[0]->data()['conditionRating']);

        // 'good' resolves to the average tier, so only that column is populated.
        $this->assertEquals(12000, $result['average_price']);
        $this->assertNull($result['clean_price']);
        $this->assertNull($result['below_price']);
        $this->assertNull($result['retail_price']);
    }

    public function testOmittingCosmeticConditionMakesMultipleAutoTraderCalls()
    {
        $this->configureAutoTraderDriver();

        $driver = new AppAutoTraderDriver(App::make(AutoTraderConfig::class));
        $driver->getValuation('FOO11BAZ', 60123);

        $valuationCalls = Http::recorded(
            fn (Request $request) => str_contains($request->url(), '/valuations')
        );

        $this->assertCount(3, $valuationCalls);
        $ratings = $valuationCalls->map(fn (array $pair): string => $pair[0]->data()['conditionRating'])->values()->all();
        $this->assertEqualsCanonicalizing(['Excellent', 'Good', 'Poor'], $ratings);
    }

    public function testFairConditionFetchesFairRatingIntoBelowTier()
    {
        $this->configureAutoTraderDriver();

        $driver = new AppAutoTraderDriver(App::make(AutoTraderConfig::class));
        $result = $driver->getValuation('FOO11BAZ', 60123, null, 'Fair')->toArray();

        $valuationCalls = Http::recorded(
            fn (Request $request) => str_contains($request->url(), '/valuations')
        );

        // 'Fair' is one of the five AutoTrader markers, so it is requested
        // verbatim in a single call and only its value is stored.
        $this->assertCount(1, $valuationCalls);
        $this->assertEquals('Fair', $valuationCalls->first()[0]->data()['conditionRating']);

        $this->assertEquals(12000, $result['below_price']);
        $this->assertNull($result['clean_price']);
        $this->assertNull($result['average_price']);
        $this->assertNull($result['retail_price']);
    }

    public function testNoConditionDoesNotReuseConditionSpecificCachedValuation()
    {
        $this->configureAutoTraderDriver();

        // A condition-specific request stores a single-tier row.
        $fair = Valuation::get('FOO11BAZ', 60123, null, 'Fair');
        $this->assertEquals('Fair', $fair->cosmetic_condition);
        $this->assertNull($fair->clean_price);

        // A request with no condition must not reuse the cached Fair row; it
        // processes every tier instead.
        $default = Valuation::get('FOO11BAZ', 60123);

        $this->assertNull($default->cosmetic_condition);
        $this->assertEquals(12000, $default->clean_price);
        $this->assertEquals(12000, $default->average_price);
        $this->assertEquals(12000, $default->below_price);
        $this->assertEquals(20000, $default->retail_price);
    }

    private function configureAutoTraderDriver(): void
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => true,
            'type' => 'bool',
        ]);
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-trader-advertiser-id',
            'value' => 'abc-123',
            'type' => 'string',
        ]);
        config()->set('valuation.drivers.auto-trader.api_key', 'test-key');
        config()->set('valuation.drivers.auto-trader.api_secret', 'test-secret');

        Http::fake([
            '*autotrader.co.uk/authenticate' => Http::response(['access_token' => 'test-token']),
            '*autotrader.co.uk/vehicles*' => Http::response([
                'vehicle' => [
                    'derivativeId' => 'DERIV123',
                    'firstRegistrationDate' => '2022-03-01',
                    'make' => 'Ford',
                    'model' => 'Focus',
                    'vehicleType' => 'Car',
                    'vin' => 'VIN123',
                    'owners' => 1,
                ],
            ]),
            '*autotrader.co.uk/valuations*' => Http::response([
                'valuations' => [
                    'retail' => ['amountGBP' => 20000],
                    'partExchange' => ['amountGBP' => 12000],
                    'trade' => ['amountGBP' => 11000],
                    'private' => ['amountGBP' => 13000],
                ],
            ]),
        ]);
    }

    public function testGoodbyeCarFullJourney()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-trader-advertiser-id',
            'value' => 'abc-123',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-require-customer-details',
            'value' => true,
            'type' => 'bool',
        ]);

        $valuation_amount = 100;

        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/request-valuation*' => Http::response([
                'vehicle' => [
                    'manufacturer' => 'test_make',
                    'model' => 'test_model',
                    'body' => 'coupe',
                    'colour' => 'red',
                    'engine_size' => 1.6,
                    'fuel' => 'petrol',
                    'transmission' => 'manual',
                ],
                'valuation' => $valuation_amount,
                'valuation_high' => 125,
                'valuation_low' => 75,
                'id' => 123
            ]),
            'http://www.goodbyecar.mtcdevserver4.com/api/customer-info*' => Http::response([
                'status' => 'success'
            ])
        ]);

        // try an invalid request
        $response = $this
            ->postJson(route('valuations.get'));

        $response->assertStatus(422);
        $this->assertArrayHasKey('registration_number', $response->json('errors'));
        $this->assertArrayHasKey('mileage', $response->json('errors'));

        // try a valid request
        $response = $this
            ->postJson(route('valuations.get'), [
                'registration_number' => 'FOO11BAZ',
                'mileage' => 60123
            ]);

        // assert that the valuation is not returned
        $response->assertStatus(201);
        $this->assertArrayHasKey('id', $response->json());
        $this->assertArrayHasKey('make', $response->json());
        $this->assertArrayHasKey('model', $response->json());
        $this->assertArrayHasKey('retailPrice', $response->json());

        $this->assertEquals('test_make', $response->json('make'));
        $this->assertEquals('test_model', $response->json('model'));

        $this->assertNull($response->json('retailPrice'));
        $this->assertNull($response->json('belowPrice'));
        $this->assertNull($response->json('averagePrice'));
        $this->assertNull($response->json('cleanPrice'));

        // assert that the valuation id was returned
        $this->assertArrayHasKey('valuation_id', $response->json());

        // assert that the valuation was created
        $this->assertCount(1, VehicleValuation::all());

        // assert that the valuation id returned matches a db row
        $valuation_id = $response->json('valuation_id');
        $valuation_model = VehicleValuation::query()->where('valuation_id', '=', $valuation_id)->first();
        $this->assertNotNull($valuation_model);
        $this->assertEquals('FOO11BAZ', $valuation_model->registration);

        // send customer details to retrieve valuation
        $response = $this
            ->postJson(route('valuations.submit-customer'), [
                'valuation_id' => $valuation_id,
                'first_name' => 'test',
                'last_name' => 'test',
                'email' => 'test@test.com',
                'phone' => 123,
                'postcode' => 'abc',
            ]);

        $response->assertStatus(200);

        // assert that the valuation was retrieved
        $this->assertArrayHasKey('valuation', $response->json());
        $this->assertArrayHasKey('registration', $response->json('valuation'));
        $this->assertEquals($valuation_model->registration, $response->json('valuation.registration'));
        $this->assertEquals($valuation_amount, $response->json('valuation.averagePrice'));
    }

    public function testGoodbyeCarSendCustomerData()
    {
        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/customer-info*' => Http::response([
                'status' => 'success'
            ])
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => false,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        $valuation = VehicleValuation::query()->create([
            'valuation_id' => 'ab123',
            'provider' => 'test',
            'registration' => 'foo',
            'mileage' => 12345,
        ]);

        $response = $this
            ->postJson(route('valuations.submit-customer'), [
                'valuation_id' => $valuation->valuation_id,
                'first_name' => 'test',
                'last_name' => 'test',
                'email' => 'test@test.com',
                'phone' => 123,
                'postcode' => 'abc',
            ]);

        Http::assertSent(fn (Request $request) => stripos($request->url(), '?api_token=test-gbc-key') !== false);

        $response->assertStatus(200);

        $this->assertArrayHasKey('valuation', $response->json());
        $this->assertArrayHasKey('registration', $response->json('valuation'));
        $this->assertEquals($valuation->registration, $response->json('valuation.registration'));
    }

    public function testGoodbyeCarSendCustomerDataFailure()
    {
        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/customer-info*' => Http::response([])
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => false,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        $valuation = VehicleValuation::query()->create([
            'valuation_id' => 'ab123',
            'provider' => 'test',
            'registration' => 'foo',
            'mileage' => 12345,
        ]);

        $response = $this
            ->postJson(route('valuations.submit-customer'), [
                'valuation_id' => $valuation->valuation_id,
                'first_name' => 'test',
                'last_name' => 'test',
                'email' => 'test@test.com',
                'phone' => 123,
                'postcode' => 'abc',
            ]);

        Http::assertSent(fn (Request $request) => stripos($request->url(), '?api_token=test-gbc-key') !== false);

        $response->assertStatus(422);

        $this->assertArrayHasKey('valuation', $response->json());
        $this->assertNull($response->json('valuation'));
    }

    public function testGoodbyeCarCustomerInvalidRequest()
    {
        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/customer-info*' => Http::response([
                'status' => 'success'
            ])
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => false,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        $valuation = VehicleValuation::query()->create([
            'valuation_id' => 'ab123',
            'provider' => 'test',
            'registration' => 'foo',
            'mileage' => 12345,
        ]);

        $response = $this
            ->postJson(route('valuations.submit-customer'), [
                'valuation_id' => $valuation->id,
            ]);

        $response->assertStatus(422);
    }

    public function testGoodbyeCarCustomerNoValuation()
    {
        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/customer-info*' => Http::response([
                'status' => 'success'
            ])
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => false,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        $response = $this
            ->postJson(route('valuations.submit-customer'), [
                'valuation_id' => 123,
                'first_name' => 'test',
                'last_name' => 'test',
                'email' => 'test@test.com',
                'phone' => 123,
                'postcode' => 'abc',
            ]);

        $response->assertStatus(422);
    }

    public function testGoodbyeCarValuationSaved()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => false,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/request-valuation*' => Http::response([
                'vehicle' => [
                    'manufacturer' => 'test_make',
                    'model' => 'test_model',
                    'body' => 'coupe',
                    'colour' => 'red',
                    'engine_size' => 1.6,
                    'fuel' => 'petrol',
                    'transmission' => 'manual',
                ],
                'valuation' => 100,
                'valuation_high' => 125,
                'valuation_low' => 75,
                'id' => 123
            ])
        ]);

        $this->assertCount(0, VehicleValuation::all());

        $response = $this
            ->postJson(route('valuations.get'), [
                'registration_number' => 'abc123',
                'mileage' => 12345,
            ]);

        $response->assertStatus(201);

        $this->assertCount(1, VehicleValuation::all());
    }

    public function testGoodbyeCarValuationFailed()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => false,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/request-valuation*' => Http::response([
                'id' => 123,
                'valuation' => null,
            ])
        ]);

        $this->assertCount(0, VehicleValuation::all());

        $response = $this
            ->postJson(route('valuations.get'), [
                'registration_number' => 'abc123',
                'mileage' => 12345,
            ]);

        $response->assertStatus(422);
        $this->assertCount(0, VehicleValuation::all());
    }

    public function testGoodbyeCarValuationApiError()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-auto-trader-enabled',
            'value' => false,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/request-valuation*' => Http::response([], 404)
        ]);

        $this->assertCount(0, VehicleValuation::all());

        $response = $this
            ->postJson(route('valuations.get'), [
                'registration_number' => 'abc123',
                'mileage' => 12345,
            ]);

        $response->assertStatus(422);

        $this->assertCount(0, VehicleValuation::all());
    }

    public function testGoodbyeCarReturnValuation()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-trader-advertiser-id',
            'value' => 'abc-123',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-require-customer-details',
            'value' => false,
            'type' => 'bool',
        ]);

        $valuation_amount = 100;

        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/request-valuation*' => Http::response([
                'vehicle' => [
                    'manufacturer' => 'test_make',
                    'model' => 'test_model',
                    'body' => 'coupe',
                    'colour' => 'red',
                    'engine_size' => 1.6,
                    'fuel' => 'petrol',
                    'transmission' => 'manual',
                ],
                'valuation' => $valuation_amount,
                'valuation_high' => 125,
                'valuation_low' => 75,
                'id' => 123
            ]),
        ]);

        $response = $this
            ->postJson(route('valuations.get'), [
                'registration_number' => 'FOO11BAZ',
                'mileage' => 60123
            ]);

        // assert that the valuation is returned
        $response->assertStatus(201);

        $this->assertArrayHasKey('make', $response->json());
        $this->assertArrayHasKey('model', $response->json());
        $this->assertArrayHasKey('averagePrice', $response->json());
        $this->assertEquals('test_make', $response->json('make'));
        $this->assertEquals('test_model', $response->json('model'));
        $this->assertEquals($valuation_amount, $response->json('averagePrice'));
    }

    public function testGoodbyeCarDoesNotReturnValuation()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-trader-advertiser-id',
            'value' => 'abc-123',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-require-customer-details',
            'value' => true,
            'type' => 'bool',
        ]);

        $valuation_amount = 100;

        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/request-valuation*' => Http::response([
                'vehicle' => [
                    'manufacturer' => 'test_make',
                    'model' => 'test_model',
                    'body' => 'coupe',
                    'colour' => 'red',
                    'engine_size' => 1.6,
                    'fuel' => 'petrol',
                    'transmission' => 'manual',
                ],
                'valuation' => $valuation_amount,
                'valuation_high' => 125,
                'valuation_low' => 75,
                'id' => 123
            ]),
        ]);

        $response = $this
            ->postJson(route('valuations.get'), [
                'registration_number' => 'FOO11BAZ',
                'mileage' => 60123
            ]);

        $response->assertStatus(201);

        $this->assertArrayHasKey('id', $response->json());
        $this->assertArrayHasKey('make', $response->json());
        $this->assertArrayHasKey('model', $response->json());
        $this->assertArrayHasKey('retailPrice', $response->json());
        $this->assertArrayHasKey('valuation_id', $response->json());

        $this->assertEquals('test_make', $response->json('make'));
        $this->assertEquals('test_model', $response->json('model'));

        $this->assertNull($response->json('retailPrice'));
        $this->assertNull($response->json('belowPrice'));
        $this->assertNull($response->json('averagePrice'));
        $this->assertNull($response->json('cleanPrice'));
    }

    public function testEmptyValuationRequiringCustomerDetails()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'auto-trader-advertiser-id',
            'value' => 'abc-123',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-goodbye-car-api-key',
            'value' => 'test-gbc-key',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-require-customer-details',
            'value' => true,
            'type' => 'bool',
        ]);

        Http::fake([
            'http://www.goodbyecar.mtcdevserver4.com/api/request-valuation*' => Http::response([
                'id' => 123,
                'valuation' => null,
            ])
        ]);

        // try a valid request
        $response = $this
            ->postJson(route('valuations.get'), [
                'registration_number' => 'FOO11BAZ',
                'mileage' => 60123
            ]);

        $response->assertStatus(422);
        $this->assertCount(0, VehicleValuation::all());
    }

    public function testBcaCondition()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-bca-enabled',
            'type' => 'boolean',
            'value' => true,
        ]);

        Http::fake([
            'https://login.microsoftonline.com/ffbeab18-cefa-4aaf-9554-75a0af201128/oauth2/v2.0/token' => Http::response(
                [
                    'access_token' => 'abcdef',
                ],
                200
            ),
            'https://bca-apim-prod-gateway.api.bca.com/onlinevaluation/api/vehicles/abc123/specification' => Http::response([
                'vehicleSpecifications' => [
                    [
                        'identifier' => 'foo',
                        'colour' => 'blue',
                        'registrationDate' => '2020-01-01T00:00:00',
                        'vehicleType' => 'car',
                        'make' => 'bmw',
                    ],
                ],
                'correlationId' => '',
            ], 200),
            '*' => Http::response([
                'current' => [
                    'valuation' => 55000,
                ],
            ], 200),
        ]);

        Valuation::get(
            'abc123',
            12345,
            null,
            'good',
        );

        Http::assertSent(function (Request $request) {
            if (Str::contains($request->body(), 'cosmeticCondition')) {
                return Str::contains($request->body(), '"cosmeticCondition":"Good"');
            }
        });

        $this->assertCount(1, VehicleValuation::where('cosmetic_condition', 'Good')->get());
    }

    public function testBcaNoCondition()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-bca-enabled',
            'type' => 'boolean',
            'value' => true,
        ]);

        Http::fake([
            'https://login.microsoftonline.com/ffbeab18-cefa-4aaf-9554-75a0af201128/oauth2/v2.0/token' => Http::response(
                [
                    'access_token' => 'abcdef',
                ],
                200
            ),
            'https://bca-apim-prod-gateway.api.bca.com/onlinevaluation/api/vehicles/abc123/specification' => Http::response([
                'vehicleSpecifications' => [
                    [
                        'identifier' => 'foo',
                        'colour' => 'blue',
                        'registrationDate' => '2020-01-01T00:00:00',
                        'vehicleType' => 'car',
                        'make' => 'bmw',
                    ],
                ],
                'correlationId' => '',
            ], 200),
            '*' => Http::response([
                'current' => [
                    'valuation' => 55000,
                ],
            ], 200),
        ]);

        Valuation::get(
            'abc123',
            12345,
            null,
        );

        Http::assertSent(function (Request $request) {
            if (Str::contains($request->body(), 'cosmeticCondition')) {
                return Str::contains($request->body(), '"cosmeticCondition":"Excellent"');
            }
        });

        $this->assertCount(1, VehicleValuation::where('cosmetic_condition', 'Excellent')->get());
    }

    public function testBcaServiceHistory()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-bca-enabled',
            'type' => 'boolean',
            'value' => true,
        ]);

        Http::fake([
            'https://login.microsoftonline.com/ffbeab18-cefa-4aaf-9554-75a0af201128/oauth2/v2.0/token' => Http::response(
                [
                    'access_token' => 'abcdef',
                ],
                200
            ),
            'https://bca-apim-prod-gateway.api.bca.com/onlinevaluation/api/vehicles/abc123/specification' => Http::response([
                'vehicleSpecifications' => [
                    [
                        'identifier' => 'foo',
                        'colour' => 'blue',
                        'registrationDate' => '2020-01-01T00:00:00',
                        'vehicleType' => 'car',
                        'make' => 'bmw',
                    ],
                ],
                'correlationId' => '',
            ], 200),
            '*' => Http::response([
                'current' => [
                    'valuation' => 55000,
                ],
            ], 200),
        ]);

        Valuation::get(
            'abc123',
            12345,
            null,
            null,
            ['service_history' => 'partial'],
        );

        Http::assertSent(function (Request $request) {
            if (Str::contains($request->body(), 'serviceHistory')) {
                return Str::contains($request->body(), '"serviceHistory":"Part"');
            }
        });

        $valuation = VehicleValuation::first();
        $this->assertEquals('partial', $valuation->data['service_history']);
    }

    public function testBcaDefaultServiceHistory()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-bca-enabled',
            'type' => 'boolean',
            'value' => true,
        ]);

        Http::fake([
            'https://login.microsoftonline.com/ffbeab18-cefa-4aaf-9554-75a0af201128/oauth2/v2.0/token' => Http::response(
                [
                    'access_token' => 'abcdef',
                ],
                200
            ),
            'https://bca-apim-prod-gateway.api.bca.com/onlinevaluation/api/vehicles/abc123/specification' => Http::response([
                'vehicleSpecifications' => [
                    [
                        'identifier' => 'foo',
                        'colour' => 'blue',
                        'registrationDate' => '2020-01-01T00:00:00',
                        'vehicleType' => 'car',
                        'make' => 'bmw',
                    ],
                ],
                'correlationId' => '',
            ], 200),
            '*' => Http::response([
                'current' => [
                    'valuation' => 55000,
                ],
            ], 200),
        ]);

        Valuation::get(
            'abc123',
            12345,
            null,
        );

        Http::assertSent(function (Request $request) {
            if (Str::contains($request->body(), 'serviceHistory')) {
                return Str::contains($request->body(), '"serviceHistory":"Full"');
            }
        });
    }

    public function testBcaServiceHistoryNone()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'valuation-bca-enabled',
            'type' => 'boolean',
            'value' => true,
        ]);

        Http::fake([
            'https://login.microsoftonline.com/ffbeab18-cefa-4aaf-9554-75a0af201128/oauth2/v2.0/token' => Http::response(
                [
                    'access_token' => 'abcdef',
                ],
                200
            ),
            'https://bca-apim-prod-gateway.api.bca.com/onlinevaluation/api/vehicles/abc123/specification' => Http::response([
                'vehicleSpecifications' => [
                    [
                        'identifier' => 'foo',
                        'colour' => 'blue',
                        'registrationDate' => '2020-01-01T00:00:00',
                        'vehicleType' => 'car',
                        'make' => 'bmw',
                    ],
                ],
                'correlationId' => '',
            ], 200),
            '*' => Http::response([
                'current' => [
                    'valuation' => 55000,
                ],
            ], 200),
        ]);

        Valuation::get(
            'abc123',
            12345,
            null,
            null,
            ['service_history' => 'none'],
        );

        Http::assertSent(function (Request $request) {
            if (Str::contains($request->body(), 'serviceHistory')) {
                return Str::contains($request->body(), '"serviceHistory":"None"');
            }
        });

        $valuation = VehicleValuation::first();
        $this->assertEquals('none', $valuation->data['service_history']);
    }
}
