<?php

namespace App\Http\Controllers\API;

use App\ConsultingEvaluate;
use App\Helpers\Notification;
use App\Hotel;
use App\HotelReservation;
use App\Http\Requests\API\SavePaymentRequest;
use App\Http\Resources\UserResource;
use App\Payment;
use App\Room;
use App\User;
use App\UsersNotification;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\Http\Resources\HotelResource;
use Illuminate\Support\Facades\Validator;
use App\Http\Resources\HotelReservationResource;
use App\Http\Requests\API\AddHotelReservationRequest;

class HotelController extends Controller
{

    /**
     * Get all hotels or hotel by id
     * @param null $hotel_id
     * @return JsonResponse
     */
    public function hotels($hotel_id = null) :JsonResponse
    {
        $hotels =  Hotel::withDescription($hotel_id);

        if ($hotel_id && !$hotels){
            return response()->json(['message' => __('hotels.hotel_not_active'), 'data' => null], 401);
        }

        if ($hotel_id && !$hotels->status){
            return response()->json(['message' => __('hotels.hotel_not_active'), 'data' => null], 401);
        }

        $hotels = $hotel_id ? HotelResource::make($hotels) : HotelResource::collection($hotels);
        return response()->json(['message' => '', 'data' => $hotels], 200);
    }

    /**
     * Add hotel reservation foreach auth user and guest
     * @param AddHotelReservationRequest $request
     * @param $hotel_id
     * @return JsonResponse
     */
    public function addReservationForUserAndGuest(AddHotelReservationRequest $request, $hotel_id) :JsonResponse
    {
        $hotel = Hotel::find($hotel_id);
        if (!$hotel){
            return response()->json(['message' => __('hotels.hotel_not_active'), 'data' => null], 401);
        }
        if (!$hotel->status){
            return response()->json(['message' => __('hotels.hotel_not_active'), 'data' => null], 401);
        }
        $data = $request->all();
        $userLogged = Auth::check() ? Auth::user() : null;
        $data['name'] = $userLogged ? $userLogged->name : $request->name;
        $data['email'] = $userLogged ? $userLogged->email : $request->email;
        $code = $userLogged ? $userLogged->code : $request->code;
        $phone = $userLogged ? $userLogged->phone : $request->phone;
        $data['phone'] = $code.$phone;
        $data['hotel_id'] = $hotel->id;
        $data['city_id'] = $hotel->city_id;
        $data['user_id'] = $userLogged ? $userLogged->id : null;
        $data['hotel_email'] = $hotel->email;
        $data['hotel_address'] = $hotel->address;
        $data['hotel_image'] = $hotel->images[0];
        $data['status'] = 'current';
//        $data['pay_type'] = $request->pay_type;

        $hotelRoomType = $hotel->room_id;
        if (!in_array($request->room_type, $hotelRoomType)){
            return response()->json(['message' => __('hotels.room_type_not_available'), 'data' => null], 401);
        }

        $data['room_type'] = Room::where('id', $request->room_type)->first()->id;

//        $hotelAddedService = $hotel->added_service;
//        $hotelAddedServicePrice = array_filter($hotel->added_service_price);

        $roomsPrices = $hotel->room_type_price[$request->room_type];

        $prices = 0;
        $days = 0;
        $from = Carbon::make($request->going_date)->addDays(-1)->setTimezone('Asia/Riyadh');
        $to = Carbon::make($request->return_date);
        while($to->diff($from)->days){
            $from = $from->addDay();
            if ($from->englishDayOfWeek != 'Friday' && $from->englishDayOfWeek != 'Thursday'){
                $prices += $roomsPrices[0];
            }
            if ($from->englishDayOfWeek == 'Thursday'){
                $prices += $roomsPrices[1];
            }
            if ($from->englishDayOfWeek == 'Friday'){
                $prices += $roomsPrices[2];
            }
            $days += 1;
        }


//        return response()->json(['message' => $days, 'prices' => $prices], 401);
//        $addedServicesPrice = [];
//        $addedServices = [];
//        $hotelAddedServices = array_combine($hotelAddedService, $hotelAddedServicePrice);

//        foreach ($request->added_service as $service) {
//            if (isset($hotelAddedServices[$service])){
//                $addedServicesPrice[] = $hotelAddedServices[$service];
//                $addedServices[] = $service;
//            }
//        }

//        $total = ($room_price+array_sum($addedServicesPrice))*($request->person_count*$request->days_count);
//        $total = ($room_price)*($request->person_count*$request->days_count);
        $total = ($prices*$request->person_count);
        $addedValue = array_key_exists('added_value', settings()) ? settings('added_value') : 15;
        $addedValueAmount = ($total*$addedValue)/100;
        $data['total'] = $total+$addedValueAmount;
        $data['days_count'] = $days;
//        $data['added_service'] = $addedServices;
//        $data['added_service_price'] = $addedServicesPrice;

        $hotelReservation = HotelReservation::create($data);
        $data = $userLogged ? UserResource::make($userLogged) : HotelReservationResource::make($hotelReservation);

        /**
         * Send notification with reservation
         * success for authentication user only
         */

        if ($userLogged){

            // Check if invoice_id found or not
            $payment = Payment::where('invoice_id', $request->invoice_id)
                ->where('hotel_reservation_id' , $hotelReservation->id)->first();
            if (!$payment){
                $paymentData['invoice_id'] = $request->invoice_id;
                $paymentData['user_id'] = $userLogged->id;
                $paymentData['hotel_reservation_id'] = $hotelReservation->id;
                $paymentData['amount'] = $hotelReservation->total;
//                $hotelReservation->update(['pay_type' => $request->pay_type]);
                $this->savePayment($paymentData);
            }

            $title = __('hotel_reservations.reservation_success_title');
            $title = str_replace('@@', descriptions($hotel)->name, $title);
            $message = __('hotel_reservations.reservation_success_message');
            $message = str_replace('@@', descriptions($hotel)->name, $message);

            $userNotification = [
                'title' => $title,
                'message' => $message,
                'user_id' => $userLogged->id,
                'reservation_id' => $hotelReservation->id,
                'notification_type' => 'hotel',
            ];
            UsersNotification::create($userNotification);

            $notificationData['notification'] = [
                'title' => $title,
                'body' => $message,
                'page_id' => $hotelReservation->id,
                'type' => 'hotel',
                'vibrate' => 1,
                'priority' => 'high',
                'visibility'=> 1,
                'foreground'=> true,
                'no-cache' => 1,
                'force-start' => 1,
                'sound' => 'default'
            ];
            $target['to'] = $userLogged->device_token['token'];
            Notification::send($notificationData, $target);
            return response()->json([
                'message' => '',
                'data' => $notificationData,
            ], 200);
        }


        return response()->json(['message' => '', 'data' => $data], 200);

    }

    /**
     * Get all reservation by hotel id or hotel id and reservation status [current-finished]
     * @param $hotel_id
     * @param null $status
     * @return JsonResponse
     */
    public function getReservations($hotel_id = null, $status = null) :JsonResponse
    {
        $user = Auth::user();
//        $hotel = Hotel::find($hotel_id);
//        if (!$hotel){
//            return response()->json(['message' => __('hotels.hotel_not_found'), 'data' => null], 401);
//        }
        $reservations = HotelReservation::whereIn('hotel_reservations.status', ['finished', 'confirmed'])
            ->orderBy('hotel_reservations.id', 'desc')
            ->where('hotel_reservations.user_id', $user->id)
//            ->where('hotel_reservations.hotel_id', $hotel_id)
            ->get()->groupBy('status');

        $current = isset($reservations['confirmed']) ? $reservations['confirmed'] : [];
        $previous = isset($reservations['finished']) ? $reservations['finished'] : [];
        return response()->json(['message' => '', 'data' => [
            'current' => count($current) ? HotelReservationResource::collection($current) : [],
            'previous' => count($previous) ? HotelReservationResource::collection($previous) : [],
        ]], 200);

    }

    /**
     * Hotel evaluate
     * @param Request $request
     * @param $reservation_id
     * @return JsonResponse
     */
    public function evaluate(Request $request, $reservation_id) :JsonResponse
    {
        $validation = Validator::make($request->all(),
            [
                'evaluate_average' => 'required|in:1,2,3,4,5',
                'comment' => 'required|min:3|max:400',
            ],[],[
                'comment' => __('evaluates.comment'),
                'evaluate_average' => __('evaluates.evaluate_average')
            ]);

        if ($validation->fails()){
            return response()->json(['message' => $validation->errors()->first()], 400);
        }

        $user = Auth::user();

        $hotelReservation = HotelReservation::where('status', 'finished')
            ->where('id', $reservation_id)->where('user_id', $user->id)->first();

        if (!$hotelReservation){
            return response()->json(['message' => __('hotels.reservation_not_found')], 400);
        }

//        $hotel = Hotel::find($hotel_id);
//
//        if (!$hotel){
//            return response()->json(['message' => __('hotels.hotel_not_found'), 'data' => null], 401);
//        }
//        if (!$hotel->status){
//            return response()->json(['message' => __('hotels.hotel_not_active'), 'data' => null], 401);
//        }


        if ($hotelReservation->return_date > date('Y-m-d') || $hotelReservation->status != 'finished'){
            return response()->json(['message' => __('hotels.reservation_not_finished')], 400);
        }

        $isEvaluateBefore = ConsultingEvaluate::where('user_id', $user->id)
            ->where('hotel_id', $hotelReservation->hotel_id)
            ->where('hotel_reservation_id', $reservation_id)
            ->first();

        if ($isEvaluateBefore){
            return response()->json(['message' => __('hotels.evaluate_before')], 400);
        }

        $hotel_id = $hotelReservation->hotel_id;
        ConsultingEvaluate::create([
            'user_id' => $user->id,
            'hotel_id' => $hotel_id,
            'hotel_reservation_id' => $reservation_id,
            'comment' => $request->comment,
            'evaluate_average' => $request->evaluate_average,
        ]);
        $rate = DB::table('evaluates')
            ->selectSub("SELECT SUM(evaluate_average) FROM evaluates WHERE hotel_id={$hotel_id} LIMIT 1", 'evaluate_sum')
            ->selectSub("SELECT COUNT(evaluate_average) FROM evaluates WHERE hotel_id={$hotel_id} LIMIT 1", 'evaluate_count')->first();
        $rate = $rate->evaluate_sum/$rate->evaluate_count;
        $hotel = Hotel::find($hotel_id);
        if ($hotel){
            $hotel->update(['rate' => $rate]);
        }

        return response()->json(['message' => __('hotels.evaluate_successfully'), 'data' => UserResource::make($user)], 200);

    }

    /**
     * Add or remove hotel to favorite
     * @param $hotel_id
     * @return JsonResponse
     */
    public function addToFavorite($hotel_id) :JsonResponse
    {
        $user = Auth::user();
        $hotel = Hotel::find($hotel_id);

        if (!$hotel){
            return response()->json(['message' => __('hotels.hotel_not_found'), 'data' => null], 401);
        }
        if (!$hotel->status){
            return response()->json(['message' => __('hotels.hotel_not_active'), 'data' => null], 401);
        }
        $favoriteHotels = $user->hotelFavorites()->pluck('hotel_id')->toArray();
        $message = __('hotels.favorite_successfully');
        if (in_array($hotel_id, $favoriteHotels)){
            $message = __('hotels.remove_favorite_successfully');
        }
        $user->hotelFavorites()->toggle($hotel_id);
        return response()->json(['message' => $message, 'data' => UserResource::make($user)], 200);
    }

    /**
     * Get hotel rooms information
     * @param $hotel_id
     * @return JsonResponse
     */
    public function roomTypes($hotel_id) :JsonResponse
    {
        $hotel = Hotel::find($hotel_id);
        $roomsTypes = [];

        if ($hotel){
            $rooms = is_string($hotel->room_type) ? json_decode($hotel->room_type, true) : $hotel->room_type;
            $price = is_string($hotel->room_type_price) ? json_decode($hotel->room_type_price, true) : $hotel->room_type_price;
            $roomsTypes = array_combine($rooms, array_filter($price));
        }

        return response()->json(['message' => '', 'data' => $roomsTypes], 200);
    }

    /**
     * Hotel search
     * @param Request $request
     * @return JsonResponse
     */
    public function search(Request $request)
    {
        $languageId = currentLanguage()->id;
        $hotels = Hotel::where('hotels.status', 1)
            ->join('hotel_descriptions as hd', 'hd.hotel_id', 'hotels.id')
            ->where('hd.language_id', $languageId);

//        if ($request->added_service){
//            /** First way */
////            $addedService = null;
////            foreach ($request->added_service as $service) {
////                $addedService .= "\"$service\"".',';
////            }
////            $addedService = trim($addedService, ',');
////            $hotels->where('hotels.added_service', 'LIKE', '%'.$addedService.'%');
////
//            /** Second way */
//            foreach ($request->added_service as $service) {
//                $hotels->hasAddedService($service);
//            }
//        }
        if ($request->room_type){
            /** First way */
//            $roomType = null;
//            foreach ($request->room_type as $type) {
//                $roomType .= "\"$type\"".',';
//            }
//            $roomType = trim($roomType, ',');
//            $hotels->where('hotels.room_type', 'LIKE', '%'.$roomType.'%');

            /** Second way */
            foreach ($request->room_type as $roomType) {
                $hotels->hasRoomType($roomType);
            }
        }

        if ($request->city_id){
            $hotels->where('hotels.city_id', $request->city_id);
        }

        if ($request->sort == 'highest_rate'){
            $hotels->orderBy('hotels.rate', 'desc');
        }

        if ($request->sort == 'lowest_rate'){
            $hotels->orderBy('hotels.rate', 'asc');
        }

        $hotels->select([
                'hotels.*',
                'hd.name',
                'hd.address',
            ]
        );
//            ->selectSub("Select TRIM(LEADING '[' FROM SUBSTRING_INDEX(room_type_price,',',1))", 'first_room_price');


        if ($request->sort == 'highest_price'){
            $hotels->orderBy('hotels.first_room_type_price', 'desc');
        }

        if ($request->sort == 'lowest_price'){
            $hotels->orderBy('hotels.first_room_type_price', 'asc');
        }

        $hotels = $hotels->cursor();

        $hotelsWithPersonCount = [];

        if ($request->person_count){
            foreach ($hotels as $hotel) {
                $roomType = is_string($hotel->room_type) ? json_decode($hotel->room_type) : $hotel->room_type;
                if (!in_array($request->person_count, $roomType)){
                    if ($request->person_count > 4 && in_array(4, $roomType)){
                        $hotelsWithPersonCount[] = $hotel;
                    }
                    if ($request->person_count < 4 && in_array(4, $roomType)){
                        $hotelsWithPersonCount[] = $hotel;
                    }
                }
                if (in_array($request->person_count, $roomType)){
                    $hotelsWithPersonCount[] = $hotel;
                }
            }
        }

        $hotels = $request->person_count ? $hotelsWithPersonCount : $hotels;

        return response()->json(['message' => '', 'data' => HotelResource::collection($hotels)], 200);

    }


    /**
     * Get hotel reservation requires like room types with price
     * and added services with price
     * @param $hotel_id
     * @return JsonResponse
     */
    public function requires($hotel_id) :JsonResponse
    {
        $hotel = Hotel::find($hotel_id);

        if (!$hotel){
            return response()->json(['message' => __('hotels.hotel_not_found'), 'data' => null], 401);
        }
        if (!$hotel->status){
            return response()->json(['message' => __('hotels.hotel_not_active'), 'data' => null], 401);
        }
        $roomTypes = [];
//        $addedServices = [];

        if ($hotel){
            $roomTypes = is_string($hotel->room_type) ? json_decode($hotel->room_type, true) : $hotel->room_type;
            $roomTypesPrice = is_string($hotel->room_type_price) ? json_decode($hotel->room_type_price, true) : $hotel->room_type_price;
//            $addedServices = is_string($hotel->added_service) ? json_decode($hotel->added_service, true) : $hotel->added_service;
//            $addedServicesPrice = is_string($hotel->added_service_price) ? json_decode($hotel->added_service_price, true) : $hotel->added_service_price;

            $roomTypes = array_combine($roomTypes, array_filter($roomTypesPrice));
//            $addedServices = array_combine($addedServices, array_filter($addedServicesPrice));
        }
        return response()->json(['message' => '', 'data' => [
            'room_types' =>  $roomTypes,
//            'added_services' => $addedServices,
        ]], 200);

    }


    /**
     * @param $data
     */
    private function savePayment($data)
    {
        Payment::create($data);
    }

}
