<?php

namespace FCA\StockApi\Tests\Unit\Collection\Filter;

use FCA\StockApi\Collection\Filter\Builder\Fields;
use FCA\StockApi\Collection\Filter\Wizard;
use FCA\StockApi\Exception\ApiException;
use PHPUnit\Framework\TestCase;

class WizardTest extends TestCase
{
    /**
     * @throws ApiException
     */
    public function testGetFilter()
    {
        $wizard = new Wizard();
        $result = $wizard->getFilters();
        $this->assertEquals([], $result);

        $wizard = new Wizard();
        $wizard->setEnginePowerTo(104);
        $wizard->setEnginePowerFrom(90);
        $result = $wizard->getFilters();

        $returnArray = [
            '$and' => [
                [
                    Fields::ENGINE_POWER => [
                        '$lte' => 104
                    ]
                ],
                [
                    Fields::ENGINE_POWER => [
                        '$gte' => 90
                    ]
                ]
            ]
        ];

        $this->assertEquals($returnArray, $result);
    }

    /**
     * @throws ApiException
     */
    public function testSetEnginePowerTo()
    {
        $value = 55;

        $wizard = new Wizard();
        $wizard->setEnginePowerTo($value);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::ENGINE_POWER => [
                '$lte' => $value
            ]
        ];

        $this->assertEquals($returnArray, $result);
    }

    /**
     * @throws ApiException
     */
    public function testSetEnginePowerFrom()
    {
        $value = 55;

        $wizard = new Wizard();
        $wizard->setEnginePowerFrom($value);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::ENGINE_POWER => [
                '$gte' => $value
            ]
        ];

        $this->assertEquals($returnArray, $result);
    }


    /**
     * @throws ApiException
     */
    public function testSetPriceTypeWithInvalidValue()
    {
        $this->expectException(ApiException::class);
        $wizard = new Wizard();
        $wizard->setPriceType('invalidType');
    }

    /**
     * @throws ApiException
     */
    public function testSetFuelType()
    {
        $value_1 = 'Benzyna';
        $value_2 = 'LPG';

        $wizard = new Wizard();
        $wizard->setFuelTypes([$value_1, $value_2]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::FUEL_TYPE => [
                '$in' => [$value_1, $value_2]
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $value_3 = 'Olej napędowy';
        $wizard->addFuelType($value_3);
        $this->assertEquals(
            [
                Fields::FUEL_TYPE => [
                    '$in' => [$value_1, $value_2, $value_3],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->addFuelType($value_3); // Adding the same value again purposely - should not result with duplicate values
        $this->assertEquals(
            [
                Fields::FUEL_TYPE => [
                    '$in' => [$value_1, $value_2, $value_3],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->removeFuelType($value_2);
        $this->assertEquals(
            [
                Fields::FUEL_TYPE => [
                    '$in' => [$value_1, $value_3],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->clearFuelTypes();
        $this->assertEquals(
            [],
            $wizard->getFilters()
        );
    }

    /**
     * @throws ApiException
     */
    public function testSetModels()
    {
        $value_1 = '357HB';

        $wizard = new Wizard();
        $wizard->setModels([$value_1]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::MODEL_COMMERCIAL_CODE => [
                '$in' => [$value_1]
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $value_2 = '150CS3';
        $wizard->addModel($value_2);
        $this->assertEquals(
            [
                Fields::MODEL_COMMERCIAL_CODE => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->addModel($value_2); // Adding the same value again purposely - should not result with duplicate values
        $this->assertEquals(
            [
                Fields::MODEL_COMMERCIAL_CODE => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->removeModel($value_1);
        $this->assertEquals(
            [
                Fields::MODEL_COMMERCIAL_CODE => [
                    '$in' => [$value_2],
                ],
            ],
            $wizard->getFilters()
        );
        $wizard->clearModels();
        $this->assertEquals(
            [],
            $wizard->getFilters()
        );
    }

    /**
     * @throws ApiException
     */
    public function testSetInteriorType()
    {
        $value_1 = 'Skóra';

        $wizard = new Wizard();
        $wizard->setInteriorTypes([$value_1]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::INTERIOR_TYPE => [
                '$in' => [$value_1]
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $value_2 = 'Eko-skóra';
        $wizard->addInteriorType($value_2);
        $this->assertEquals(
            [
                Fields::INTERIOR_TYPE => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->addInteriorType($value_2); // Adding the same value again purposely - should not result with duplicate values
        $this->assertEquals(
            [
                Fields::INTERIOR_TYPE => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->removeInteriorType($value_1);
        $this->assertEquals(
            [
                Fields::INTERIOR_TYPE => [
                    '$in' => [$value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->clearInteriorTypes();
        $this->assertEquals(
            [],
            $wizard->getFilters()
        );
    }

    /**
     * @throws ApiException
     */
    public function testSetPriceFrom()
    {
        $value = 65464.00;

        $wizard = new Wizard();
        $wizard->setPriceFrom($value);
        $wizard->setPriceType(Fields::FINAL_PRICE_BRUTTO);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::FINAL_PRICE_BRUTTO => [
                '$gte' => $value
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $wizard = new Wizard();
        $wizard->setPriceFrom($value);
        $this->expectException(ApiException::class);
        $wizard->getFilters();
    }

    /**
     * @throws ApiException
     */
    public function testSetPriceTo()
    {
        $value = 65464.00;

        $wizard = new Wizard();
        $wizard->setPriceTo($value);
        $wizard->setPriceType(Fields::FINAL_PRICE_BRUTTO);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::FINAL_PRICE_BRUTTO => [
                '$lte' => $value
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $wizard = new Wizard();
        $wizard->setPriceTo($value);
        $this->expectException(ApiException::class);
        $wizard->getFilters();
    }

    /**
     * @throws ApiException
     */
    public function testSetProductionYear()
    {
        $value_1 = 2018;

        $wizard = new Wizard();
        $wizard->setProductionYears([$value_1]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::PRODUCTION_YEAR => [
                '$in' => [$value_1]
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $value_2 = 2019;
        $wizard->addProductionYear($value_2);
        $this->assertEquals(
            [
                Fields::PRODUCTION_YEAR => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->addProductionYear($value_2); // Adding the same value again purposely - should not result with duplicate values
        $this->assertEquals(
            [
                Fields::PRODUCTION_YEAR => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->removeProductionYear($value_1);
        $this->assertEquals(
            [
                Fields::PRODUCTION_YEAR => [
                    '$in' => [$value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->clearProductionYears();
        $this->assertEquals(
            [],
            $wizard->getFilters()
        );
    }

    /**
     * @throws ApiException
     */
    public function testSetGearboxType()
    {
        $value_1 = 'Automatyczna';

        $wizard = new Wizard();
        $wizard->setGearboxTypes([$value_1]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::GEARBOX_TYPE => [
                '$in' => [$value_1]
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $value_2 = 'Manualna';
        $wizard->addGearboxType($value_2);
        $this->assertEquals(
            [
                Fields::GEARBOX_TYPE => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->addGearboxType($value_2); // Adding the same value again purposely - should not result with duplicate values
        $this->assertEquals(
            [
                Fields::GEARBOX_TYPE => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->removeGearboxType($value_1);
        $this->assertEquals(
            [
                Fields::GEARBOX_TYPE => [
                    '$in' => [$value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->clearGearboxTypes();
        $this->assertEquals(
            [],
            $wizard->getFilters()
        );
    }

    /**
     * @throws ApiException
     */
    public function testSetBrandCode()
    {
        $value = '00';

        $wizard = new Wizard();
        $wizard->setBrandCodes([$value]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::BRAND_CODE => ['$in' => [$value]]
        ];

        $this->assertEquals($returnArray, $result);
    }

    /**
     * @throws ApiException
     */
    public function testSetDriveType()
    {
        $value_1 = 'Napęd na przednie koła';

        $wizard = new Wizard();
        $wizard->setDriveTypes([$value_1]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::DRIVE_TYPE => [
                '$in' => [$value_1]
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $value_2 = '4x4';
        $wizard->addDriveType($value_2);
        $this->assertEquals(
            [
                Fields::DRIVE_TYPE => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->addDriveType($value_2); // Adding the same value again purposely - should not result with duplicate values
        $this->assertEquals(
            [
                Fields::DRIVE_TYPE => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->removeDriveType($value_1);
        $this->assertEquals(
            [
                Fields::DRIVE_TYPE => [
                    '$in' => [$value_2],
                ],
            ],
            $wizard->getFilters()
        );
        $wizard->clearDriveTypes();
        $this->assertEquals(
            [],
            $wizard->getFilters()
        );
    }

    /**
     * @throws ApiException
     */
    public function testSetColor()
    {
        $value_1 = 'WHITE';

        $wizard = new Wizard();
        $wizard->setColors([$value_1]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::COLOR_CATEGORY => [
                '$in' => [$value_1]
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $value_2 = 'BLACK';
        $wizard->addColor($value_2);
        $this->assertEquals(
            [
                Fields::COLOR_CATEGORY => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->addColor($value_2); // Adding the same value again purposely - should not result with duplicate values
        $this->assertEquals(
            [
                Fields::COLOR_CATEGORY => [
                    '$in' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->removeColor($value_1);
        $this->assertEquals(
            [
                Fields::COLOR_CATEGORY => [
                    '$in' => [$value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->clearColors();
        $this->assertEquals(
            [],
            $wizard->getFilters()
        );
    }

    /**
     * @throws ApiException
     */
    public function testSetEquipments()
    {
        $value_1 = 'BNG';

        $wizard = new Wizard();
        $wizard->setEquipments([$value_1]);
        $result = $wizard->getFilters();

        $returnArray = [
            Fields::EQUIPMENT_OPTIONS => [
                '$all' => [$value_1]
            ]
        ];

        $this->assertEquals($returnArray, $result);

        $value_2 = 'XYZ';
        $wizard->addEquipment($value_2);
        $this->assertEquals(
            [
                Fields::EQUIPMENT_OPTIONS => [
                    '$all' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->addEquipment($value_2); // Adding the same value again purposely - should not result with duplicate values
        $this->assertEquals(
            [
                Fields::EQUIPMENT_OPTIONS => [
                    '$all' => [$value_1, $value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->removeEquipment($value_1);
        $this->assertEquals(
            [
                Fields::EQUIPMENT_OPTIONS => [
                    '$all' => [$value_2],
                ],
            ],
            $wizard->getFilters()
        );

        $wizard->clearEquipments();
        $this->assertEquals(
            [],
            $wizard->getFilters()
        );
    }

    /**
     * @throws ApiException
     */
    public function testNearByCoordinates()
    {
        $wizard = new Wizard();
        $wizard->setLatitude(12.54465);
        $wizard->setLongitude(45.55478);
        $wizard->setMaxDistance(10);

        $expectedArray = [
            Fields::DEALER_COORDINATES => [
                '$near' => [
                    '$geometry' => ['type' => 'Point', 'coordinates' => [45.55478, 12.54465]],
                    '$maxDistance' => 10000
                ]
            ]
        ];

        $this->assertEquals($expectedArray, $wizard->getFilters());

        //===========================================================================================

        $wizard = new Wizard();
        //$wizard->setLatitude(12.54465);
        $wizard->setLongitude(45.55478);
        $wizard->setMaxDistance(10000);


        $this->assertEquals([], $wizard->getFilters());

        //===========================================================================================

        $wizard = new Wizard();
        $wizard->setLatitude(12.54465);
        //$wizard->setLongitude(45.55478);
        $wizard->setMaxDistance(10000);


        $this->assertEquals([], $wizard->getFilters());

        //===========================================================================================

        $wizard = new Wizard();
        $wizard->setLatitude(12.54465);
        $wizard->setLongitude(45.55478);
        //$wizard->setMaxDistance(10000);


        $this->assertEquals([], $wizard->getFilters());
    }

    /**
     * @throws \TypeError
     */
    public function testSetLatitudeWithBadValue()
    {
        $wizard = new Wizard();
        $this->expectException(\TypeError::class);
        $wizard->setLongitude('foo');
    }

    /**
     * @throws \TypeError
     */
    public function testSetLongitudeWithBadValue()
    {
        $wizard = new Wizard();
        $this->expectException(\TypeError::class);
        $wizard->setLongitude('foo');
    }

    /**
     * @throws \TypeError
     */
    public function testSetMaxDistanceWithBadValue()
    {
        $wizard = new Wizard();
        $this->expectException(\TypeError::class);
        $wizard->setLongitude('foo');
    }
}
