<?php

namespace Tests\Tenant;

use App\Crm\Config\DealerKitCrmConfig;
use App\Facades\Settings;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Http;
use Mtc\Crm\Facades\Enquiries;
use Mtc\Crm\Models\Enquiry;
use Mtc\Crm\Models\EnquiryAction;
use Mtc\Crm\Models\FormQuestion;
use Mtc\MercuryDataModels\ApiNotification;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleValuation;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class SendEnquiryToDealerKitTest extends TenantTestCase
{
    use UserForTenant;

    private const TEST_LEADS_ENDPOINT = 'https://api.dealerkit.test/integrators/leads';

    public function testEnabledReflectsCrmToggle()
    {
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'DealerKit',
            'name' => 'CRM enabled',
            'config_key' => 'dealerkit-crm-enabled',
            'type' => 'boolean',
            'value' => false,
        ]);

        /** @var DealerKitCrmConfig $config */
        $config = App::make(DealerKitCrmConfig::class);
        $this->assertFalse($config->enabled());

        Settings::update('dealerkit-crm-enabled', true);
        $this->assertTrue($config->enabled());
    }

    public function testSendLeadPostsExpectedPayload()
    {
        $this->addDealerKitSettings();
        Http::fake([
            self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'LEAD-123']], 201),
        ]);

        $vehicle = $this->makeDealerKitVehicle('vehicle-uuid-abc');
        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions($vehicle);

        $result = Enquiries::makeAction('send-to-dealerkit')->handle($action, $enquiry);

        $this->assertTrue($result);

        Http::assertSent(function (Request $request) {
            $payload = $request->data();
            return $request->url() === self::TEST_LEADS_ENDPOINT
                && $request->hasHeader('Authorization', 'Bearer test_secret')
                && $payload['type'] === 'sales'
                && $payload['stock_listing_id'] === 'vehicle-uuid-abc'
                && $payload['person']['first_name'] === 'Peter'
                && $payload['person']['last_name'] === 'Parker'
                && $payload['person']['email'] === 'foo@bar.com'
                && $payload['person']['telephone'] === '00000111222'
                && $payload['person']['marketing_consent']['email'] === true
                && $payload['person']['marketing_consent']['sms'] === false
                && $payload['person']['marketing_consent']['telephone'] === false
                && !empty($payload['person']['updated_at'])
                && $payload['message']['plain'] === 'my_message';
        });

        $this->assertCount(1, ApiNotification::query()->where('provider', 'dealerkit-crm')->get());
    }

    public function testPreferredContactMethodsMapToMarketingConsentChannels()
    {
        $this->addDealerKitSettings();
        Http::fake([
            self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'LEAD-PC']], 201),
        ]);

        $vehicle = $this->makeDealerKitVehicle('uuid-pc');
        $question = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'preferredContactMethods']]);
        $enquiry = Enquiry::factory()->create([
            'email' => 'a@b.com',
            'details' => [$question->id => ['answer' => 'email,phone']],
        ]);
        $enquiry->objects()->create([
            'object_id' => $vehicle->id,
            'object_type' => $vehicle->getMorphClass(),
        ]);
        $action = EnquiryAction::factory()->create([
            'action_name' => 'send-to-dealerkit',
            'data' => [],
            'processed_at' => null,
            'failed_at' => null,
        ]);

        Enquiries::makeAction('send-to-dealerkit')->handle($action, $enquiry);

        Http::assertSent(function (Request $request) {
            $consent = $request->data()['person']['marketing_consent'];
            return $consent['email'] === true
                && $consent['telephone'] === true
                && $consent['sms'] === false;
        });
    }

    public function testSendLeadOmitsEmptyOptionalKeys()
    {
        $this->addDealerKitSettings();
        Http::fake([
            self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'LEAD-X']], 201),
        ]);

        $vehicle = $this->makeDealerKitVehicle('uuid-2');
        $q1 = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'person.first_name']]);
        $q2 = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'person.last_name']]);
        $enquiry = Enquiry::factory()->create([
            'email' => 'a@b.com',
            'details' => [
                $q1->id => ['answer' => 'Jane'],
                $q2->id => ['answer' => 'Doe'],
            ],
        ]);
        $enquiry->objects()->create([
            'object_id' => $vehicle->id,
            'object_type' => $vehicle->getMorphClass(),
        ]);
        $action = EnquiryAction::factory()->create([
            'action_name' => 'send-to-dealerkit',
            'data' => [],
            'processed_at' => null,
            'failed_at' => null,
        ]);

        Enquiries::makeAction('send-to-dealerkit')->handle($action, $enquiry);

        Http::assertSent(function (Request $request) {
            $payload = $request->data();
            return !array_key_exists('part_exchange', $payload)
                && !array_key_exists('note', $payload)
                && !array_key_exists('message', $payload)
                && !array_key_exists('tracking', $payload)
                && !array_key_exists('email', $payload['person'])
                && !array_key_exists('telephone', $payload['person'])
                && !array_key_exists('company_name', $payload['person']);
        });
    }

    public function testSendLeadIncludesPartExchangeWhenValuationAttached()
    {
        $this->addDealerKitSettings();
        Http::fake([
            self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'LEAD-PE']], 201),
        ]);

        $vehicle = $this->makeDealerKitVehicle('uuid-pe');
        $valuation = VehicleValuation::query()->create([
            'provider' => 'foo',
            'registration' => 'FO25FAZ',
            'mileage' => 25000,
            'make' => 'Ford',
            'model' => 'Focus',
            'average_price' => 99448,
        ]);

        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions($vehicle);
        $enquiry->objects()->create([
            'object_id' => $valuation->id,
            'object_type' => $valuation->getMorphClass(),
        ]);

        Enquiries::makeAction('send-to-dealerkit')->handle($action, $enquiry);

        Http::assertSent(function (Request $request) {
            $payload = $request->data();
            return ($payload['part_exchange']['vrm'] ?? null) === 'FO25FAZ'
                && ($payload['part_exchange']['mileage'] ?? null) === 25000;
        });
    }

    public function testSendLeadIncludesTrackingFromEnquiryMeta()
    {
        $this->addDealerKitSettings();
        Http::fake([
            self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'LEAD-T']], 201),
        ]);

        $vehicle = $this->makeDealerKitVehicle('uuid-t');
        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions($vehicle, [
            'meta' => [
                'source_url' => 'https://site.test/used-cars/foo',
                'utm_source' => 'google',
                'utm_campaign' => 'spring-sale',
            ],
        ]);

        Enquiries::makeAction('send-to-dealerkit')->handle($action, $enquiry);

        Http::assertSent(function (Request $request) {
            $tracking = $request->data()['tracking'] ?? [];
            return ($tracking['landing_page_url'] ?? null) === 'https://site.test/used-cars/foo'
                && ($tracking['utm_source'] ?? null) === 'google'
                && ($tracking['utm_campaign'] ?? null) === 'spring-sale'
                && !array_key_exists('utm_medium', $tracking)
                && !array_key_exists('referrer', $tracking);
        });
    }

    public function testSkipsWhenNoDealerKitVehicleAttached()
    {
        $this->addDealerKitSettings();
        Http::fake([self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'X']], 201)]);

        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions(null);

        $result = Enquiries::makeAction('send-to-dealerkit')->handle($action, $enquiry);

        $this->assertFalse($result);
        Http::assertNothingSent();

        $notification = ApiNotification::query()->where('provider', 'dealerkit-crm')->first();
        $this->assertNotNull($notification);
        $this->assertFalse((bool) $notification->processed);
        $this->assertEquals(
            'No DealerKit-sourced vehicle or valuation attached to enquiry',
            $notification->data['skipped_reason']
        );
    }

    public function testSkipsWhenAttachedVehicleIsNotDealerKitSourced()
    {
        $this->addDealerKitSettings();
        Http::fake([self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'X']], 201)]);

        $vehicle = Vehicle::factory()->create([
            'stock_provider' => 'auto-trader',
            'uuid' => 'not-dealerkit',
        ]);
        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions($vehicle);

        $result = Enquiries::makeAction('send-to-dealerkit')->handle($action, $enquiry);

        $this->assertFalse($result);
        Http::assertNothingSent();
    }

    public function testSendsBuyingLeadWhenValuationOnlyAttached()
    {
        $this->addDealerKitSettings();
        Http::fake([
            self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'LEAD-BUY']], 201),
        ]);

        $valuation = VehicleValuation::query()->create([
            'provider' => 'foo',
            'registration' => 'VAL25 ABC',
            'mileage' => 42000,
            'make' => 'Ford',
            'model' => 'Focus',
        ]);
        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions(null);
        $enquiry->objects()->create([
            'object_id' => $valuation->id,
            'object_type' => $valuation->getMorphClass(),
        ]);

        $crm = Enquiries::makeAction('send-to-dealerkit');
        $result = $crm->handle($action, $enquiry);

        $this->assertTrue($result);

        Http::assertSent(function (Request $request) {
            $payload = $request->data();
            return $request->url() === self::TEST_LEADS_ENDPOINT
                && $payload['type'] === 'buying'
                && !array_key_exists('stock_listing_id', $payload)
                && !array_key_exists('part_exchange', $payload)
                && ($payload['vehicle']['vrm'] ?? null) === 'VAL25 ABC'
                && ($payload['vehicle']['mileage'] ?? null) === 42000
                && $payload['person']['first_name'] === 'Peter'
                && $payload['person']['last_name'] === 'Parker'
                && !empty($payload['person']['updated_at']);
        });

        $this->assertStringContainsString('LEAD-BUY', $crm->successDetails());
    }

    public function testNonDealerKitVehicleWithValuationStillSkips()
    {
        $this->addDealerKitSettings();
        Http::fake([self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'X']], 201)]);

        $vehicle = Vehicle::factory()->create([
            'stock_provider' => 'auto-trader',
            'uuid' => 'not-dealerkit',
        ]);
        $valuation = VehicleValuation::query()->create([
            'provider' => 'foo',
            'registration' => 'AB12CDE',
            'mileage' => 10000,
        ]);
        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions($vehicle);
        $enquiry->objects()->create([
            'object_id' => $valuation->id,
            'object_type' => $valuation->getMorphClass(),
        ]);

        $result = Enquiries::makeAction('send-to-dealerkit')->handle($action, $enquiry);

        $this->assertFalse($result);
        Http::assertNothingSent();

        $notification = ApiNotification::query()->where('provider', 'dealerkit-crm')->first();
        $this->assertEquals(
            'Attached vehicle is not DealerKit-sourced',
            $notification->data['skipped_reason']
        );
    }

    public function testValidationErrorIsExposedAsFailureReason()
    {
        $this->addDealerKitSettings();
        Http::fake([
            self::TEST_LEADS_ENDPOINT => Http::response([
                'message' => 'The given data was invalid.',
                'errors' => [
                    'person.first_name' => ['The first name field is required.'],
                    'stock_listing_id' => ['The stock listing id field is required.'],
                ],
            ], 422),
        ]);

        $vehicle = $this->makeDealerKitVehicle('uuid-422');
        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions($vehicle);

        $crm = Enquiries::makeAction('send-to-dealerkit');
        $result = $crm->handle($action, $enquiry);

        $this->assertFalse($result);

        $reason = $crm->failureReason();
        $this->assertStringContainsString('The given data was invalid', $reason);
        $this->assertStringContainsString('person.first_name', $reason);
        $this->assertStringContainsString('first name field is required', $reason);

        $notification = ApiNotification::query()->where('provider', 'dealerkit-crm')->first();
        $this->assertNotNull($notification);
        $this->assertFalse((bool) $notification->processed);
        $this->assertEquals(422, $notification->data['http_status']);
    }

    public function testNonStandardErrorStatusIsTreatedAsFailure()
    {
        $this->addDealerKitSettings();
        Http::fake([self::TEST_LEADS_ENDPOINT => Http::response('server boom', 500)]);

        $vehicle = $this->makeDealerKitVehicle('uuid-500');
        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions($vehicle);

        $crm = Enquiries::makeAction('send-to-dealerkit');
        $result = $crm->handle($action, $enquiry);

        $this->assertFalse($result);
        $this->assertStringContainsString('500', $crm->failureReason());
    }

    public function testSuccessReferenceExtractedFromResponse()
    {
        $this->addDealerKitSettings();
        Http::fake([
            self::TEST_LEADS_ENDPOINT => Http::response(['data' => ['id' => 'LEAD-XYZ']], 201),
        ]);

        $vehicle = $this->makeDealerKitVehicle('uuid-ok');
        [$enquiry, $action] = $this->makeEnquiryWithStandardQuestions($vehicle);

        $crm = Enquiries::makeAction('send-to-dealerkit');
        $crm->handle($action, $enquiry);

        $this->assertStringContainsString('LEAD-XYZ', $crm->successDetails());
    }

    private function makeDealerKitVehicle(string $uuid): Vehicle
    {
        return Vehicle::factory()->create([
            'stock_provider' => 'dealerkit',
            'uuid' => $uuid,
        ]);
    }

    private function makeEnquiryWithStandardQuestions(?Vehicle $vehicle, array $extraData = []): array
    {
        $q1 = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'person.first_name']]);
        $q2 = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'person.last_name']]);
        $q3 = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'person.telephone']]);
        $q4 = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'person.email']]);
        $q5 = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'message.plain']]);
        $q6 = FormQuestion::factory()->create(['data' => ['dealerkit-field' => 'preferredContactMethods']]);

        $enquiry = Enquiry::factory()->create(array_merge([
            'email' => 'foo@bar.com',
            'details' => [
                $q1->id => ['answer' => 'Peter'],
                $q2->id => ['answer' => 'Parker'],
                $q3->id => ['answer' => '00000111222'],
                $q4->id => ['answer' => 'foo@bar.com'],
                $q5->id => ['answer' => 'my_message'],
                $q6->id => ['answer' => 'email'],
            ],
            'source' => 'test.com',
        ], $extraData ? ['data' => $extraData] : []));

        if ($vehicle) {
            $enquiry->objects()->create([
                'object_id' => $vehicle->id,
                'object_type' => $vehicle->getMorphClass(),
            ]);
        }

        $action = EnquiryAction::factory()->create([
            'action_name' => 'send-to-dealerkit',
            'data' => [],
            'processed_at' => null,
            'failed_at' => null,
        ]);

        return [$enquiry, $action];
    }

    private function addDealerKitSettings(): void
    {
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'DealerKit',
            'name' => 'CRM enabled',
            'config_key' => 'dealerkit-crm-enabled',
            'type' => 'boolean',
            'value' => true,
        ]);

        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'DealerKit',
            'name' => 'API Secret',
            'config_key' => 'dealerkit-crm-api-secret',
            'type' => 'secret',
            'value' => 'test_secret',
        ]);

        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'DealerKit',
            'name' => 'Use live API',
            'config_key' => 'dealerkit-crm-use-live-api',
            'type' => 'boolean',
            'value' => false,
        ]);
    }
}
