<?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\Support\Facades\Http;
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\Vehicle;
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);
    }

    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();
    }
}
