<?php

namespace Tests\Tenant;

use App\Crm\Config\FuseCrmConfig;
use App\Facades\Settings;
use App\Master\Models\VehicleMake;
use App\Services\FuseCrmApi;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
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\NewCar;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\MercuryDataModels\VehicleOffer;
use Mtc\MercuryDataModels\VehicleValuation;
use Mtc\VehicleReservations\Reservation;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class FuseCrmTest extends TenantTestCase
{
    use UserForTenant;

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

        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Fuse',
            'name' => 'Fuse domain',
            'config_key' => 'fuse-crm-domain',
            'type' => 'string',
            'value' => 'https://foo.com',
        ]);

        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Fuse',
            'name' => 'Client ID',
            'config_key' => 'fuse-crm-client-id',
            'type' => 'string',
            'value' => 'foo_client_id',
        ]);

        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Fuse',
            'name' => 'Client Secret',
            'config_key' => 'fuse-crm-client-secret',
            'type' => 'secret',
            'value' => 'foo_client_secret',
        ]);

        /** @var FuseCrmConfig $config */
        $config = App::make(FuseCrmConfig::class);
        $this->assertFalse($config->enabled());
        $this->assertEquals('https://foo.com', $config->apiDomain());
        $this->assertEquals('foo_client_id', $config->clientId());
        $this->assertEquals('foo_client_secret', $config->clientSecret());
    }

    public function testToken()
    {
        $this->addSettingsAndHttpFake();

        (new FuseCrmApi(App::make(FuseCrmConfig::class)))->sendLead(new Enquiry(), new EnquiryAction());

        Http::assertSent(fn(Request $request) => $request->url() === 'https://foo.com/api/token'
        && $request->data()['client_id'] == 'foo_client_id'
        && $request->data()['client_secret'] == 'foo_client_secret');
    }

    public function testSendLead()
    {
        $this->addSettingsAndHttpFake();

        $q1 = FormQuestion::factory()->create(['data' => ["fuse-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["fuse-field" => "surname"]]);
        $q3 = FormQuestion::factory()->create(['data' => ["fuse-field" => "phone"]]);
        $q4 = FormQuestion::factory()->create(['data' => ["fuse-field" => "email"]]);
        $q5 = FormQuestion::factory()->create(['data' => ["fuse-field" => "customer_comments"]]);

        $enquiry = Enquiry::factory()->create([
            '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'],
            ],
            'source' => 'test.com',
        ]);

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

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

        Http::assertSent(function (Request $request) {
            return Str::contains($request->url(), 'https://foo.com/api/enquiry')
                && $request['forename'] === 'Peter'
                && $request['surname'] === 'Parker'
                && $request['email'] === 'foo@bar.com'
                && $request['phone'] === '00000111222'
                && $request['customer_comments'] == 'my_message';
        });

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

    public function testSendLeadForVehicle()
    {
        $this->addSettingsAndHttpFake();

        $q1 = FormQuestion::factory()->create(['data' => ["fuse-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["fuse-field" => "surname"]]);
        $q3 = FormQuestion::factory()->create(['data' => ["fuse-field" => "phone"]]);
        $q4 = FormQuestion::factory()->create(['data' => ["fuse-field" => "email"]]);
        $q5 = FormQuestion::factory()->create(['data' => ["fuse-field" => "customer_comments"]]);
        $make = VehicleMake::factory()->create(['name' => 'Audi']);
        $model = VehicleModel::factory()->create(['name' => 'A6']);
        $vehicle = Vehicle::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'type' => 'car',
            'is_new' => 0,
            'price' => 12345,
            'registration_number' => 'FO25 FAZ',
            'vrm_condensed' => 'FO25FAZ',
            'cap_id' => 12311
        ]);

        $enquiry = Enquiry::factory()->create([
            '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'],
            ],
            'source' => 'test.com',
        ]);
        $enquiry->objects()->create([
            'object_id' => $vehicle->id,
            'object_type' => $vehicle->getMorphClass(),
        ]);

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

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

        Http::assertSent(function (Request $request) {
            return Str::contains($request->url(), 'https://foo.com/api/enquiry')
                && $request['forename'] === 'Peter'
                && $request['surname'] === 'Parker'
                && $request['email'] === 'foo@bar.com'
                && $request['phone'] === '00000111222'
                && $request['car_or_van'] === 'car'
                && $request['sale_type'] === 'Used'
                && $request['vehicle_interest'] === 'Audi'
                && $request['vehicle_model'] === 'A6'
                && $request['vehicle_type'] === 'FO25FAZ'
                && $request['vehicle_cap_id'] == 12311
                && $request['loan_amount'] == 12345
                && $request['customer_comments'] == 'my_message';
        });

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

    public function testSendLeadForOffer()
    {
        $this->addSettingsAndHttpFake();

        $q1 = FormQuestion::factory()->create(['data' => ["fuse-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["fuse-field" => "surname"]]);
        $q3 = FormQuestion::factory()->create(['data' => ["fuse-field" => "phone"]]);
        $q4 = FormQuestion::factory()->create(['data' => ["fuse-field" => "email"]]);
        $q5 = FormQuestion::factory()->create(['data' => ["fuse-field" => "customer_comments"]]);
        $make = VehicleMake::factory()->create(['name' => 'Audi']);
        $model = VehicleModel::factory()->create(['name' => 'A6']);
        $vehicle = VehicleOffer::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'name' => 'Foo Faz Deluxe',
            'cap_id' => 12311,
        ]);

        $enquiry = Enquiry::factory()->create([
            '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'],
            ],
            'source' => 'test.com',
        ]);
        $enquiry->objects()->create([
            'object_id' => $vehicle->id,
            'object_type' => $vehicle->getMorphClass(),
        ]);

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

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

        Http::assertSent(function (Request $request) {
            return Str::contains($request->url(), 'https://foo.com/api/enquiry')
                && $request['forename'] === 'Peter'
                && $request['surname'] === 'Parker'
                && $request['email'] === 'foo@bar.com'
                && $request['phone'] === '00000111222'
                && $request['sale_type'] === 'New'
                && $request['vehicle_interest'] === 'Audi'
                && $request['vehicle_model'] === 'A6'
                && $request['vehicle_type'] === 'Foo Faz Deluxe'
                && $request['vehicle_cap_id'] == 12311
                && $request['customer_comments'] == 'my_message';
        });

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

    public function testSendLeadForNewCar()
    {
        $this->addSettingsAndHttpFake();

        $q1 = FormQuestion::factory()->create(['data' => ["fuse-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["fuse-field" => "surname"]]);
        $q3 = FormQuestion::factory()->create(['data' => ["fuse-field" => "phone"]]);
        $q4 = FormQuestion::factory()->create(['data' => ["fuse-field" => "email"]]);
        $q5 = FormQuestion::factory()->create(['data' => ["fuse-field" => "customer_comments"]]);
        $make = VehicleMake::factory()->create(['name' => 'Audi']);
        $model = VehicleModel::factory()->create(['name' => 'A6']);
        $vehicle = NewCar::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'name' => 'Foo Faz Deluxe',
            'price' => 99448
        ]);

        $enquiry = Enquiry::factory()->create([
            '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'],
            ],
            'source' => 'test.com',
        ]);
        $enquiry->objects()->create([
            'object_id' => $vehicle->id,
            'object_type' => $vehicle->getMorphClass(),
        ]);

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

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

        Http::assertSent(function (Request $request) {
            return Str::contains($request->url(), 'https://foo.com/api/enquiry')
                && $request['forename'] === 'Peter'
                && $request['surname'] === 'Parker'
                && $request['email'] === 'foo@bar.com'
                && $request['phone'] === '00000111222'
                && $request['sale_type'] === 'New'
                && $request['vehicle_interest'] === 'Audi'
                && $request['vehicle_model'] === 'A6'
                && $request['vehicle_type'] === 'Foo Faz Deluxe'
                && $request['loan_amount'] == 99448
                && $request['customer_comments'] == 'my_message';
        });

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

    public function testSendLeadForValuation()
    {
        $this->addSettingsAndHttpFake();

        $q1 = FormQuestion::factory()->create(['data' => ["fuse-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["fuse-field" => "surname"]]);
        $q3 = FormQuestion::factory()->create(['data' => ["fuse-field" => "phone"]]);
        $q4 = FormQuestion::factory()->create(['data' => ["fuse-field" => "email"]]);
        $q5 = FormQuestion::factory()->create(['data' => ["fuse-field" => "customer_comments"]]);
        $valuation = VehicleValuation::query()->create([
            'provider' => 'foo',
            'registration' => 'FO25FAZ',
            'mileage' => 25000,
            'make' => 'Ford',
            'model' => 'Focus',
            'average_price' => 99448,
            'cosmetic_condition' => 'good',
        ]);

        $enquiry = Enquiry::factory()->create([
            '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'],
            ],
            'source' => 'test.com',
        ]);
        $enquiry->objects()->create([
            'object_id' => $valuation->id,
            'object_type' => $valuation->getMorphClass(),
        ]);

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

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

        Http::assertSent(function (Request $request) {
            return Str::contains($request->url(), 'https://foo.com/api/enquiry')
                && $request['forename'] === 'Peter'
                && $request['surname'] === 'Parker'
                && $request['email'] === 'foo@bar.com'
                && $request['phone'] === '00000111222'
                && Str::contains($request['customer_comments'], 'Ford')
                && Str::contains($request['customer_comments'], 'Focus')
                && Str::contains($request['customer_comments'], 99448)
                && Str::contains($request['customer_comments'], 'my_message')
                && Str::contains($request['customer_comments'], 'condition good');
        });

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

    public function testSendLeadForReservation()
    {
        $this->addSettingsAndHttpFake();

        $make = VehicleMake::factory()->create(['name' => 'Audi']);
        $model = VehicleModel::factory()->create(['name' => 'A6']);
        $vehicle = Vehicle::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'type' => 'car',
            'is_new' => 0,
            'price' => 12345,
            'registration_number' => 'FO25 FAZ',
            'vrm_condensed' => 'FO25FAZ',
            'cap_id' => 12311
        ]);

        $reservation = Reservation::factory()->create([
            'contact_number' => 1231231122,
            'email' => 'foo@faz.com',
            'vehicle_id' => $vehicle->id,
            'name' => 'Peter Parker',
        ]);

        $enquiry_action = Enquiries::makeAction('send-to-fuse');
        $enquiry_action->sendReservation($reservation);

        Http::assertSent(function (Request $request) {
            return Str::contains($request->url(), 'https://foo.com/api/enquiry')
                && $request['forename'] === 'Peter'
                && $request['surname'] === 'Parker'
                && $request['email'] === 'foo@faz.com'
                && $request['phone'] === 1231231122
                && $request['car_or_van'] === 'car'
                && $request['sale_type'] === 'Used'
                && $request['vehicle_interest'] === 'Audi'
                && $request['vehicle_model'] === 'A6'
                && $request['loan_amount'] == 12345
                && $request['vehicle_type'] === 'FO25FAZ'
                && $request['vehicle_cap_id'] === '12311'
                && stripos($request['customer_comments'], 'Reservation') !== false
                && stripos($request['customer_comments'], 'Payment reference') !== false;
        });

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

    public function testMarketing()
    {
        $this->addSettingsAndHttpFake();

        $q1 = FormQuestion::factory()->create(['data' => ["fuse-field" => "forename"]]);
        $q2 = FormQuestion::factory()->create(['data' => ["fuse-field" => "surname"]]);
        $q3 = FormQuestion::factory()->create(['data' => ["fuse-field" => "phone"]]);
        $q4 = FormQuestion::factory()->create(['data' => ["fuse-field" => "email"]]);
        $q5 = FormQuestion::factory()->create(['data' => ["fuse-field" => "agreeMarketing"]]);

        $enquiry = Enquiry::factory()->create([
            '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' => null],
            ],
            'source' => 'test.com',
        ]);

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

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

        Http::assertSent(function (Request $request) {
            return Str::contains($request->url(), 'https://foo.com/api/enquiry')
                && $request['forename'] === 'Peter'
                && $request['surname'] === 'Parker'
                && $request['email'] === 'foo@bar.com'
                && $request['phone'] === '00000111222'
                // ensure that null answer was converted to boolean false
                && $request['agreeMarketing'] === false;
        });
    }

    private function addSettingsAndHttpFake()
    {
        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Fuse',
            'name' => 'Enabled',
            'config_key' => 'fuse-crm-enabled',
            'type' => 'boolean',
            'value' => false,
        ]);

        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Fuse',
            'name' => 'Fuse domain',
            'config_key' => 'fuse-crm-domain',
            'type' => 'string',
            'value' => 'https://foo.com',
        ]);

        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Fuse',
            'name' => 'Client ID',
            'config_key' => 'fuse-crm-client-id',
            'type' => 'string',
            'value' => 'foo_client_id',
        ]);

        Settings::make([
            'tab' => 'CRM',
            'section' => 'Integrations',
            'group' => 'Fuse',
            'name' => 'Client Secret',
            'config_key' => 'fuse-crm-client-secret',
            'type' => 'secret',
            'value' => 'foo_client_secret',
        ]);

        Http::fake([
            '*/token' => Http::response([
                'access_token' => 'ABC123'
            ]),
            '*' => Http::response(null, 400),
        ]);
    }
}
