<?php

namespace Tests\Tenant\Services;

use App\Crm\Config\DealerWebConfig;
use App\Facades\Settings;
use App\Services\DealershipDetection;
use App\Services\DealerWebLmsApi;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use Mockery;
use Mtc\Crm\Contracts\EnquiryActionModel;
use Mtc\Crm\Contracts\EnquiryModel;
use Mtc\Crm\Models\Enquiry;
use Mtc\Crm\Models\EnquiryAction;
use Mtc\Crm\Models\FormQuestion;
use Mtc\MercuryDataModels\CarConfiguratorEdition;
use Mtc\MercuryDataModels\CarConfiguratorEngine;
use Mtc\MercuryDataModels\CarConfiguratorExtra;
use Mtc\MercuryDataModels\CarConfiguratorModel;
use Mtc\MercuryDataModels\CarConfiguratorSection;
use Mtc\MercuryDataModels\CustomerCarConfiguration;
use Mtc\MercuryDataModels\CustomerCarConfigurationSection;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\NewCar;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleValuation;
use Tests\TenantTestCase;

class DealerWebLmsApiTest extends TenantTestCase
{
    #[\Override]
    protected function setUp(): void
    {
        parent::setUp();

        // just to be EXTRA careful that no outbound http call would be made
        Http::preventStrayRequests();
    }

    public function testSubmitLead()
    {
        $debugEndpoint = '*';
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => $debugEndpoint,
            'description' => 'Dealer Web LMS endpoint',
        ]);

        // Mock the HTTP response for the DealerWeb LMS API
        Http::fake([
            $debugEndpoint => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>
            '),
            '*' => Http::response([], 400),
        ]);

        $vehicle = Vehicle::factory()->create();

        $q1 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "surname"]]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => 'vehicle',
            'reason_id' => $vehicle->id,
            'email' => 'carlover@example.com',
            'details' => [
                $q1->id => ['answer' => 'Peter'],
                $q2->id => ['answer' => 'Parker'],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                ],
            ]
        ]);
        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'checkup',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $result = $dealerWebApi->sendLead($enquiry, $action);

        $this->assertFalse($result);
    }

    public function testSubmitLeadReturnsFalseIfEndpointIsMissing()
    {
        $mockConfig = Mockery::mock(DealerWebConfig::class);
        $mockDetection = Mockery::mock(DealershipDetection::class);

        $service = new DealerWebLmsApi($mockConfig, $mockDetection);

        $reflection = new \ReflectionClass($service);
        $property = $reflection->getProperty('endpoint');
        $property->setValue($service, '');

        $result = $this->invokeMethod($service, 'submitLead', [['data' => 'test']]);

        $this->assertFalse($result);
    }

    public function testSubmitLeadHandlesMissingAddLeadResult()
    {
        $mockConfig = Mockery::mock(DealerWebConfig::class);
        $mockDetection = Mockery::mock(DealershipDetection::class);

        $service = new DealerWebLmsApi($mockConfig, $mockDetection);

        Http::fake([
            '*' => Http::response('<InvalidResponse></InvalidResponse>', 200),
        ]);

        $reflection = new \ReflectionClass($service);
        $property = $reflection->getProperty('endpoint');
        $property->setValue($service, 'http://example.com');

        $result = $this->invokeMethod($service, 'submitLead', [['data' => 'test']]);
        $this->assertFalse($result);
        $this->assertEquals('AddLeadResult element not found in response', $service->getResponseMessage());
    }

    public function testGetResponseMessage()
    {
        $service = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());

        $reflection = new \ReflectionClass($service);
        $property = $reflection->getProperty('responseMessage');
        $property->setValue($service, 'Test response message');

        $this->assertEquals('Test response message', $service->getResponseMessage());
    }

    public function testSendLead()
    {
        $mockConfig = Mockery::mock(DealerWebConfig::class);
        $mockDetection = Mockery::mock(DealershipDetection::class);

        $service = Mockery::mock(DealerWebLmsApi::class, [$mockConfig, $mockDetection])
            ->makePartial()
            ->shouldAllowMockingProtectedMethods();

        $enquiry = Mockery::mock(EnquiryModel::class);
        $action = Mockery::mock(EnquiryActionModel::class);

        $service->shouldReceive('mapEnquiry')->once()
            ->with($enquiry)
            ->andReturn(['mapped' => 'data']);
        $service->shouldReceive('submitLead')->once()
            ->with(['mapped' => 'data'])
            ->andReturn(true);

        $result = $service->sendLead($enquiry, $action);

        $this->assertTrue($result);
    }

    public function testSendVehicleLeadIsNotSuccessful()
    {
        $debugEndpoint = '*';
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => $debugEndpoint,
            'description' => 'Dealer Web LMS endpoint',
        ]);

        Http::fake([
            $debugEndpoint => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>
            '),
            '*' => Http::response([], 400),
        ]);

        $vehicle = Vehicle::factory()->create();

        $q1 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "surname"]]);
        $q3 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "Ready"]]);
        $q4 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "Marketing"]]);
        $q5 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "Details Content"]]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => 'vehicle',
            'reason_id' => $vehicle->id,
            'email' => 'carlover@example.com',
            'details' => [
                $q1->id => [
                    'answer' => 'Peter',
                ],
                $q2->id => ['answer' => 'Parker'],
                $q3->id => ['answer' => '1'],
                $q4->id => ['answer' => [
                    'sms',
                    'email',
                    'mail'
                ]],
                $q5->id => ['answer' => '0']
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                    $q3->id => [
                        'component' => 'Boolean',
                        'componentName' => 'TextField',
                        'meta' => null,
                        "dealer-web-lms-field" => "something else"
                    ],
                    $q4->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                        'dealer-web-lms-field' => 'marketing_preference'
                    ],
                    $q5->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                        'dealer-web-lms-field' => 'include_in_details_content'
                    ],
                ],
            ]
        ]);
        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'checkup',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $result = $dealerWebApi->sendLead($enquiry, $action);

        $this->assertFalse($result);
    }

    public function testSendValuationLeadNotSuccessful()
    {
        $debugEndpoint = '*';
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => $debugEndpoint,
            'description' => 'Dealer Web LMS endpoint',
        ]);

        Http::fake([
            $debugEndpoint => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>
            '),
            '*' => Http::response([], 400),
        ]);

        $vehicle = Vehicle::factory()->create();

        $valuation = VehicleValuation::factory()->create();

        $q1 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "surname"]]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => 'valuation',
            'reason_id' => $valuation->id,
            'email' => 'carlover@example.com',
            'details' => [
                [
                    'id' => 124,
                    'question' => 'Vehicle',
                    'answer' => $vehicle->id,
                ],
                [
                    'id' => 125,
                    'question' => 'test2',
                    'answer' => 'answer2',
                ],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                ],
            ]
        ]);
        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'checkup',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $result = $dealerWebApi->sendLead($enquiry, $action);

        $this->assertFalse($result);
    }

    public function testMarketing()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'dealerweblms-endpoint',
            'value' => 'foo',
            'type' => 'string',
        ]);

        Http::fake([
            '*' => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>
            '),
        ]);

        $question = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "Marketing"]]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => null,
            'reason_id' => null,
            'email' => 'carlover@example.com',
            'details' => [
                $question->id => ['answer' => [
                    'SMS',
                    'Post'
                ]],
            ],
            'data' => [
                'questions' => [
                    $question->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                        'dealer-web-lms-field' => 'marketing_preference'
                    ],
                ],
            ]
        ]);

        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'checkup',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $dealerWebApi->sendLead($enquiry, $action);

        Http::assertSent(fn(Request $request) => Str::contains($request->body(), '<NoSMS></NoSMS>')
            && Str::contains($request->body(), '<NoMail></NoMail>')
            && Str::contains($request->body(), '<NoEmail>1</NoEmail>'));
    }

    public function testCarConfiguration()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'dealerweblms-endpoint',
            'value' => 'foo',
            'type' => 'string',
        ]);

        Http::fake([
            '*' => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>
            '),
        ]);

        $vehicle_make = VehicleMake::factory()->create();
        $vehicle_model = VehicleModel::factory()->create([
            'make_id' => $vehicle_make->id,
        ]);
        $model = CarConfiguratorModel::factory()->create([
            'make_id' => $vehicle_make->id,
            'model_id' => $vehicle_model->id,
        ]);
        $config_section_editions = CarConfiguratorSection::factory()->create([
            'model_id' => $model->id,
            'name' => 'Editions',
        ]);
        $config_section_engines = CarConfiguratorSection::factory()->create([
            'model_id' => $model->id,
            'name' => 'Engines',
        ]);
        $config_section_extras = CarConfiguratorSection::factory()->create([
            'model_id' => $model->id,
            'name' => 'Extras',
        ]);
        $edition = CarConfiguratorEdition::factory()->create([
            'model_id' => $model->id,
            'name' => 'super',
        ]);
        $engine = CarConfiguratorEngine::factory()->create([
            'model_id' => $model->id,
            'name' => '2.0 diesel',
        ]);
        $extra_foo = CarConfiguratorExtra::factory()->create([
            'name' => 'foo',
        ]);
        CarConfiguratorExtra::factory()->create([
            'name' => 'bar',
        ]);
        $extra_baz = CarConfiguratorExtra::factory()->create([
            'name' => 'baz',
        ]);
        $car_configuration = CustomerCarConfiguration::factory()->create([
            'model_id' => $model->id,
        ]);
        CustomerCarConfigurationSection::query()->create([
            'configuration_id' => $car_configuration->id,
            'section_id' => $config_section_editions->id,
            'details' => [
                'id' => $edition->id,
                'name' => $edition->name,
            ],
        ]);
        CustomerCarConfigurationSection::query()->create([
            'configuration_id' => $car_configuration->id,
            'section_id' => $config_section_engines->id,
            'details' => [
                'id' => $engine->id,
                'name' => $engine->name,
            ],
        ]);
        CustomerCarConfigurationSection::query()->create([
            'configuration_id' => $car_configuration->id,
            'section_id' => $config_section_extras->id,
            'details' => [
                'id' => $extra_foo->id,
                'name' => $extra_foo->name,
            ],
        ]);
        CustomerCarConfigurationSection::query()->create([
            'configuration_id' => $car_configuration->id,
            'section_id' => $config_section_extras->id,
            'details' => [
                'id' => $extra_baz->id,
                'name' => $extra_baz->name,
            ],
        ]);

        $q1 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "surname"]]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => 'car-configuration',
            'reason_id' => $car_configuration->id,
            'email' => 'carlover@example.com',
            'details' => [
                $q1->id => ['answer' => 'Peter'],
                $q2->id => ['answer' => 'Parker'],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                ],
            ]
        ]);

        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'checkup',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $dealerWebApi->sendLead($enquiry, $action);

        Http::assertSent(fn(Request $request) => Str::contains($request->body(), 'Editions: super;')
            && Str::contains($request->body(), 'Engines: 2.0 diesel;')
            && Str::contains($request->body(), 'Extras: foo, baz')
            && Str::contains($request->body(), '<Model>' . $vehicle_make->name . ' ' . $vehicle_model->name . '</Model>')
            && Str::contains($request->body(), '<NewUsed>N</NewUsed>'));
    }

    public function testDealershipFromQuestions()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'dealerweblms-endpoint',
            'value' => 'foo',
            'type' => 'string',
        ]);

        Http::fake([
            '*' => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>
            '),
        ]);

        $dealership = Dealership::factory()->create([
            'data' => [
                'dealerweb-dealer-id' => 'example_dealerweb_id'
            ],
        ]);

        $question = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "DealerNo"]]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => null,
            'reason_id' => null,
            'email' => 'carlover@example.com',
            'details' => [
                $question->id => ['answer' => $dealership->id],
            ],
            'data' => [
                'questions' => [
                    $question->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                        'dealer-web-lms-field' => 'DealerNo'
                    ],
                ],
            ]
        ]);

        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'checkup',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $dealerWebApi->sendLead($enquiry, $action);

        Http::assertSent(fn(Request $request) => Str::contains($request->body(), '<DealerNo>example_dealerweb_id</DealerNo>'));
    }

    public function testValuationLead()
    {
        $debugEndpoint = '*';
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => $debugEndpoint,
            'description' => 'Dealer Web LMS endpoint',
        ]);

        Settings::make([
            'tab' => 'Site',
            'section' => 'General',
            'group' => 'Site Details',
            'name' => 'Site Currency',
            'config_key' => 'app-details-currency',
            'value' => 'GBP',
            'type' => 'string',
        ]);

        Http::fake([
            $debugEndpoint => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>', 200),
        ]);

        $valuation = VehicleValuation::factory()->create([
            'make' => 'foo',
            'model' => 'bar',
            'registration' => 'abc123',
            'mileage' => 123000,
            'clean_price' => 333,
            'average_price' => 222,
            'below_price' => 111,
        ]);

        $q1 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "surname"]]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => 'valuation',
            'reason_id' => $valuation->id,
            'email' => 'carlover@example.com',
            'details' => [
                [
                    'id' => 125,
                    'question' => 'test2',
                    'answer' => 'answer2',
                ],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                ],
            ]
        ]);
        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'checkup',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $result = $dealerWebApi->sendLead($enquiry, $action);

        $this->assertTrue($result);

        Http::assertSent(fn(Request $request) => Str::contains($request->body(), '<PexMake>foo</PexMake>')
            && Str::contains($request->body(), '<PexModel>bar</PexModel>')
            && Str::contains($request->body(), '<PexMileage>123000</PexMileage>')
            && Str::contains($request->body(), '<PexRegNo>abc123</PexRegNo>')
            && Str::contains($request->body(), 'Valuation: £222'));
    }

    public function testNewCarLead()
    {
        $debugEndpoint = '*';
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => $debugEndpoint,
            'description' => 'Dealer Web LMS endpoint',
        ]);

        Http::fake([
            $debugEndpoint => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>', 200),
        ]);

        $make = VehicleMake::factory()->create([
            'name' => 'foo',
        ]);
        $model = VehicleModel::factory()->create([
            'make_id' => $make->id,
            'name' => 'bar',
        ]);
        $new_car = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'name' => 'baz',
        ]);

        $q1 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["dealer-web-lms-field" => "surname"]]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => 'new-car',
            'reason_id' => $new_car->id,
            'email' => 'carlover@example.com',
            'details' => [
                [
                    'id' => 125,
                    'question' => 'test2',
                    'answer' => 'answer2',
                ],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null
                    ],
                ],
            ]
        ]);
        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'checkup',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $result = $dealerWebApi->sendLead($enquiry, $action);

        $this->assertTrue($result);

        Http::assertSent(function (Request $request) use ($new_car) {
            $expected_model = $new_car->make?->name . ' ' . $new_car->model?->name . ' ' . $new_car->name;

            return Str::contains($request->body(), '<NewUsed>N</NewUsed>')
                && Str::contains($request->body(), '<Model>' . $expected_model . '</Model>');
        });
    }

    public function testSendServiceBooking()
    {
        $debugEndpoint = '*';
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => $debugEndpoint,
            'description' => 'Dealer Web LMS endpoint',
        ]);

        Http::fake([
            $debugEndpoint => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>', 200),
        ]);

        $dealership = Dealership::factory()->create([
            'data' => [
                'dealerweb-dealer-id' => 'test_dealer_123'
            ],
        ]);

        $deliveryOption = \Mtc\MercuryDataModels\BookingDeliveryOption::query()->create([
            'name' => 'foo',
            'description' => 'We collect and deliver your vehicle',
            'price' => 25.00,
        ]);

        $booking = \Mtc\MercuryDataModels\Booking::factory()->create([
            'uuid' => Str::uuid()->toString(),
            'first_name' => 'John',
            'last_name' => 'Smith',
            'email' => 'john.smith@example.com',
            'phone_number' => '07700900123',
            'registration_number' => 'AB12CDE',
            'mileage' => 45000,
            'location_id' => $dealership->id,
            'delivery_option_id' => $deliveryOption->id,
            'booking_time' => '2024-03-15 10:00:00',
            'vehicle_data' => [
                'make' => 'Ford',
                'model' => 'Focus',
                'transmission' => 'Manual',
                'fuel_type' => 'Petrol',
                'manufacture_year' => '2020',
                'registration_date' => '2020-03-01',
            ],
            'data' => [
                'service_plan' => 'yes',
            ],
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $dealerWebApi->sendServiceBooking($booking);

        Http::assertSent(function (Request $request) use ($booking, $dealership, $deliveryOption) {
            $body = $request->body();

            return Str::contains($body, '<Forename>John</Forename>')
                && Str::contains($body, '<Surname>Smith</Surname>')
                && Str::contains($body, '<Email>john.smith@example.com</Email>')
                && Str::contains($body, '<Tel_Mobile>07700900123</Tel_Mobile>')
                && Str::contains($body, '<DealerNo>test_dealer_123</DealerNo>')
                && Str::contains($body, '<LeadType>USE</LeadType>')
                && Str::contains($body, '<Model>Ford Focus</Model>')
                && Str::contains($body, '<NewUsed>U</NewUsed>')
                && Str::contains($body, 'Registration: AB12CDE')
                && Str::contains($body, 'Mileage: 45000')
                && Str::contains($body, 'Delivery Option: foo')
                && Str::contains($body, 'Make: Ford')
                && Str::contains($body, 'Model: Focus')
                && Str::contains($body, 'Transmission: Manual')
                && Str::contains($body, 'Fuel: Petrol')
                && Str::contains($body, 'Service Plan: yes');
        });
    }

    public function testVehicleFromObjects()
    {
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => '*',
            'description' => 'Dealer Web LMS endpoint',
        ]);

        Http::fake([
            '*' => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>', 200),
        ]);

        $make = VehicleMake::factory()->create(['name' => 'BMW']);
        $model = VehicleModel::factory()->create(['name' => 'X5', 'make_id' => $make->id]);
        $dealership = Dealership::factory()->create([
            'data' => ['dealerweb-dealer-id' => 'obj_dealer_123'],
        ]);
        $vehicle = Vehicle::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'dealership_id' => $dealership->id,
            'type' => 'car',
            'is_new' => 0,
            'registration_number' => 'OB25 JVH',
        ]);

        $q1 = FormQuestion::factory()->create(['data' => ['dealer-web-lms-field' => 'Forename']]);
        $q2 = FormQuestion::factory()->create(['data' => ['dealer-web-lms-field' => 'Surname']]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => null,
            'reason_id' => null,
            'email' => 'test@example.com',
            'details' => [
                $q1->id => ['answer' => 'John'],
                $q2->id => ['answer' => 'Doe'],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                    ],
                ],
            ],
        ]);
        $enquiry->objects()->create([
            'object_id' => $vehicle->id,
            'object_type' => $vehicle->getMorphClass(),
        ]);

        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-to-dealer-web-lms',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $result = $dealerWebApi->sendLead($enquiry, $action);

        $this->assertTrue($result);

        Http::assertSent(function (Request $request) use ($make, $model, $vehicle) {
            $body = $request->body();

            return Str::contains($body, '<Model>' . $make->name . ' ' . $model->name . ' ' . $vehicle->vrm_condensed . '</Model>')
                && Str::contains($body, '<NewUsed>U</NewUsed>')
                && Str::contains($body, '<LeadType>USE</LeadType>')
                && Str::contains($body, '<DealerNo>obj_dealer_123</DealerNo>');
        });
    }

    public function testValuationFromObjects()
    {
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => '*',
            'description' => 'Dealer Web LMS endpoint',
        ]);

        Http::fake([
            '*' => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>', 200),
        ]);

        $valuation = VehicleValuation::factory()->create([
            'make' => 'Audi',
            'model' => 'A3',
            'registration' => 'VA25LUE',
            'mileage' => 35000,
        ]);

        $q1 = FormQuestion::factory()->create(['data' => ['dealer-web-lms-field' => 'Forename']]);
        $q2 = FormQuestion::factory()->create(['data' => ['dealer-web-lms-field' => 'Surname']]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => null,
            'reason_id' => null,
            'email' => 'test@example.com',
            'details' => [
                $q1->id => ['answer' => 'Jane'],
                $q2->id => ['answer' => 'Smith'],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                    ],
                ],
            ],
        ]);
        $enquiry->objects()->create([
            'object_id' => $valuation->id,
            'object_type' => $valuation->getMorphClass(),
        ]);

        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-to-dealer-web-lms',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $result = $dealerWebApi->sendLead($enquiry, $action);

        $this->assertTrue($result);

        Http::assertSent(function (Request $request) {
            $body = $request->body();

            return Str::contains($body, '<PexMake>Audi</PexMake>')
                && Str::contains($body, '<PexModel>A3</PexModel>')
                && Str::contains($body, '<PexRegNo>VA25LUE</PexRegNo>')
                && Str::contains($body, '<PexMileage>35000</PexMileage>')
                && Str::contains($body, '<LeadType>USE</LeadType>');
        });
    }

    public function testVehicleAndValuationFromObjects()
    {
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Dealer Web LMS',
            'name' => 'Dealer Web Endpoint',
            'config_key' => 'dealerweblms-endpoint',
            'type' => 'string',
            'value' => '*',
            'description' => 'Dealer Web LMS endpoint',
        ]);

        Http::fake([
            '*' => Http::response('<AddLeadResult>
                <CustomerID>123456</CustomerID>
                <ErrorCode>0</ErrorCode>
                <ErrorMessage />
            </AddLeadResult>', 200),
        ]);

        $make = VehicleMake::factory()->create(['name' => 'Mercedes']);
        $model = VehicleModel::factory()->create(['name' => 'C-Class', 'make_id' => $make->id]);
        $dealership = Dealership::factory()->create([
            'data' => ['dealerweb-dealer-id' => 'combo_dealer_456'],
        ]);
        $vehicle = Vehicle::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'dealership_id' => $dealership->id,
            'type' => 'car',
            'is_new' => 0,
            'registration_number' => 'CO25 MBO',
        ]);

        $valuation = VehicleValuation::factory()->create([
            'make' => 'Ford',
            'model' => 'Fiesta',
            'registration' => 'TR25ADE',
            'mileage' => 60000,
        ]);

        $q1 = FormQuestion::factory()->create(['data' => ['dealer-web-lms-field' => 'Forename']]);
        $q2 = FormQuestion::factory()->create(['data' => ['dealer-web-lms-field' => 'Surname']]);

        $enquiry = Enquiry::factory()->create([
            'reason_type' => $vehicle->getMorphClass(),
            'reason_id' => $vehicle->id,
            'email' => 'test@example.com',
            'details' => [
                $q1->id => ['answer' => 'Bob'],
                $q2->id => ['answer' => 'Jones'],
            ],
            'data' => [
                'questions' => [
                    $q1->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                    ],
                    $q2->id => [
                        'component' => 'TextField',
                        'componentName' => 'TextField',
                        'meta' => null,
                    ],
                ],
            ],
        ]);
        $enquiry->objects()->create([
            'object_id' => $vehicle->id,
            'object_type' => $vehicle->getMorphClass(),
        ]);
        $enquiry->objects()->create([
            'object_id' => $valuation->id,
            'object_type' => $valuation->getMorphClass(),
        ]);

        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-to-dealer-web-lms',
            'attempts' => 5,
            'processed_at' => null,
        ]);

        $dealerWebApi = new DealerWebLmsApi(new DealerWebConfig(), new DealershipDetection());
        $result = $dealerWebApi->sendLead($enquiry, $action);

        $this->assertTrue($result);

        Http::assertSent(function (Request $request) use ($make, $model, $vehicle) {
            $body = $request->body();

            // Vehicle of interest from objects
            return Str::contains($body, '<Model>' . $make->name . ' ' . $model->name . ' ' . $vehicle->vrm_condensed . '</Model>')
                && Str::contains($body, '<NewUsed>U</NewUsed>')
                && Str::contains($body, '<DealerNo>combo_dealer_456</DealerNo>')
                // Part exchange from valuation object
                && Str::contains($body, '<PexMake>Ford</PexMake>')
                && Str::contains($body, '<PexModel>Fiesta</PexModel>')
                && Str::contains($body, '<PexRegNo>TR25ADE</PexRegNo>')
                && Str::contains($body, '<PexMileage>60000</PexMileage>')
                && Str::contains($body, '<LeadType>USE</LeadType>');
        });
    }

    private function invokeMethod(&$object, $methodName, array $parameters = [])
    {
        $reflection = new \ReflectionClass($object::class);
        $method = $reflection->getMethod($methodName);
        return $method->invokeArgs($object, $parameters);
    }

    #[\Override]
    protected function tearDown(): void
    {
        parent::tearDown();

        Mockery::close();
    }
}
