<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Carbon\Carbon;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\ApiNotification;
use Mtc\MercuryDataModels\Setting;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\VehicleReservations\Jobs\ProcessIncomingReservationJob;
use Mtc\VehicleReservations\Reservation;
use Tests\TenantTestCase;

class KeyloopApiTest extends TenantTestCase
{
    protected bool $useTestSettingRepository = false;

    public function testReserve()
    {
        Event::fake();
        ApiNotification::query()->delete();
        VehicleAttribute::query()->where('slug', 'keyloop-id')->delete();
        Setting::query()->whereIn('config_key', [
            'keyloop-reservations-enabled',
            'keyloop-reservations-client-id',
            'keyloop-reservations-client-secret',
            'keyloop-reservations-enterprise-id',
        ])->delete();

        Http::fake([
            "https://api.eu.keyloop.io/oauth/client_credential/accesstoken?grant_type=client_credentials"
            => Http::response($this->tokenResponse()),
            "https://api.eu.keyloop.io/buzz/*"
            => Http::response([], 200),
            "*" => Http::response([], 400),
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'app-details-currency',
            'value' => 'GBC',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'sales-stripe-public_key',
            'value' => 'foo',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-client-id',
            'value' => 'test-client-id',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-client-secret',
            'value' => 'test-client-secret',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-enterprise-id',
            'value' => 'buzz',
            'type' => 'string',
        ]);

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

        $vehicle = Vehicle::factory()->create([
            'dealership_id' => $dealership->id,
            'registration_number' => 'ABC123',
            'vrm_condensed' => 'ABC123',
            'derivative' => 'foo',
            'price' => 789
        ]);

        $vehicle_attribute = VehicleAttribute::factory()->create([
            'slug' => 'keyloop-id',
        ]);

        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'slug' => $vehicle_attribute->slug,
            'value' => 'bar',
        ]);

        $reservation = Reservation::factory()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'ingested_at' => null,
        ]);

        // local datetime
        Carbon::setTestNow('2013-09-01 10:20:30.654321');

        // expecting datetime to be converted to UTC and formated Y-m-dTH:i:s.vZ
        $expected_datetime = '2013-09-01T09:20:30.654Z';

        new ProcessIncomingReservationJob($reservation)->handle();

        $expected_url = 'https://api.eu.keyloop.io/buzz/foo/v1/inventory-vehicles/bar/reserve';

        Http::assertSent(function (Request $request) use ($expected_url, $expected_datetime) {
            if (Str::contains($request->url(), 'inventory')) {
                $request_data = json_decode($request->body(), true);
                return $request->url() == $expected_url
                    && $request_data['reservation']['reservationDate'] == $expected_datetime
                    && is_array($request_data['reservation']['reservedBy'])
                    && array_key_exists('salesPersonId', $request_data['reservation']['reservedBy'])
                    && array_key_exists('name', $request_data['reservation']['reservedBy']);
            }

            return false;
        });

        $notifications = ApiNotification::all();
        $this->assertCount(1, $notifications);
        $this->assertEquals($expected_url, $notifications->first()->data['url']);
        $this->assertEquals('200', $notifications->first()->data['status_code']);
    }

    public function testReserveWithSalesperson()
    {
        Event::fake();
        ApiNotification::query()->delete();
        VehicleAttribute::query()->where('slug', 'keyloop-id')->delete();
        Setting::query()->whereIn('config_key', [
            'keyloop-reservations-enabled',
            'keyloop-reservations-client-id',
            'keyloop-reservations-client-secret',
            'keyloop-reservations-enterprise-id',
            'keyloop-reservations-salesperson-name',
            'keyloop-reservations-salesperson-id',
        ])->delete();

        Http::fake([
            "https://api.eu.keyloop.io/oauth/client_credential/accesstoken?grant_type=client_credentials"
            => Http::response($this->tokenResponse()),
            "https://api.eu.keyloop.io/buzz/*"
            => Http::response([], 200),
            "*" => Http::response([], 400),
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'app-details-currency',
            'value' => 'GBC',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'sales-stripe-public_key',
            'value' => 'foo',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-enabled',
            'value' => true,
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-client-id',
            'value' => 'test-client-id',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-client-secret',
            'value' => 'test-client-secret',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-enterprise-id',
            'value' => 'buzz',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-salesperson-name',
            'value' => 'bob',
            'type' => 'string',
        ]);

        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'keyloop-reservations-salesperson-id',
            'value' => '789',
            'type' => 'string',
        ]);

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

        $vehicle = Vehicle::factory()->create([
            'dealership_id' => $dealership->id,
            'registration_number' => 'ABC123',
            'vrm_condensed' => 'ABC123',
            'derivative' => 'foo',
            'price' => 789
        ]);

        $vehicle_attribute = VehicleAttribute::factory()->create([
            'slug' => 'keyloop-id',
        ]);

        VehicleAttributeValue::factory()->create([
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'slug' => $vehicle_attribute->slug,
            'value' => 'bar',
        ]);

        $reservation = Reservation::factory()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'ingested_at' => null,
        ]);

        // local datetime
        Carbon::setTestNow('2013-09-01 10:20:30.654321');

        // expecting datetime to be converted to UTC and formated Y-m-dTH:i:s.vZ
        $expected_datetime = '2013-09-01T09:20:30.654Z';

        new ProcessIncomingReservationJob($reservation)->handle();

        $expected_url = 'https://api.eu.keyloop.io/buzz/foo/v1/inventory-vehicles/bar/reserve';

        Http::assertSent(function (Request $request) use ($expected_url, $expected_datetime) {
            if (Str::contains($request->url(), 'inventory')) {
                $request_data = json_decode($request->body(), true);
                return $request->url() == $expected_url
                    && $request_data['reservation']['reservationDate'] == $expected_datetime
                    && $request_data['reservation']['reservedBy']['salesPersonId'] == '789'
                    && $request_data['reservation']['reservedBy']['name'] == 'bob';
            }

            return false;
        });

        $notifications = ApiNotification::all();
        $this->assertCount(1, $notifications);
        $this->assertEquals($expected_url, $notifications->first()->data['url']);
        $this->assertEquals('200', $notifications->first()->data['status_code']);
    }

    private function tokenResponse()
    {
        return json_encode([
            'access_token' => 'foo123',
        ]);
    }
}
