<?php

namespace Tests\Tenant;

use App\Facades\LeaseLabels;
use App\Facades\Settings;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\TransmissionType;
use Mtc\MercuryDataModels\VehicleMake;
use Carbon\Carbon;
use Mtc\MercuryDataModels\KeyloopLeaseVehicleVariant;
use Mtc\MercuryDataModels\Label;
use Mtc\MercuryDataModels\LabelRule;
use Mtc\MercuryDataModels\VehicleModel;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class LeaseLabelRepositoryTest extends TenantTestCase
{
    use UserForTenant;

    public function testShouldRevoke()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-just-arrived-days',
            'value' => '5',
            'type' => 'number',
        ]);

        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'created_at' => Carbon::now()->subWeek(),
        ]);

        /** @var Label $label */
        $label = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [
                'assign_when' => 'just_arrived',
                'revoke_when' => 'not_just_arrived',
            ],
        ]);

        $vehicle->labels()->attach($label->id);

        $this->assertTrue(LeaseLabels::shouldRevoke($vehicle, $label));
    }

    public function testAdvancedLabelRules()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'price_ex_vat_ex_vrt' => 13456,
        ]);

        $vehicle_low_price = KeyloopLeaseVehicleVariant::factory()->create([
            'price_ex_vat_ex_vrt' => 123,
        ]);

        $vehicle_high_price = KeyloopLeaseVehicleVariant::factory()->create([
            'price_ex_vat_ex_vrt' => 98765432,
        ]);

        /** @var Label $label_applicable */
        $label_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [
                'applies_to_lease_vehicles' => true,
            ],
        ]);

        /** @var Label $label_not_applicable */
        $label_not_applicable = Label::query()->create([
            'name' => 'foo2',
            'type' => 'baz2',
            'data' => [],
        ]);

        LabelRule::query()->create(
            [
                'label_id' => $label_applicable->id,
                'condition_field' => 'vehicle_price_min',
                'value_data_type' => 'decimal',
                'condition_value' => 13000
            ]
        );

        LabelRule::query()->create(
            [
                'label_id' => $label_applicable->id,
                'condition_field' => 'vehicle_price_max',
                'value_data_type' => 'decimal',
                'condition_value' => 17000
            ]
        );

        LabelRule::query()->create(
            [
                'label_id' => $label_not_applicable->id,
                'condition_field' => 'vehicle_price_min',
                'value_data_type' => 'decimal',
                'condition_value' => 55000
            ]
        );

        $this->assertNotNull($label_applicable->rules);
        $this->assertNotNull($label_not_applicable->rules);
        $this->assertTrue(LeaseLabels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle, $label_not_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle_low_price, $label_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle_high_price, $label_applicable));
    }

    public function testAdvancedRulesTransmission()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        $transmission_type = TransmissionType::factory()->create();

        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'transmission_id' => $transmission_type->id
        ]);

        $vehicle_not_eligible = KeyloopLeaseVehicleVariant::factory()->create([
            'transmission_id' => $transmission_type->id + 1
        ]);

        /** @var Label $label_applicable */
        $label_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        /** @var Label $label_not_applicable */
        $label_not_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'transmission_id',
            'condition_value' => $transmission_type->id,
            'value_data_type' => 'integer'
        ]);

        LabelRule::query()->create([
            'label_id' => $label_not_applicable->id,
            'condition_field' => 'transmission_id',
            'condition_value' => $transmission_type->id + 1,
            'value_data_type' => 'integer'
        ]);

        $this->assertNotNull($label_applicable->rules);
        $this->assertTrue(LeaseLabels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle, $label_not_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle_not_eligible, $label_applicable));
    }

    public function testAdvancedRulesNotApplicable()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        $transmission_type = TransmissionType::factory()->create();

        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'transmission_id' => $transmission_type->id
        ]);

        /** @var Label $label_applicable */
        $label = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [
                'applies_to_lease_vehicles' => false,
            ],
        ]);

        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'transmission_id',
            'condition_value' => $transmission_type->id,
            'value_data_type' => 'integer'
        ]);

        $this->assertFalse(LeaseLabels::shouldAssign($vehicle, $label));
    }

    public function testAdvancedRulesFuel()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        $fuel_type = FuelType::factory()->create();

        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'fuel_type_id' => $fuel_type->id
        ]);

        $vehicle_not_eligible = KeyloopLeaseVehicleVariant::factory()->create([
            'fuel_type_id' => $fuel_type->id + 1
        ]);

        /** @var Label $label_applicable */
        $label_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        /** @var Label $label_not_applicable */
        $label_not_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'fuel_type_id',
            'condition_value' => $fuel_type->id,
            'value_data_type' => 'integer'
        ]);

        LabelRule::query()->create([
            'label_id' => $label_not_applicable->id,
            'condition_field' => 'fuel_type_id',
            'condition_value' => $fuel_type->id + 1,
            'value_data_type' => 'integer'
        ]);

        $this->assertNotNull($label_applicable->rules);
        $this->assertTrue(LeaseLabels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle, $label_not_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle_not_eligible, $label_applicable));
    }

    public function testAdvancedRulesVehicleType()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

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

        $vehicle_not_eligible = KeyloopLeaseVehicleVariant::factory()->create([
            'type' => 'lcv'
        ]);

        /** @var Label $label_applicable */
        $label_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        /** @var Label $label_not_applicable */
        $label_not_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'vehicle_type',
            'condition_value' => 'car',
            'vehicle_data_type' => 'string'
        ]);

        LabelRule::query()->create([
            'label_id' => $label_not_applicable->id,
            'condition_field' => 'vehicle_type',
            'condition_value' => 'bike',
            'value_data_type' => 'string'
        ]);

        $this->assertNotNull($label_applicable->rules);
        $this->assertTrue(LeaseLabels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle, $label_not_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle_not_eligible, $label_applicable));
    }

    public function testAdvancedRulesActiveRange()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        $vehicle = KeyloopLeaseVehicleVariant::factory()->create();

        /** @var Label $label_applicable */
        $label_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        /** @var Label $label_not_applicable */
        $label_not_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'active_from',
            'condition_value' => Carbon::yesterday(),
            'value_data_type' => 'date'
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'active_to',
            'condition_value' => Carbon::tomorrow(),
            'value_data_type' => 'date'
        ]);

        LabelRule::query()->create([
            'label_id' => $label_not_applicable->id,
            'condition_field' => 'active_from',
            'condition_value' => Carbon::today()->subDays(100),
            'value_data_type' => 'date'
        ]);

        LabelRule::query()->create([
            'label_id' => $label_not_applicable->id,
            'condition_field' => 'active_to',
            'condition_value' => Carbon::today()->subDays(50),
            'value_data_type' => 'date'
        ]);

        $this->assertNotNull($label_applicable->rules);
        $this->assertTrue(LeaseLabels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle, $label_not_applicable));
    }

    public function testAdvancedRulesMakeIds()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        $make = VehicleMake::factory()->create();
        $make2 = VehicleMake::factory()->create();
        $make3 = VehicleMake::factory()->create();

        $vehicle_eligible = KeyloopLeaseVehicleVariant::factory()->create([
            'make_id' => $make->id
        ]);

        $vehicle_not_eligible = KeyloopLeaseVehicleVariant::factory()->create([
            'make_id' => $make3->id
        ]);

        $label = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'make_ids',
            'condition_value' => json_encode([
                $make->id,
                $make2->id
            ]),
            'value_data_type' => 'json'
        ]);

        $this->assertNotNull($label->rules);
        $this->assertTrue(LeaseLabels::shouldAssign($vehicle_eligible, $label));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle_not_eligible, $label));
    }

    public function testAdvancedRulesModelIds()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        $model = VehicleModel::factory()->create();
        $model2 = VehicleModel::factory()->create();
        $model3 = VehicleModel::factory()->create();

        $vehicle_eligible = KeyloopLeaseVehicleVariant::factory()->create([
            'model_id' => $model->id
        ]);

        $vehicle_not_eligible = KeyloopLeaseVehicleVariant::factory()->create([
            'model_id' => $model3->id
        ]);

        /** @var Label $label */
        $label = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'model_ids',
            'condition_value' => json_encode([
                $model->id,
                $model2->id
            ]),
            'value_data_type' => 'json'
        ]);

        $this->assertNotNull($label->rules);
        $this->assertTrue(LeaseLabels::shouldAssign($vehicle_eligible, $label));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle_not_eligible, $label));
    }

    public function testRevokeAdvanced()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-just-arrived-days',
            'value' => '5',
            'type' => 'number',
        ]);

        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'price_ex_vat_ex_vrt' => 25000,
            'created_at' => Carbon::now()->subWeek(),
        ]);

        /** @var Label $label */
        $label = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [
                'revoke_when' => 'not_just_arrived',
            ],
        ]);

        // rule to make label incompatible with vehicle
        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'vehicle_price_max',
            'condition_value' => 11000,
            'value_data_type' => 'decimal'
        ]);

        $vehicle->labels()->attach($label->id);

        $this->assertTrue(LeaseLabels::shouldRevoke($vehicle, $label));
    }

    public function testNoRevoke()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-just-arrived-days',
            'value' => '5',
            'type' => 'number',
        ]);

        // test no revoke eligibility
        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'price_ex_vat_ex_vrt' => 25000,
            'created_at' => Carbon::now(),
        ]);

        /** @var Label $label */
        $label = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [
                'revoke_when' => 'not_just_arrived',
            ],
        ]);

        // rule to make label incompatible with vehicle
        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'vehicle_price_max',
            'condition_value' => 99000,
            'value_data_type' => 'decimal'
        ]);

        $vehicle->labels()->attach($label->id);

        $this->assertFalse(LeaseLabels::shouldRevoke($vehicle, $label));
    }

    public function testNotApplicableRevoke()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-just-arrived-days',
            'value' => '5',
            'type' => 'number',
        ]);

        // test no revoke eligibility
        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'price_ex_vat_ex_vrt' => 25000,
            'created_at' => Carbon::now(),
        ]);

        /** @var Label $label */
        $label = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [
                'revoke_when' => 'not_just_arrived',
                'applies_to_lease_vehicles' => false,
            ],
        ]);

        // rule to make label incompatible with vehicle
        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'vehicle_price_max',
            'condition_value' => 99000,
            'value_data_type' => 'decimal'
        ]);

        $vehicle->labels()->attach($label->id);

        $this->assertTrue(LeaseLabels::shouldRevoke($vehicle, $label));
    }

    public function testAdvancedLabelsExtra()
    {
        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'lease-vehicle-labels-advanced-rules-enabled',
            'value' => 'true',
            'type' => 'bool',
        ]);

        $transmission = TransmissionType::factory()->create();
        $fuel = FuelType::factory()->create();

        $vehicle = KeyloopLeaseVehicleVariant::factory()->create([
            'price_ex_vat_ex_vrt' => 13456,
            'transmission_id' => $transmission->id,
            'fuel_type_id' => $fuel->id,
            'type' => 'car',
        ]);

        /** @var Label $label_applicable */
        $label_applicable = Label::query()->create([
            'name' => 'foo',
            'type' => 'baz',
            'data' => [],
        ]);

        /** @var Label $label_not_applicable */
        $label_not_applicable = Label::query()->create([
            'name' => 'foo2',
            'type' => 'baz2',
            'data' => [],
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'vehicle_price_min',
            'condition_value' => 13000,
            'value_data_type' => 'decimal',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'vehicle_price_max',
            'condition_value' => 17000,
            'value_data_type' => 'decimal',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'active_from',
            'condition_value' => Carbon::yesterday(),
            'value_data_type' => 'date',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'active_to',
            'condition_value' => Carbon::tomorrow(),
            'value_data_type' => 'date',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'transmission_id',
            'condition_value' => $transmission->id,
            'value_data_type' => 'integer',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'fuel_type_id',
            'condition_value' => $fuel->id,
            'value_data_type' => 'integer',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'vehicle_type',
            'condition_value' => 'car',
            'value_data_type' => 'string',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'make_ids',
            'condition_value' => json_encode([
                $vehicle->make_id
            ]),
            'value_data_type' => 'json',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'model_ids',
            'condition_value' => json_encode([
                $vehicle->model_id
            ]),
            'value_data_type' => 'json',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_not_applicable->id,
            'condition_field' => 'vehicle_price_min',
            'condition_value' => 55000,
            'value_data_type' => 'integer',
        ]);

        $this->assertNotNull($label_applicable->rules);
        $this->assertNotNull($label_not_applicable->rules);
        $this->assertTrue(LeaseLabels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(LeaseLabels::shouldAssign($vehicle, $label_not_applicable));
    }
}
