<?php

namespace Tests\Unit\Services;

use App\Crm\Config\DealerWebConfig;
use App\Facades\Settings;
use App\Services\DealershipDetection;
use App\Services\DealerWebLmsApi;
use Illuminate\Foundation\Testing\RefreshDatabase;
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\Vehicle;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleValuation;
use Tests\TestCase;

class DealerWebLmsApiTest extends TestCase
{
    use RefreshDatabase;
    protected $tenancy = true;


    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->setAccessible(true);
        $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->setAccessible(true);
        $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->setAccessible(true);
        $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(function(Request $request) {
            return 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(function(Request $request) use ($vehicle_make, $vehicle_model) {
            return 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(function(Request $request) {
            return Str::contains($request->body(), '<DealerNo>example_dealerweb_id</DealerNo>');
        });
    }

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

    protected function tearDown(): void
    {
        parent::tearDown();

        Mockery::close();
    }
}
