<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
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());
    }

    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(function (Request $request) {
            return 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(function (Request $request) {
            return 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());
    }
}
