<?php

namespace FCA\StockApi\Collection\Filter;

use FCA\StockApi\Collection\Filter\Builder\Fields;
use FCA\StockApi\Exception\ApiException;

class Wizard
{
    private $brandCode = null;
    private $model = [];
    private $model_groups_slug = [];
    private $fuelType = [];
    private $priceFrom = null;
    private $priceTo = null;
    private $priceType = null;

    private $productionYear = [];
    private $gearboxType = [];
    private $driveType = [];
    private $enginePowerFrom = null;
    private $enginePowerTo = null;

    private $color = [];
    private $interiorType = [];
    private $equipmentCode = [];

    private $longitude = null;
    private $latitude = null;
    private $maxDistance = null;

    // TODO - wyszukiwanie po tagach ofert

    /**
     * @return array
     * @throws ApiException
     */
    public function getFilters()
    {
        $b = new Builder();

        $filters = [];

        if ($this->brandCode !== null) {
            $filters[] = $b->is(Fields::BRAND_CODE, '=', $this->brandCode);
        }
        
        if (count($this->model)) {
            $filters[] = $b->is(Fields::MODEL_COMMERCIAL_CODE, 'in', array_values($this->model));
        }

        if (count($this->model_groups_slug)) {
            $filters[] = $b->is(Fields::MODEL_GROUPS_SLUG, 'in', array_values($this->model_groups_slug));
        }

        if (count($this->fuelType)) {
            $filters[] = $b->is(Fields::FUEL_TYPE, 'in', array_values($this->fuelType));
        }

        if ($this->priceType == null and ($this->priceTo !== null or $this->priceFrom !== null)) {
            throw new ApiException('priceType cannot be null');
        } elseif ($this->priceTo !== null and $this->priceFrom === null) {
            $filters[] = $b->is($this->priceType, '<=', $this->priceTo);
        } elseif ($this->priceTo === null and $this->priceFrom !== null) {
            $filters[] = $b->is($this->priceType, '>=', $this->priceFrom);
        } elseif ($this->priceTo !== null and $this->priceFrom !== null) {
            $filters[] =
                $b->andWhere(
                    $b->is($this->priceType, '<=', $this->priceTo),
                    $b->is($this->priceType, '>=', $this->priceFrom)
                );
        }

        if (count($this->productionYear)) {
            $filters[] = $b->is(Fields::PRODUCTION_YEAR, 'in', array_values($this->productionYear));
        }

        if (count($this->gearboxType)) {
            $filters[] = $b->is(Fields::GEARBOX_TYPE, 'in', array_values($this->gearboxType));
        }

        if (count($this->driveType)) {
            $filters[] = $b->is(Fields::DRIVE_TYPE, 'in', array_values($this->driveType));
        }

        if ($this->enginePowerTo !== null and $this->enginePowerFrom === null) {
            $filters[] = $b->is(Fields::ENGINE_POWER, '<=', $this->enginePowerTo);
        } elseif ($this->enginePowerTo === null and $this->enginePowerFrom !== null) {
            $filters[] = $b->is(Fields::ENGINE_POWER, '>=', $this->enginePowerFrom);
        } elseif ($this->enginePowerTo !== null and $this->enginePowerFrom !== null) {
            $filters[] =
                $b->andWhere(
                    $b->is(Fields::ENGINE_POWER, '<=', $this->enginePowerTo),
                    $b->is(Fields::ENGINE_POWER, '>=', $this->enginePowerFrom)
                );
        }
        
        if (count($this->color)) {
            $filters[] = $b->is(Fields::COLOR_CATEGORY, 'in', array_values($this->color));
        }

        if (count($this->interiorType)) {
            $filters[] = $b->is(Fields::INTERIOR_TYPE, 'in', array_values($this->interiorType));
        }

        if (count($this->equipmentCode)) {
            $filters[] = $b->is(Fields::EQUIPMENT_CODE, 'in', array_values($this->equipmentCode));
        }

        if ($this->latitude !== null and $this->longitude !== null && $this->maxDistance !== null) {
            $filters[] = $b->isNear(Fields::DEALER_COORDINATES, $this->longitude, $this->latitude, $this->maxDistance);
        }

        return $b->andWhere(...$filters);
    }

    /**
     * @param $brandCode
     * @return $this
     */
    public function setBrandCode($brandCode)
    {
        $this->brandCode = $brandCode;
        return $this;
    }

    /**
     * @return $this
     */
    public function clearBrandCode()
    {
        $this->brandCode = null;
        return $this;
    }

    /**
     * @param array $models
     * @return $this
     */
    public function setModels(array $models)
    {
        // Convert all values to strings
        array_walk($models, function (&$value) {
            $value = (string)$value;
        });
        $this->model = array_combine($models, $models);
        return $this;
    }

    /**
     * @param $model
     * @return $this
     */
    public function addModel($model)
    {
        $this->model[(string) $model] = (string) $model;
        return $this;
    }

    /**
     * @param $model
     * @return $this
     */
    public function removeModel($model)
    {
        unset($this->model[(string) $model]);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearModels()
    {
        $this->model = [];
        return $this;
    }

    /**
     * @param array $slugs
     * @return $this
     */
    public function setModelGroupsSlugs(array $slugs)
    {
        // Convert all values to strings
        array_walk($slugs, function (&$value) {
            $value = (string)$value;
        });
        $this->model_groups_slug = array_combine($slugs, $slugs);
        return $this;
    }

    /**
     * @param $slug
     * @return $this
     */
    public function addModelGroupsSlug($slug)
    {
        $this->model_groups_slug[(string) $slug] = (string) $slug;
        return $this;
    }

    /**
     * @param $slug
     * @return $this
     */
    public function removeModelGroupsSlug($slug)
    {
        unset($this->model_groups_slug[(string) $slug]);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearModelGroupsSlugs()
    {
        $this->model_groups_slug = [];
        return $this;
    }

    /**
     * @param $fuelType
     * @return $this
     */
    public function addFuelType($fuelType)
    {
        $this->fuelType[(string) $fuelType] = (string) $fuelType;
        return $this;
    }

    /**
     * @param $fuelType
     * @return $this
     */
    public function removeFuelType($fuelType)
    {
        unset($this->fuelType[(string) $fuelType]);
        return $this;
    }

    /**
     * @param array $fuelTypes
     * @return $this
     */
    public function setFuelTypes(array $fuelTypes)
    {
        // Convert all values to strings
        array_walk($fuelTypes, function (&$value) {
            $value = (string)$value;
        });
        $this->fuelType = array_combine($fuelTypes, $fuelTypes);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearFuelTypes()
    {
        $this->fuelType = [];
        return $this;
    }

    /**
     * @param $priceFrom
     * @return $this
     */
    public function setPriceFrom($priceFrom)
    {
        $this->priceFrom = $priceFrom;
        return $this;
    }

    /**
     * @return $this
     */
    public function clearPriceFrom()
    {
        $this->priceFrom = null;
        return $this;
    }

    /**
     * @param $priceTo
     * @return $this
     */
    public function setPriceTo($priceTo)
    {
        $this->priceTo = $priceTo;
        return $this;
    }

    /**
     * @return $this
     */
    public function clearPriceTo()
    {
        $this->priceTo = null;
        return $this;
    }

    /**
     * @param $productionYear
     * @return $this
     */
    public function addProductionYear($productionYear)
    {
        $this->productionYear[(string) $productionYear] = $productionYear;
        return $this;
    }

    /**
     * @param $productionYear
     * @return $this
     */
    public function removeProductionYear($productionYear)
    {
        unset($this->productionYear[(string) $productionYear]);
        return $this;
    }

    /**
     * @param $productionYears
     * @return $this
     */
    public function setProductionYears(array $productionYears)
    {
        // Convert all values to strings
        array_walk($productionYears, function (&$value) {
            $value = (string)$value;
        });
        $this->productionYear = array_combine($productionYears, $productionYears);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearProductionYears()
    {
        $this->productionYear = [];
        return $this;
    }

    /**
     * @param $gearboxType
     * @return $this
     */
    public function addGearboxType($gearboxType)
    {
        $this->gearboxType[(string) $gearboxType] = $gearboxType;
        return $this;
    }

    /**
     * @param $gearboxType
     * @return $this
     */
    public function removeGearboxType($gearboxType)
    {
        unset($this->gearboxType[(string) $gearboxType]);
        return $this;
    }

    /**
     * @param array $gearboxTypes
     * @return $this
     */
    public function setGearboxTypes(array $gearboxTypes)
    {
        // Convert all values to strings
        array_walk($gearboxTypes, function (&$value) {
            $value = (string)$value;
        });
        $this->gearboxType = array_combine($gearboxTypes, $gearboxTypes);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearGearboxTypes()
    {
        $this->gearboxType = [];
        return $this;
    }

    /**
     * @param array $driveTypes
     * @return $this
     */
    public function setDriveTypes(array $driveTypes)
    {
        // Convert all values to strings
        array_walk($driveTypes, function (&$value) {
            $value = (string)$value;
        });
        $this->driveType = array_combine($driveTypes, $driveTypes);
        return $this;
    }

    /**
     * @param $driveType
     * @return $this
     */
    public function addDriveType($driveType)
    {
        $this->driveType[(string) $driveType] = $driveType;
        return $this;
    }

    /**
     * @param $driveType
     * @return $this
     */
    public function removeDriveType($driveType)
    {
        unset($this->driveType[(string) $driveType]);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearDriveTypes()
    {
        $this->driveType = [];
        return $this;
    }

    /**
     * @param $enginePowerFrom
     * @return $this
     */
    public function setEnginePowerFrom($enginePowerFrom)
    {
        $this->enginePowerFrom = $enginePowerFrom;
        return $this;
    }

    /**
     * @return $this
     */
    public function clearEnginePowerFrom()
    {
        $this->enginePowerFrom = null;
        return $this;
    }

    /**
     * @param $enginePowerTo
     * @return $this
     */
    public function setEnginePowerTo($enginePowerTo)
    {
        $this->enginePowerTo = $enginePowerTo;
        return $this;
    }

    /**
     * @return $this
     */
    public function clearEnginePowerTo()
    {
        $this->enginePowerTo = null;
        return $this;
    }

    /**
     * @param $color
     * @return $this
     */
    public function addColor($color)
    {
        $this->color[(string) $color] = $color;
        return $this;
    }

    /**
     * @param $color
     * @return $this
     */
    public function removeColor($color)
    {
        unset($this->color[(string) $color]);
        return $this;
    }

    /**
     * @param array $colors
     * @return $this
     */
    public function setColors(array $colors)
    {
        // Convert all values to strings
        array_walk($colors, function (&$value) {
            $value = (string)$value;
        });
        $this->color = array_combine($colors, $colors);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearColors()
    {
        $this->color = [];
        return $this;
    }

    /**
     * @param $interiorType
     * @return $this
     */
    public function addInteriorType($interiorType)
    {
        $this->interiorType[(string) $interiorType] = $interiorType;
        return $this;
    }

    /**
     * @param $interiorType
     * @return $this
     */
    public function removeInteriorType($interiorType)
    {
        unset($this->interiorType[(string) $interiorType]);
        return $this;
    }

    /**
     * @param array $interiorTypes
     * @return $this
     */
    public function setInteriorTypes($interiorTypes)
    {
        // Convert all values to strings
        array_walk($interiorTypes, function (&$value) {
            $value = (string)$value;
        });
        $this->interiorType = array_combine($interiorTypes, $interiorTypes);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearInteriorTypes()
    {
        $this->interiorType = [];
        return $this;
    }

    /**
     * @param array $equipmentCodes
     * @return $this
     */
    public function setEquipmentCodes(array $equipmentCodes)
    {
        // Convert all values to strings
        array_walk($equipmentCodes, function (&$value) {
            $value = (string)$value;
        });
        $this->equipmentCode = array_combine($equipmentCodes, $equipmentCodes);
        return $this;
    }

    /**
     * @param $equipmentCode
     * @return $this
     */
    public function addEquipmentCode($equipmentCode)
    {
        $this->equipmentCode[(string) $equipmentCode] = (string) $equipmentCode;
        return $this;
    }

    /**
     * @param $equipmentCode
     * @return $this
     */
    public function removeEquipmentCode($equipmentCode)
    {
        unset($this->equipmentCode[(string) $equipmentCode]);
        return $this;
    }

    /**
     * @return $this
     */
    public function clearEquipmentCodes()
    {
        $this->equipmentCode = [];
        return $this;
    }

    /**
     * @param $priceType
     *
     * @return Wizard
     * @throws ApiException
     */
    public function setPriceType($priceType)
    {
        $validValues = [
            Fields::BASE_PRICE_BRUTTO,
            Fields::BASE_PRICE_NETTO,
            Fields::FINAL_PRICE_BRUTTO,
            Fields::FINAL_PRICE_NETTO
        ];
        if (in_array($priceType, $validValues)) {
            $this->priceType = $priceType;
        } else {
            throw new ApiException('Invalid priceType value!');
        }
        return $this;
    }

    /**
     * @return $this
     */
    public function clearPriceType()
    {
        $this->priceType = null;
        return $this;
    }

    /**
     * @param $longitude double
     * @throws ApiException
     */
    public function setLongitude($longitude)
    {
        if (is_float($longitude)) {
            $this->longitude = $longitude;
        } else {
            throw new ApiException('Longitude must be double!');
        }
    }

    /**
     * @return $this
     */
    public function clearLongitude()
    {
        $this->longitude = null;
        return $this;
    }

    /**
     * @param $latitude double
     * @throws ApiException
     */
    public function setLatitude($latitude)
    {
        if (is_float($latitude)) {
            $this->latitude = $latitude;
        } else {
            throw new ApiException('Latitude must be double!');
        }
    }

    /**
     * @return $this
     */
    public function clearLatitude()
    {
        $this->latitude = null;
        return $this;
    }

    /**
     * @param $distance integer
     * @throws ApiException
     * @return $this
     */
    public function setMaxDistance($distance)
    {
        if (is_int($distance)) {
            $this->maxDistance = $distance;
        } else {
            throw new ApiException('Max Distance must be integer!');
        }
        return $this;
    }

    /**
     * @return $this
     */
    public function clearMaxDistance()
    {
        $this->maxDistance = null;
        return $this;
    }
}
