<?php
namespace WpBookingHotelFrontend\app\models;
defined('_WPBOOKINGHOTEL_EXEC') or die;
use WpBookingHotel\Factory as FactoryAlias;
use WpBookingHotel\Factory;
use WpBookingHotel\Mvc\Model\Model;
use WpBookingHotel\Form\Form;
use WpBookingHotel\Mvc\Model\ModelList;
use WpBookingHotel\Registry\Registry;
use WpBookingHotelFrontend\app\helpers\FrontendHelper;

class HotelsModel extends ModelList
{
    /**
     * @var string
     */
    public $context = "hotels";
    /**
     * @var string
     */
    public $table_name = "hotel";

    public function getListQuery()
    {
        $input = Factory::getInput();
        $data = $input->getData();

        $keyword_address = isset($data['keyword_address'])?$data['keyword_address']:'';
        $check_in = isset($data['check_in'])?$data['check_in']:'';
        $check_out = isset($data['check_out'])?$data['check_out']:'';
        $number_adult = isset($data['number_adult'])?$data['number_adult']:0;
        $number_child = isset($data['number_child'])?$data['number_child']:0;
        $rating = isset($data['rating'])?$data['rating']:array();
        $country_id = $input->getInt('country_id',0);
        $near_me = $input->getInt('near_me',0);
        $latitude = $input->getFloat('latitude','');
        $longitude = $input->getFloat('longitude','');
        $appConfig = FactoryAlias::getAppConfig();
        $radius_for_search = $appConfig->get('radius_for_search', '');
        $unit_for_search = $appConfig->get('unit_for_search', '');

        $location_id= isset($data['location_id'])?$data['location_id']:'';
        $price_search= isset($data['price_search'])?$data['price_search']:'';
        $service_id= isset($data['service_id'])?$data['service_id']:array();

        $query=$this->db->getQuery(true);
        $query->select("a.*")
            ->from($this->getTableName().' AS a')
            ->where('a.published=1')
        ;
        if(isset($data['total_rating_avg']) && $data['total_rating_avg']>0) {
            $query->leftJoin($this->getTableName('hotelproperty') . ' AS hotelproperty5 ON hotelproperty5.hotel_id=a.id')
                ->leftJoin($this->getTableName('review') . ' AS review ON review.id=hotelproperty5.object_id')
                ->where('hotelproperty5.type=' . $query->quote(FrontendHelper::getWpBookingReviewKey()))
                ->where('review.rating=' . (int)$data['total_rating_avg']);
        }

        if( is_array($service_id) && !empty($service_id)){
            $query->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty12 ON hotelproperty12.hotel_id=a.id')
                -> where('hotelproperty12.type='.$query->quote(FrontendHelper::getWpBookingServiceKey()))
                ->where('hotelproperty12.object_id IN (' .implode(',',$service_id).')');
        } elseif(is_string($service_id) && trim($service_id) != '') {
            $query->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty12 ON hotelproperty12.hotel_id=a.id')
                ->where('hotelproperty12.type='.$query->quote(FrontendHelper::getWpBookingServiceKey()))
                ->where('hotelproperty12.object_id = '.$service_id);
        }

        if($number_adult > 0) {
            $query->where('a.max_adult >='.(int)$number_adult);
        }
        if($number_child > 0) {
            $query->where('a.max_child >='.(int)$number_child);
        }
        if($near_me == 1) {
            if($latitude != '' && $longitude != '') {
                $modelLocations = Model::getInstance('locations');
                $list_location = $modelLocations->getList();
                $query2= $this->_db->getQuery(true);

                foreach ($list_location as $location) {
                    $distance = static::getDistanceBetweenPointsNew($latitude, $longitude, $location->lat, $location->lang,$unit_for_search);
                    $query2->clear()
                        ->update($this->getTableName('hotel'). ' AS hotel')
                        ->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty15 ON hotelproperty15.hotel_id=hotel.id')
                        ->set('hotel.distance='.(float)$distance)
                        ->where('hotelproperty15.type='.$query->quote(FrontendHelper::getWpBookingDestinationKey()))
                        ->where('hotelproperty15.object_id='.(int)$location->id)

                    ;
                    $this->db->setQuery($query2)->execute();
                }
                $query->where('a.distance <= '.(float)$radius_for_search);
            }
        }

        if($keyword_address != '' && trim($keyword_address)!='') {
            $query->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty1 ON hotelproperty1.hotel_id=a.id')
                ->leftJoin($this->getTableName('location'). ' AS location ON location.id=hotelproperty1.object_id')
                ->where('hotelproperty1.type='.$query->quote(FrontendHelper::getWpBookingDestinationKey()))
                ->where('location.address LIKE '.$query->quote("%$keyword_address%"))
            ;
        }

        
        $roomtype_id ='';
        if(array_key_exists('room_type_id',(array)$data) ) {
            $roomtype_id=$data['room_type_id'];
            if(!empty($roomtype_id)){
                $roomtype_id=(array)$roomtype_id;
            }
        }
        if(is_array($roomtype_id) && !empty($roomtype_id)) {
            $query->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty4 ON hotelproperty4.hotel_id=a.id')
                ->where('hotelproperty4.type='.$query->quote(FrontendHelper::getWpBookingRoomtypeKey()))
                ->where('hotelproperty4.object_id IN (' .implode(',',$roomtype_id).')');
        } elseif(trim($roomtype_id) != '') {
            $query->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty4 ON hotelproperty4.hotel_id=a.id')
                ->where('hotelproperty4.type='.$query->quote(FrontendHelper::getWpBookingRoomtypeKey()))
                ->where('hotelproperty4.object_id = '.$roomtype_id);
        }
        if($location_id !='' && trim($location_id) !=''){
            $query->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty11 ON hotelproperty11.hotel_id=a.id')
                -> where('hotelproperty11.type='.$query->quote(FrontendHelper::getWpBookingDestinationKey()))
                -> where('hotelproperty11.object_id='.(int)$location_id);
        }
        if($country_id > 0) {
            $query->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty6 ON hotelproperty6.hotel_id=a.id')
                ->leftJoin($this->getTableName('location').' AS location ON location.id=hotelproperty6.object_id')
                ->leftJoin($this->getTableName('state'). ' AS state ON state.id=location.state_id')
                ->leftJoin($this->getTableName('country'). ' AS country ON country.id=state.country_id')
                ->where('hotelproperty6.type='.$query->quote(FrontendHelper::getWpBookingDestinationKey()))
                ->where('country.id='.(int)$country_id)
            ;
        }
        $query->group('a.id');

        $query->order($this->getState('list.ordering', 'a.ordering') . ' ' . $this->getState('list.direction', 'ASC'));

        if($price_search!==""){
            $price_search=(array)json_decode($price_search);
        }
        if(is_array($price_search) && !empty($price_search)){
            $min=reset($price_search);
            $max=end($price_search);
            $query->where('a.price>='.(float)$min);
            $query->where('a.price<='.(float)$max);
        }
        $key_sort_by="a.ordering";
        if(isset($data['key_sort']) && trim($data['key_sort'])!==''){
            $key_sort_by=$data['key_sort'];
        }
        $direction="";
        if(isset($data['direction']) && trim($data['direction'])!==''){
            $direction=$data['direction'];
        }
        
        $query->order("$key_sort_by $direction");

        $query->group('a.id');

        return $query;
    }

    public function getList()
    {
        $input=Factory::getInput();
        $data=$input->getData();
        $start=0;
        if(isset($data['start']) && $data['start'] !== ''){
            $start = (int)$data['start'];
        }
        $limit=0;
        if(isset($data['limit']) && $data['limit'] !== ''){
            $limit = (int)$data['limit'];
        }
        $db=FactoryAlias::getDBO();        
        $query=$this->getListQuery();
        $list = $db->setQuery($query,$start,$limit)->loadObjectList();

        foreach ($list as &$item) {
            $query->clear()
                ->select('DISTINCT location.*')
                ->from($this->getTableName('location').' AS location')
                ->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty ON hotelproperty.object_id=location.id')
                ->where('hotelproperty.hotel_id='.(int)$item->id)
                ->where('hotelproperty.type='.$query->quote(FrontendHelper::getWpBookingDestinationKey()))
            ;
            $destination= $this->_db->setQuery($query)->loadObject();
            $item->destination=$destination;

            $query->clear()
                ->select('DISTINCT review.*')
                ->from($this->getTableName('review').' AS review')
                ->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty ON hotelproperty.object_id=review.id')
                ->where('hotelproperty.hotel_id='.(int)$item->id)
                ->where('hotelproperty.type='.$query->quote(FrontendHelper::getWpBookingReviewKey()))
            ;
            $list_review = $this->_db->setQuery($query)->loadObjectList();
            $rating_sum = 0;
            foreach ($list_review as $review) {
                if(isset($review->rating)) {
                    $rating_sum += $review->rating;
                }
            }
            $item->list_review = $list_review;
            $item->rating_avg = !empty($list_review)?($rating_sum/count($list_review)):0;

            $register = new Registry();
            $register->loadString($item->params);
            $item->params = $register;
        }

        return $list;
    }

    public function getTotalRecord(){
        $db=FactoryAlias::getDBO();
        $query=$this->getListQuery();
        $list_service=$db->setQuery($query)->loadObjectList();
        return count($list_service);
    }

    public function getFilterFormHotel()
    {
        return self::get_filter_form_hotel();
    }

    public static function get_filter_form_hotel()
    {

        try {
            $form = Form::getInstance(WPBOOKINGHOTEL_PATH_ROOT."/frontend/app/models/forms/filter_form_hotel.xml"); //TODO: refactor late.

        } catch (\Exception $e) {
            echo ($e->getMessage());
            die;
            return false;
        }
        return $form;
    }

    public function get_list_hotel_loc()
    {
        $db=FactoryAlias::getDBO();
        $input=FactoryAlias::getInput();
        $data=$input->getData();
        $user_id = 0;
        if(!empty($data['user_id'])){
            $user_id = intval($data['user_id']);
        }
        $query=$this->getListQuery();
        $list_service=$db->setQuery($query)->loadObjectList();
        foreach ($list_service as &$item) {
            $query = $this->db->getQuery(true);
            $query->clear()
                ->select('DISTINCT location.*')
                ->from($this->getTableName('location').' AS location')
                ->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty ON hotelproperty.object_id=location.id')
                ->where('hotelproperty.hotel_id='.(int)$item->id)
                ->where('hotelproperty.type='.$query->quote(FrontendHelper::getWpBookingDestinationKey()))
            ;
            $destination= $this->_db->setQuery($query)->loadObject();
            $item->destination=$destination;
            $query->clear()
                ->select('DISTINCT review.*')
                ->from($this->getTableName('review').' AS review')
                ->leftJoin($this->getTableName('hotelproperty').' AS hotelproperty ON hotelproperty.object_id=review.id')
                ->where('hotelproperty.hotel_id='.(int)$item->id)
                ->where('hotelproperty.type='.$query->quote(FrontendHelper::getWpBookingReviewKey()))
            ;
            $list_review = $this->_db->setQuery($query)->loadObjectList();
            $rating_sum = 0;
            foreach ($list_review as $review) {
                if(isset($review->rating)) {
                    $rating_sum += $review->rating;
                }
            }
            $item->list_review = $list_review;
            $item->rating_avg = !empty($list_review)?($rating_sum/count($list_review)):0;

            $register = new Registry();
            $register->loadString($item->params);
            $item->params = $register;

            $item->lang = $item->destination->lang;
            $item->lat = $item->destination->lat;
        }

        return $list_service;
    }

    public function getListHotelsAjax() {
        $input = Factory::getInput();
        $data = $input->getData();
        $page_hotel_detail = isset($data['page_hotel_detail']) ? $data['page_hotel_detail'] : "";
        $modelHotels = Model::getInstance('hotels');
        $list_hotels = $modelHotels->getList();
        return $this->htmlViewListHotels($list_hotels,$page_hotel_detail);
    }
    public static function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'Mi') {
        $theta = (float)$longitude1 - (float)$longitude2;
        $distance = sin(deg2rad((float)$latitude1)) * sin(deg2rad((float)$latitude2)) + cos(deg2rad((float)$latitude1)) * cos(deg2rad((float)$latitude2)) * cos(deg2rad((float)$theta));

        $distance = acos($distance);
        $distance = rad2deg($distance);
        $distance = $distance * 60 * 1.1515;

        switch($unit)
        {
            case 'Mi': break;
            case 'Km' : $distance = $distance * 1.609344;
        }

        return (round($distance,2));
    }



}
