<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use App\Modules\Payment\Stripe;
use Mtc\Checkout\Invoice;
use Mtc\Checkout\InvoiceRepository;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;
use Mtc\Stripe\Config\StripeConfig;
use Mtc\VehicleReservations\Reservation;
use Tests\TenantTestCase;

class ReservationTest extends TenantTestCase
{
    public function testReservationData()
    {
        $this->seed();

        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',
        ]);

        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'ABC123',
            'make_id' => $make->id,
            'model_id' => $model->id,
            'is_sold' => false,
            'is_reserved' => false,
            'derivative' => 'foo',
            'price' => 789
        ]);

        $response = $this
            ->postJson('frontend/reservations/' . $vehicle->slug, [
                'name' => 'test',
                'email' => 'test@test.com',
            ]);

        $response->assertStatus(201);

        $this->assertCount(1, Reservation::all());

        $reservation = Reservation::query()->first();
        $expected_string = $vehicle->registration_number . ' ' . $make->name . ' ' . $model->name . ' foo 789';

        $this->assertIsArray($reservation->data);
        $this->assertArrayHasKey('vehicle', $reservation->data);
        $this->assertArrayHasKey('description', $reservation->data['vehicle']);
        $this->assertEquals($expected_string, $reservation->data['vehicle']['description']);
    }

    public function testReservationDataCastsBooleanFieldsToTrue()
    {
        $this->seed();

        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',
        ]);

        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $vehicle = Vehicle::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'is_sold' => false,
            'is_reserved' => false,
        ]);

        $response = $this->postJson('frontend/reservations/' . $vehicle->slug, [
            'name' => 'test',
            'email' => 'test@test.com',
            'customer_has_part_ex' => 'yes',
            'customer_requires_finance' => 'true',
        ]);

        $response->assertStatus(201);

        $reservation = Reservation::query()->first();

        $this->assertTrue($reservation->data['customer_has_part_ex']);
        $this->assertTrue($reservation->data['customer_requires_finance']);
    }

    public function testReservationDataCastsBooleanFieldsToFalse()
    {
        $this->seed();

        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',
        ]);

        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $vehicle = Vehicle::factory()->create([
            'make_id' => $make->id,
            'model_id' => $model->id,
            'is_sold' => false,
            'is_reserved' => false,
        ]);

        $response = $this->postJson('frontend/reservations/' . $vehicle->slug, [
            'name' => 'test',
            'email' => 'test@test.com',
            'customer_has_part_ex' => 'no',
            'customer_requires_finance' => '0',
        ]);

        $response->assertStatus(201);

        $reservation = Reservation::query()->first();

        $this->assertFalse($reservation->data['customer_has_part_ex']);
        $this->assertFalse($reservation->data['customer_requires_finance']);
    }

    public function testPaymentDescription()
    {
        $this->seed();

        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' => 'sales-stripe-payment-description-format',
            'value' => '{make} {model} {derivative} {vrm}',
            'type' => 'string',
        ]);

        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'ABC123',
            'vrm_condensed' => 'ABC123',
            'make_id' => $make->id,
            'model_id' => $model->id,
            'derivative' => 'foo',
            'price' => 789
        ]);

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

        $invoice = Invoice::query()->create([
            'payable_type' => 'reservation',
            'payable_id' => $reservation->id,
            'reference' => 'foo',
            'currency' => 'gbp',
            'outstanding_amount' => 123,
        ]);

        $invoice_repository = new InvoiceRepository();
        $invoice_repository->setModel($invoice);

        $description = new Stripe(new StripeConfig())->paymentDescription($invoice_repository);

        $expected = $vehicle->make->name
            . ' '
            . $vehicle->model->name
            . ' '
            . $vehicle->derivative
            . ' '
            . $vehicle->vrm_condensed;

        $this->assertEquals($expected, $description);
    }

    public function testPaymentDescriptionFallback()
    {
        $this->seed();

        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' => 'sales-stripe-payment-description-format',
            'value' => '',
            'type' => 'string',
        ]);

        $make = VehicleMake::factory()->create();
        $model = VehicleModel::factory()->create();
        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'ABC123',
            'vrm_condensed' => 'ABC123',
            'make_id' => $make->id,
            'model_id' => $model->id,
            'derivative' => 'foo',
            'price' => 789
        ]);

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

        $invoice = Invoice::query()->create([
            'payable_type' => 'reservation',
            'payable_id' => $reservation->id,
            'reference' => 'foo',
            'currency' => 'gbp',
            'outstanding_amount' => 123,
        ]);

        $invoice_repository = new InvoiceRepository();
        $invoice_repository->setModel($invoice);
        $description = new Stripe(new StripeConfig())->paymentDescription($invoice_repository);

        $this->assertStringContainsString('payment on', strtolower($description));
    }

    public function testReservationAmount()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'sales-reserve_price',
            'type' => 'number',
            'value' => 100,
        ]);

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

        $vehicle = Vehicle::factory()->create([
            'type' => 'car',
        ]);

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

        $this->assertEquals(100, $reservation->getAmount());
    }

    public function testReservationAmountLcv()
    {
        Settings::make([
            'tab' => 'foo',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'dolor',
            'config_key' => 'sales-reserve_price',
            'type' => 'number',
            'value' => 100,
        ]);

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

        $vehicle = Vehicle::factory()->create([
            'type' => 'lcv',
        ]);

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

        $this->assertEquals(500, $reservation->getAmount());
    }

    public function testInvoiceAmount()
    {
        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' => 'sales-reserve_price',
            'type' => 'number',
            'value' => 100,
        ]);

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

        $vehicle = Vehicle::factory()->create([
            'type' => 'car',
            'is_sold' => false,
            'is_reserved' => false,
        ]);

        $response = $this
            ->postJson('frontend/reservations/' . $vehicle->slug, [
                'name' => 'test',
                'email' => 'test@test.com',
            ]);

        $response->assertStatus(201);
        $this->assertCount(1, Invoice::all());
        $invoice = Invoice::query()->first();
        $this->assertEquals(100, $invoice->amount);
    }

    public function testInvoiceAmountLcv()
    {
        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' => 'sales-reserve_price',
            'type' => 'number',
            'value' => 100,
        ]);

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

        $vehicle = Vehicle::factory()->create([
            'type' => 'lcv',
            'is_sold' => false,
            'is_reserved' => false,
        ]);

        $response = $this
            ->postJson('frontend/reservations/' . $vehicle->slug, [
                'name' => 'test',
                'email' => 'test@test.com',
            ]);

        $response->assertStatus(201);
        $this->assertCount(1, Invoice::all());
        $invoice = Invoice::query()->first();
        $this->assertEquals(500, $invoice->amount);
    }
}
