<?php

namespace Tests\Feature;

use App\Facades\Labels;
use App\Facades\Settings;
use App\Master\Models\FuelType;
use App\Master\Models\TransmissionType;
use App\Master\Models\VehicleMake;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\Label;
use Mtc\MercuryDataModels\LabelRule;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\MercuryDataModels\VehicleAttribute;
use Mtc\MercuryDataModels\VehicleAttributeValue;
use Mtc\MercuryDataModels\VehicleModel;
use Tests\TestCase;
use Tests\UserForTenant;

class LabelRepositoryTest extends TestCase
{
    use RefreshDatabase;
    use UserForTenant;

    protected $tenancy = true;

    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testGetOptions()
    {
        $options = Labels::getAutomationOptions();
        $this->assertIsArray($options);
        $this->assertArrayHasKey('id', $options[0]);
        $this->assertArrayHasKey('name', $options[0]);
    }


    public function testShouldRevoke()
    {
        $vehicle = Vehicle::factory()->create([
            'available_date' => Carbon::now()->subWeek(),
        ]);

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

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

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

    public function testAvailableDateInFuture()
    {

        $vehicle = Vehicle::factory()->create([
            'available_date' => Carbon::now()->addWeek(),
        ]);

        $vehicle2 = Vehicle::factory()->create([
            'available_date' => Carbon::now()->subWeek(),
        ]);

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

        $this->assertTrue(Labels::shouldAssign($vehicle, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle2, $label));

        // Don't assign when already assigned
        $vehicle->labels()->attach($label->id);
        $this->assertFalse(Labels::shouldAssign($vehicle, $label));
    }

    public function testAvailableDateInPast()
    {
        $vehicle = Vehicle::factory()->create([
            'available_date' => Carbon::now()->subWeek(),
        ]);

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

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

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

    public function testIsReserved()
    {
        $vehicle = Vehicle::factory()->create([
            'is_reserved' => true,
        ]);

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

        $this->assertTrue(Labels::shouldAssign($vehicle, $label));
    }

    public function testIsDemo()
    {
        $vehicle = Vehicle::factory()->create([
            'is_demo' => true,
        ]);

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

        $this->assertTrue(Labels::shouldAssign($vehicle, $label));

    }

    public function testIsNew()
    {
        $vehicle = Vehicle::factory()->create([
            'is_new' => true,
        ]);

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

        $this->assertTrue(Labels::shouldAssign($vehicle, $label));

    }

    public function testHasPersonalizedNumberPlate()
    {
        $vehicle = Vehicle::factory()->create([
            'personalized_number_plate' => true,
        ]);

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

        $this->assertTrue(Labels::shouldAssign($vehicle, $label));

    }

    public function testHasReducedPrice()
    {
        $vehicle = Vehicle::factory()->create([
            'original_price' => 23456,
            'price' => 13456,
        ]);

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

        $this->assertTrue(Labels::shouldAssign($vehicle, $label));

    }

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

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

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

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

        /** @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',
                '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(Labels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle, $label_not_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle_low_price, $label_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle_high_price, $label_applicable));
    }

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

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

        $vehicle = Vehicle::factory()->create([
            'price' => 13456,
            'mpg' => 100,
            'odometer_mi' => 1000,
            'odometer_km' => 1600,
            'stock_arrival_date' => Carbon::now()->subDays(20),
            'first_registration_date' => Carbon::now()->subYears(2),
            'transmission_id' => $transmission->id,
            'fuel_type_id' => $fuel->id,
            'type' => 'car',
            'is_new' => false,
        ]);

        // add vehicle attribute for finance_option
        $attribute = VehicleAttribute::factory()->create([
            'name' => 'vehicle category',
            'slug' => 'vehicle_category',
            'type' => 'string',
            'count' => 1
        ]);

        // set attribute value
        VehicleAttributeValue::factory()->create([
            'attribute_id' => $attribute->id,
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'slug' => 'vehicle_category',
            'type' => 'string',
            'value' => 'core'
        ]);

        /** @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' => 'vehicle_mpg_min',
            'condition_value' => 40,
            'value_data_type' => 'decimal',
        ]);

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

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

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

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

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

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

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

        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' => 'vehicle_category',
            'condition_value' => 'core',
            'value_data_type' => 'string',
        ]);

        LabelRule::query()->create([
            'label_id' => $label_applicable->id,
            'condition_field' => 'vehicle_is_new',
            'condition_value' => false,
            'value_data_type' => 'boolean',
        ]);

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

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

        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_applicable->id,
            'condition_field' => 'dealership_ids',
            'condition_value' => json_encode([
                $vehicle->dealership_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(Labels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle, $label_not_applicable));
    }

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

        $vehicle = Vehicle::factory()->create([
            'is_reserved' => true,
            'price' => 25000,
        ]);

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

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

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

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

        $vehicle = Vehicle::factory()->create([
            'is_reserved' => true,
            'price' => 25000,
        ]);

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

        // 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(Labels::shouldRevoke($vehicle, $label));
    }

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

        $vehicle = Vehicle::factory()->create([
            'is_reserved' => false,
            'price' => 25000,
        ]);

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

        // 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(Labels::shouldRevoke($vehicle, $label));
    }

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

        // test no revoke eligibility
        $vehicle = Vehicle::factory()->create([
            'is_reserved' => false,
            'price' => 25000,
        ]);

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

        // 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(Labels::shouldRevoke($vehicle, $label));
    }

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

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

        $attribute = VehicleAttribute::factory()->create([
            'name' => 'vehicle category',
            'slug' => 'vehicle_category',
            'type' => 'string',
            'count' => 1
        ]);

        VehicleAttributeValue::factory()->create([
            'attribute_id' => $attribute->id,
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'slug' => 'vehicle_category',
            'type' => 'string',
            'value' => 'foo'
        ]);

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

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

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

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

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

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

        $vehicle_in_range = Vehicle::factory()->create([
            'mpg' => 123,
        ]);

        $vehicle_under_range = Vehicle::factory()->create([
            'mpg' => 5,
        ]);

        $vehicle_over_range = Vehicle::factory()->create([
            'mpg' => 999,
        ]);

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

        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'vehicle_mpg_min',
            'condition_value' => 100,
            'value_data_type' => 'decimal'
        ]);

        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'vehicle_mpg_max',
            'condition_value' => 800,
            'value_data_type' => 'decimal'
        ]);

        $this->assertNotNull($label->rules);
        $this->assertTrue(Labels::shouldAssign($vehicle_in_range, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_under_range, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_over_range, $label));
    }

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

        Settings::make([
            'tab' => 'foo-baz',
            'section' => 'lorem',
            'group' => 'ipsum',
            'name' => 'advanced labels',
            'config_key' => 'automotive-distance_measurement',
            'value' => 'mi',
            'type' => 'string',
        ]);

        $vehicle_in_range = Vehicle::factory()->create([
            'odometer_mi' => 123,
        ]);

        $vehicle_under_range = Vehicle::factory()->create([
            'odometer_mi' => 5,
        ]);

        $vehicle_over_range = Vehicle::factory()->create([
            'odometer_mi' => 999,
        ]);

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

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

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

        $this->assertNotNull($label->rules);
        $this->assertTrue(Labels::shouldAssign($vehicle_in_range, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_under_range, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_over_range, $label));
    }

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

        $vehicle_in_range = Vehicle::factory()->create([
            'stock_arrival_date' => Carbon::now()->subWeek(),
        ]);

        $vehicle_under_range = Vehicle::factory()->create([
            'stock_arrival_date' => Carbon::now(),
        ]);

        $vehicle_over_range = Vehicle::factory()->create([
            'stock_arrival_date' => Carbon::now()->addYear()
        ]);

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

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

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

        $this->assertNotNull($label->rules);
        $this->assertTrue(Labels::shouldAssign($vehicle_in_range, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_under_range, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_over_range, $label));
    }

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

        $vehicle_in_range = Vehicle::factory()->create([
            'first_registration_date' => Carbon::now()->subYears(5),
        ]);

        $vehicle_under_range = Vehicle::factory()->create([
            'first_registration_date' => Carbon::now()->subYears(1),
        ]);

        $vehicle_over_range = Vehicle::factory()->create([
            'first_registration_date' => Carbon::now()->subYears(50)
        ]);

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

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

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

        $this->assertNotNull($label->rules);
        $this->assertTrue(Labels::shouldAssign($vehicle_in_range, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_under_range, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_over_range, $label));
    }

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

        $vehicle = Vehicle::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(Labels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle, $label_not_applicable));
    }

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

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

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

        $vehicle_not_eligible = Vehicle::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(Labels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle, $label_not_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle_not_eligible, $label_applicable));
    }

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

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

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

        $vehicle_not_eligible = Vehicle::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(Labels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle, $label_not_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle_not_eligible, $label_applicable));
    }

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

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

        $vehicle_not_eligible = Vehicle::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(Labels::shouldAssign($vehicle, $label_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle, $label_not_applicable));
        $this->assertFalse(Labels::shouldAssign($vehicle_not_eligible, $label_applicable));
    }

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

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

        $vehicle_not_eligible = Vehicle::factory()->create();

        // add vehicle attribute for finance_option
        $attribute = VehicleAttribute::factory()->create([
            'name' => 'vehicle category',
            'slug' => 'vehicle_category',
            'type' => 'string',
            'count' => 1
        ]);

        // set attribute value
        VehicleAttributeValue::factory()->create([
            'attribute_id' => $attribute->id,
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle->id,
            'slug' => 'vehicle_category',
            'type' => 'string',
            'value' => 'foo'
        ]);

        // set attribute value
        VehicleAttributeValue::factory()->create([
            'attribute_id' => $attribute->id,
            'owner_type' => 'vehicle',
            'owner_id' => $vehicle_not_eligible->id,
            'slug' => 'vehicle_category',
            'type' => 'string',
            'value' => 'buzz'
        ]);

        /** @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_category',
            'condition_value' => 'foo',
            'value_data_type' => 'string'
        ]);

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

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

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

        $vehicle = Vehicle::factory()->create([
            'is_new' => 1
        ]);

        $vehicle_not_eligible = Vehicle::factory()->create([
            'is_new' => 0
        ]);

        /** @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_is_new',
            'condition_value' => 1,
            'value_data_tye' => 'boolean'
        ]);

        LabelRule::query()->create([
            'label_id' => $label_not_applicable->id,
            'condition_field' => 'vehicle_is_new',
            'condition_value' => 0,
            'value_data_type' => 'boolean'
        ]);

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

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

        $vehicle = Vehicle::factory()->create([
            'registration_number' => 'ABC123',
            'is_new' => false
        ]);

        $vehicle_not_eligible = Vehicle::factory()->create([
            'registration_number' => 'XYZ456',
            'is_new' => false
        ]);

        /** @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' => 'vrms_included',
            'condition_value' => json_encode([
                'ABC123'
            ]),
            'value_data_type' => 'json'
        ]);

        LabelRule::query()->create([
            'label_id' => $label_not_applicable->id,
            'condition_field' => 'vrms_included',
            'condition_value' => json_encode([
                'DEF999'
            ]),
            'value_data_type' => 'json'
        ]);

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

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

        $vehicle_eligible = Vehicle::factory()->create([
            'registration_number' => 'DEF789',
            'is_new' => false
        ]);

        $vehicle_not_eligible = Vehicle::factory()->create([
            'registration_number' => 'ABC123',
            'is_new' => false
        ]);

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

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

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

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

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

        $vehicle_eligible = Vehicle::factory()->create([
            'is_new' => false,
            'make_id' => $make->id
        ]);

        $vehicle_not_eligible = Vehicle::factory()->create([
            'is_new' => false,
            '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(Labels::shouldAssign($vehicle_eligible, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_not_eligible, $label));
    }

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

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

        $vehicle_eligible = Vehicle::factory()->create([
            'is_new' => false,
            'model_id' => $model->id
        ]);

        $vehicle_not_eligible = Vehicle::factory()->create([
            'is_new' => false,
            '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(Labels::shouldAssign($vehicle_eligible, $label));
        $this->assertFalse(Labels::shouldAssign($vehicle_not_eligible, $label));
    }

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

        $dealer = Dealership::factory()->create();
        $dealer2 = Dealership::factory()->create();
        $dealer3 = Dealership::factory()->create();

        $vehicle_eligible = Vehicle::factory()->create([
            'is_new' => false,
            'dealership_id' => $dealer->id
        ]);

        $vehicle_not_eligible = Vehicle::factory()->create([
            'is_new' => false,
            'dealership_id' => $dealer3->id
        ]);

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

        LabelRule::query()->create([
            'label_id' => $label->id,
            'condition_field' => 'dealership_ids',
            'condition_value' => json_encode([
                $dealer->id,
                $dealer2->id
            ]),
            'value_data_type' => 'json'
        ]);

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

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

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

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

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

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

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

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

        $this->assertNotNull($label_car->rules);
        $this->assertNotNull($label_any->rules);
        $this->assertTrue(Labels::shouldAssign($vehicle_car, $label_car));
        $this->assertTrue(Labels::shouldAssign($vehicle_car, $label_any));
        $this->assertTrue(Labels::shouldAssign($vehicle_lcv, $label_any));
        $this->assertFalse(Labels::shouldAssign($vehicle_lcv, $label_car));
    }
}
