<?php

namespace Tests\Feature;

use App\Facades\Settings;
use App\VehicleSpec\Services\HPISpecProvider;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Http;
use Mtc\MercuryDataModels\Vehicle;
use Tests\TestCase;
use Tests\UserForTenant;

class HPITest extends TestCase
{
    use DatabaseMigrations;
    use UserForTenant;

    protected $tenancy = true;

    private function seedHpiSettings(): void
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'hpi-enabled',
            'config_key' => 'vehicle-spec-providers-hpi-enabled',
            'type' => 'bool',
            'value' => true,
        ]);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'hpi-customer',
            'config_key' => 'vehicle-spec-providers-hpi-customer_code',
            'type' => 'string',
            'value' => 'test',
        ]);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'hpi-pass',
            'config_key' => 'vehicle-spec-providers-hpi-password',
            'type' => 'string',
            'value' => 'test',
        ]);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'hpi-init',
            'config_key' => 'vehicle-spec-providers-hpi-initials',
            'type' => 'string',
            'value' => 'mtc',
        ]);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'hpi-primary',
            'config_key' => 'vehicle-spec-providers-hpi-primary_product_code',
            'type' => 'string',
            'value' => 'foo',
        ]);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'hpi-supp',
            'config_key' => 'vehicle-spec-providers-hpi-supplementary_product_code',
            'type' => 'string',
            'value' => 'bar',
        ]);
    }

    public function testStandardEquipment()
    {
        $this->seedHpiSettings();
        $lookupResponse = file_get_contents(base_path('tests/data/HPI/lookupResponseWithOptions.xml'));

        Http::fake([
            'https://wss.hpi.co.uk/TradeSoap/services/SupplementaryEnquiryV1*' => Http::response($lookupResponse),
            'http://pat-wss.hpi.co.uk/TradeSoap/services/SupplementaryEnquiryV1*' => Http::response($lookupResponse),
            "*" => Http::response([], 400),
        ]);

        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'GN69 JNK',
            'vrm_condensed' => 'GN69JNK',
            'odometer_mi' => 58000,
            'vin' => null,
        ]);

        $hpi = App::make(HPISpecProvider::class);
        $result = $hpi->getSpec($vehicle);

        $this->assertNotNull($result->standard_equipment);
        $this->assertCount(8, $result->standard_equipment);

        $flatten = collect($result->standard_equipment)
            ->map(fn($equipment) => $equipment->description)
            ->all();

        $this->assertContains('12v power outlet: front and rear, front', $flatten);
        $this->assertContains('Mirror Package', $flatten);
    }

    public function testTechnicalData()
    {
        $this->seedHpiSettings();
        $lookupResponse = file_get_contents(base_path('tests/data/HPI/lookupResponseWithOptions.xml'));

        Http::fake([
            'https://wss.hpi.co.uk/TradeSoap/services/SupplementaryEnquiryV1*' => Http::response($lookupResponse),
            'http://pat-wss.hpi.co.uk/TradeSoap/services/SupplementaryEnquiryV1*' => Http::response($lookupResponse),
            "*" => Http::response([], 400),
        ]);

        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'GN69 JNK',
            'vrm_condensed' => 'GN69JNK',
            'odometer_mi' => 58000,
            'vin' => null,
        ]);

        $hpi = App::make(HPISpecProvider::class);
        $result = $hpi->getSpec($vehicle);

        $this->assertTrue($result->technical_data instanceof Collection);
        $this->assertEquals(12, $result->technical_data->count());


        $get = function (string $label) use ($result) {
            return $result->technical_data->firstWhere('description', $label);
        };

        $this->assertSame('BLUE', $get('Colour')->value);
        $this->assertSame('Petrol', $get('Fuel Type')->value);
        $this->assertSame('Hatchback', $get('Body Type')->value);
        $this->assertSame('1496', $get('Engine Size')->value);
        $this->assertSame('5', (string)$get('Doors')->value);
    }

    public function testStandardEquipmentIsEmpty(): void
    {
        $this->seedHpiSettings();
        $lookupResponse = file_get_contents(base_path('tests/data/HPI/lookupResponse.xml'));

        Http::fake([
            'https://wss.hpi.co.uk/TradeSoap/services/SupplementaryEnquiryV1*' => Http::response($lookupResponse),
            'http://pat-wss.hpi.co.uk/TradeSoap/services/SupplementaryEnquiryV1*' => Http::response($lookupResponse),
            "*" => Http::response([], 400),
        ]);

        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'GN69 JNK',
            'vrm_condensed' => 'GN69JNK',
            'odometer_mi' => 58000,
            'vin' => null,
        ]);

        $hpi = App::make(HPISpecProvider::class);
        $result = $hpi->getSpec($vehicle);

        $this->assertTrue($result->standard_equipment instanceof Collection);
        $this->assertEquals(0, $result->standard_equipment->count());
    }

    public function testHandlesHttpError(): void
    {
        $this->seedHpiSettings();

        Http::fake([
            '*' => Http::response('Internal Error', 500),
        ]);

        $result = app(HPISpecProvider::class)->getSpec(Vehicle::factory()->create());
        $this->assertTrue($result->standard_equipment instanceof Collection);
        $this->assertEquals(collect(), $result->standard_equipment);
        $this->assertTrue($result->technical_data instanceof Collection);
        $this->assertEquals(collect(), $result->technical_data);
    }

    public function testHandlesMalformedXml(): void
    {
        $this->seedHpiSettings();
        Http::fake(['*' => Http::response('<xml>oops', 200, ['Content-Type' => 'text/xml'])]);

        $res = app(HPISpecProvider::class)->getSpec(Vehicle::factory()->create());
        $this->assertEquals(collect(), $res->standard_equipment);
        $this->assertEquals(collect(), $res->technical_data);
    }

    public function testRequestContainsVrmSameAsResponse(): void
    {
        $this->seedHpiSettings();
        $lookupResponse = file_get_contents(base_path('tests/data/HPI/lookupResponseWithOptions.xml'));

        Http::fake([
            '*' => Http::response($lookupResponse)
        ]);

        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'GN69 JNK',
            'vrm_condensed' => 'GN69JNK',
            'odometer_mi' => 58000,
            'vin' => null,
        ]);
        app(HPISpecProvider::class)->getSpec($vehicle);

        Http::assertSent(function ($req) {
            $body = (string)$req->body();
            return str_contains($body, 'GN69JNK') &&
                str_contains($req->header('SOAPAction')[0] ?? '', 'Supplem');
        });
    }
}
