<?php

namespace App\Services;

use App\City;
use App\ClassHousing;
use App\Heating;
use App\Helpers\CacheTimeHelper;
use App\Http\Controllers\Traits\PriceFormatTrait;
use App\Http\Resources\City as CityResource;
use App\Http\Resources\CityDistrictCollection;
use App\OtherOption;
use App\Repository\DistrictRepository;
use App\Repository\PlanningRepository;
use App\Repository\PriceRepository;
use App\Repository\ResidentialComplexRepository;
use App\ResidentialComplex;
use App\RoomCount;
use App\RoomType;
use App\StageOfConstruction;
use App\TechnologyBuilding;
use Illuminate\Support\Facades\Cache;

class ResidentialComplexService
{
    use PriceFormatTrait;

    const CACHE_KEY_FILTER_OPTIONS = 'residential_complex_filter_options';
    /** @var PlanningRepository */
    public $planningRepository;
    /** @var PlanningService */
    public $planningService;
    /** @var DistrictRepository */
    public $districtRepository;
    /** @var ResidentialComplexRepository */
    public $residentialComplexesRepository;
    /** @var PriceRepository */
    public $priceRepository;

    public function __construct(
        PlanningRepository $planningRepository,
        PlanningService $planningService,
        DistrictRepository $districtRepository,
        ResidentialComplexRepository $residentialComplexRepository,
        PriceRepository $priceRepository
    ) {
        $this->planningRepository = $planningRepository;
        $this->planningService = $planningService;
        $this->districtRepository = $districtRepository;
        $this->residentialComplexesRepository = $residentialComplexRepository;
        $this->priceRepository = $priceRepository;
    }

    public function cachedResidentialComplexesCount()
    {
//        if (Cache::has(ResidentialComplex::CACHE_KEY_MAIN_PAGE_COUNT)) {
//            $count = Cache::get(ResidentialComplex::CACHE_KEY_MAIN_PAGE_COUNT);
//        } else {
//            $count = ResidentialComplex::query()->where('enabled', 1)->count();
//            Cache::put(ResidentialComplex::CACHE_KEY_MAIN_PAGE_COUNT, $count, CacheTimeHelper::ONE_DAY);
//        }
        $count = ResidentialComplex::query()->where('enabled', 1)->whereNull('deleted_at')->count();

        return $count;
    }

    public function reorganizeFilterParameters($parameters)
    {
        $this->getExchangeRate();

        ksort($parameters);
//        $roomTypes = isset($parameters['room_types']) ? $parameters['room_types'] : null;
//        if (isset($roomTypes)) {
//            $room = $this->planningService->room($roomTypes);
//            $roomType = $this->planningService->roomType($roomTypes);
//        }
        if (isset($parameters['date']['from'])) {
            $dateFrom = date($parameters['date']['from'] . '-01-01');
            $parameters['date']['from'] = $dateFrom;
        }
        if (isset($parameters['date']['to'])) {
            $dateTo = date($parameters['date']['to'] . '-01-01');
            $parameters['date']['to'] = $dateTo;
        }
        if (isset($parameters['price']['min']) && isset($parameters['price']['max'])) {
            $parameters['price']['min'] = $parameters['price']['min'] / $this->exchangeRate;
            $parameters['price']['max'] = $parameters['price']['max'] / $this->exchangeRate;
        }


//        $parameters['room'] = isset($room) ? $room : [];
//        $parameters['room_types'] = isset($roomType) ? $roomType : [];

        return $parameters;
    }

    public function filterParameters()
    {
        $this->getExchangeRate();

        $parameters = [
            'residential_complex_filter' => true
        ];

        $planningRange = $this->priceRepository->showFilterParams($parameters)->first()->toArray();
        $planning = $this->convertPricesSize($planningRange);
        $districts = $this->districtRepository->districtOfLvivRegion()->toArray();
        $cities = CityResource::collection(City::query()->whereEnabled(true)->whereNull('deleted_at')->get());
//        $cities = CityResource::collection(City::query()->whereEnabled(true)->where("region_center", false)->whereNull('deleted_at')->get());
//        $cityCenters = new CityDistrictCollection(City::query()->whereEnabled(true)->where("region_center", true)->whereNull('deleted_at')->get());
        $classesOfHousing = ClassHousing::all()->toArray();
        $stageOfConstructions = StageOfConstruction::all()->toArray();
        $heatings = Heating::all()->toArray();
        $technologyBuildings = TechnologyBuilding::all()->toArray();
        $otherOptions = OtherOption::all()->toArray();
        $rooms = RoomCount::all()->toArray();
        $roomTypes = RoomType::all()->toArray();
        $data = [
            'planning' => $planning,
//            'city_centers' => $cityCenters,
            'districts' => $districts,
            'cities' => $cities,
            'class_housings' => $classesOfHousing,
            'stage_of_constructions' => $stageOfConstructions,
            'heating' => $heatings,
            'technology_buildings' => $technologyBuildings,
            'other_options' => $otherOptions,
            'rooms' => $rooms,
            'room_types' => $roomTypes
        ];

        return $data;
    }

    public function otherDeveloperResidentialComplexes($residentialComplex)
    {
        $developerResidentialComplexes = $this->residentialComplexesRepository->listResidentialComplex();
    }

    /**
     * Calculates the great-circle distance between two points, with
     * the Haversine formula.
     * @param float $latitudeFrom Latitude of start point in [deg decimal]
     * @param float $longitudeFrom Longitude of start point in [deg decimal]
     * @param float $latitudeTo Latitude of target point in [deg decimal]
     * @param float $longitudeTo Longitude of target point in [deg decimal]
     * @param float $earthRadius Mean earth radius in [m]
     * @return float Distance between points in [m] (same as earthRadius)
     */
    function haversineGreatCircleDistance(
        $latitudeFrom,
        $longitudeFrom,
        $latitudeTo,
        $longitudeTo,
        $earthRadius = 6371000
    ) {
        // convert from degrees to radians
        $latFrom = deg2rad($latitudeFrom);
        $lonFrom = deg2rad($longitudeFrom);
        $latTo = deg2rad($latitudeTo);
        $lonTo = deg2rad($longitudeTo);

        $latDelta = $latTo - $latFrom;
        $lonDelta = $lonTo - $lonFrom;

        $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
                cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));

        return ($angle * $earthRadius) ;
    }

    public function setDistance(ResidentialComplex $residentialComplex, $request)
    {
        /** @var City $city */
        $city = $residentialComplex->city()->first() ? $residentialComplex->city()->first() : null;

        $residentialComplexLocationLatitude = $request->input('location_latitude');
        $residentialComplexLocationLongitude = $request->input('location_longitude');
        if (isset($residentialComplexLocationLongitude) && isset($residentialComplexLocationLatitude) && $city) {
            if ($city->center_latitude && $city->center_longitude) {
                $distance = $this->haversineGreatCircleDistance(
                    $residentialComplexLocationLatitude,
                    $residentialComplexLocationLongitude,
                    $city->center_latitude,
                    $city->center_longitude);
                if ($distance > 0) {
                    $kilometers = $distance / 1000;
                    $residentialComplex->center_distance = $kilometers;
                    $residentialComplex->update();
                }
            }
        }
    }

    public function convertPricesSize($planning)
    {
        $planningMaxPrice = $planning['max_price'] > $planning['max_from_min_price'] ?
            $planning['max_price'] : $planning['max_from_min_price'];
        $planningMaxSpace = $planning['max_space'] > $planning['max_from_min_space'] ?
            $planning['max_space'] : $planning['max_from_min_space'];

            $data = [
                'min_price' =>  (float)$planning['min_price'] * $this->exchangeRate,
                'max_price' => (float)$planningMaxPrice * $this->exchangeRate,
//                'min_price_old' =>  (float)$planning['min_price'] ,
//                'max_price_old' => (float)$planningMaxPrice,
                'min_space' => $planning['min_space'],
                'max_space' => $planningMaxSpace
            ];

            return $data;
    }
}
