<?php

namespace App\Http\Controllers\Web;

use App\City;
use App\Hotel;
use App\Helpers\NotificationHelper;
use App\Http\Requests\AddReservationRequest;
use App\Jobs\InvitationJob;
use App\Mail\InvitationMail;
use App\Occasion;
use App\Region;
use App\Reservation;
use App\Http\Controllers\Controller;
use App\Sector;
use App\Service;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\View\View;


class ReservationController extends Controller
{

    protected $view = 'web.reservations.';

    /**
     * Show reservation page to reserve hall
     * @param Hotel $hall
     * @return Factory|View
     */
    public function reservationPage(Hotel $hall)
    {

        $user = Auth::user();

        if ($user->role != 'user'){
            return  redirect()->route('home');
        }

        $region = Region::withDescription(null, $hall->region_id);
        $city = City::withDescription(null, $hall->city_id);
        $sector = Sector::withDescription(null, $hall->sector_id);

        /**
         * Check if whether region or city or sector not deleted
         */
        if (!$region || !$city || !$sector){
            return redirect()->route('home');
        }

        // used in increment dates in javascript
//        $availableDatesFrom = [];
//        $availableDatesTo = [];
        // to check date value when date input changed
        $availableDates = [];
        $years = [];
//        $isDiscount = [];
        $discountPercentage = [];

        $hall->available_dates = json_decode($hall->available_dates);
        if (is_array($hall->available_dates) && count($hall->available_dates)){
            foreach ($hall->available_dates as $key => $available_date) {

                $from = Carbon::make($available_date['from'])->addDays(-1);
                $to = Carbon::make($available_date['to']);
                while($to->diff($from)->days){
                    $from = $from->addDay();
                    $availableDates[] = $from->format('Y-m-d');
                    $years[] = $from->format('Y');
                    $months[] = $from->format('M');
//                    array_push($isDiscount, $available_date['discount']);
                    array_push($discountPercentage, $available_date['discount_percentage']);

                }

//                array_push($availableDatesFrom, $available_date['from']);
//                array_push($availableDatesTo, $available_date['to']);
//                array_push($discountPercentage, $available_date['discount_percentage']);
            }
        }


//        $availableDatesFrom = json_encode($availableDatesFrom);
//        $availableDatesTo = json_encode($availableDatesTo);
//        $availableDates = json_encode($availableDates);
        $years = array_unique($years);
        $months = array_unique($months);
//        $isDiscount = json_encode($isDiscount);
//        $discountPercentage = json_encode($discountPercentage);

//        dd($discountPercentage, $availableDates);
//        dd($hall->available_dates);
//        dd($availableDates);

        $services = Service::withDescription(null, $hall->reservation_type);
        $addedServices = json_decode($hall->added_services);
        $occasions = Occasion::withDescription($hall->occasions);


        return view($this->view.'reservation_page', compact(
            'hall',
//            'availableDatesFrom',
//            'availableDatesTo',
            'availableDates',
            'years',
            'months',
            'services',
            'addedServices',
            'occasions',
//            'isDiscount',
            'discountPercentage'
        ));
    }

    /**
     * Show reservation details in user profile
     * @param Reservation $reservation
     * @return Factory|RedirectResponse|View
     */
    public function reservationDetails(Reservation $reservation)
    {
        $user = Auth::user();
        $view = null;

        if(!$reservation->hall->hall_status){
            return redirect()->route('home');
        }

        // Check for user
        if ($user->role == 'user'){

            $view = 'user_reservation_details';

            if ($reservation->user_id != $user->id){
                return redirect()->route('home');
            }

            if (in_array($reservation->re_status, ['waiting_for_pay', null])){
                return redirect()->route('reservation.payNow', $reservation->id);
            }
        }

        // Check for user
        if ($user->role == 'provider'){

            $view = 'provider_reservation_details';

            if ($reservation->provider_id != $user->id){
                return redirect()->route('home');
            }
        }

        $userReservation = Reservation::userReservations(null, null, null, null, null, $reservation->id);
        $services = Service::withDescription($reservation->services);
        $addedServices = [];
        $hallAddedServices = json_decode($reservation->hall->added_services);

        foreach ($hallAddedServices as $key => $hallAddedService) {
            if ($reservation->added_services[$key] == $hallAddedService->id){
                $addedServices[] = $hallAddedService;
            }
        }

        $addedValue = array_key_exists('added_value', settings()) ? settings('added_value') : 15;
        $sitePercentage = array_key_exists('website_percentage', settings()) ? settings('website_percentage') : 15;
        $sitePercentageAmount = (($userReservation->total-$userReservation->added_value_amount)*$sitePercentage)/100;

        return view($this->view.$view, compact('userReservation', 'services', 'addedServices', 'sitePercentage', 'addedValue', 'sitePercentageAmount'));
    }


    /**
     * Create new reservation to hall
     * @param AddReservationRequest $request
     * @param Hotel $hall
     * @return \Illuminate\Http\JsonResponse
     */
    public function addReservation(AddReservationRequest $request, Hotel $hall)
    {

        if ($request->ajax()){
            if (!Auth::check()){
                return response()->json(['url' => route('user.login')]);
            }

            $lastReservation = Reservation::orderBy('id', 'desc')->first();
            $re_no = $lastReservation ? ($lastReservation->re_no+1) : '200';
            $user = Auth::user();
            $total = [];
            $addedValueAmount = [];
            $minCapacity = $hall->min_capacity;
            $addedServicePrice = 0;
            $addedValue = array_key_exists('added_value', settings()) ? settings('added_value') : 15;
            $websitePercentage = array_key_exists('website_percentage', settings()) ? settings('website_percentage') : 15;
            $servicesPrice = Service::whereIn('id', $request->services ?? [])->sum('price');
            $hallServices = is_string($hall->added_services) ? json_decode($hall->added_services) : $hall->added_services;

            foreach ($hallServices as $key => $addedService) {
                if (in_array($addedService->id, $request->added_services)){
                    $addedServicePrice += $addedService->price;
                }
            }


            $userSelectedDays = $request->re_days;//[]; // User-selected days from request
            $isDiscount = []; // Days that have a discount

//            $from = Carbon::make($request->re_date_from)->addDays(-1);
//            $to = Carbon::make($request->re_date_to);
//            while($to->diff($from)->days){
//                $from = $from->addDay();
//                $userSelectedDays[] = $from->format('m/d/Y');
//            }

            $availableDates = is_string($hall->available_dates) ? json_decode($hall->available_dates, true) : $hall->available_dates;
            if (count($availableDates)){
                foreach ($availableDates as $key => $available_date) {

                    $from = Carbon::make($available_date['from'])->addDays(-1);
                    $to = Carbon::make($available_date['to']);
                    while($to->diff($from)->days){
                        $from = $from->addDay();
                        if (in_array($from->format('Y-m-d'), $userSelectedDays)){
                            $isDiscount[] = ['discount_percentage' => $available_date['discount_percentage'], 'date' => $from->format('Y-m-d')];
                        }
                    }
                }
            }

            if (count($isDiscount)){
                foreach ($isDiscount as $key => $discount) {
                    if ($hall->reservation_type == 'person_count'){
                        // check if person count greater than min capacity
                        $personCount = $minCapacity > $request->person_count ? $minCapacity : $request->person_count;
                        $personCount = $personCount > $hall->total_capacity ? $hall->total_capacity : $personCount;
                        $personPrice = ($personCount*$hall->booking_amount_per_person)+(($addedServicePrice*$personCount)+($servicesPrice*$personCount));
                        $personPrice_added_value = ($personPrice*$addedValue)/100;
//                    $personPrice_website_percentage = ($personPrice*$websitePercentage)/100;
                        $personPrice = $personPrice+$personPrice_added_value; //+$personPrice_website_percentage
                        $personPrice = $personPrice-(($personPrice*$discount['discount_percentage'])/100);
                        $total[] = $personPrice;
                        $addedValueAmount[] = $personPrice_added_value;
                    }

                    if ($hall->reservation_type == 'days_count'){
//                    $daysCount = count($isDiscount);
                        $dayPrice = $hall->booking_amount_per_day+$addedServicePrice+$servicesPrice;
//                    $dayPrice_website_percentage = ($dayPrice*$websitePercentage)/100; // 15
                        $dayPrice = $dayPrice-(($dayPrice*$discount['discount_percentage'])/100);
                        $dayPrice_added_value = ($dayPrice*$addedValue)/100;
                        $dayPrice = $dayPrice+$dayPrice_added_value; //+$dayPrice_website_percentage
                        $total[] = $dayPrice;
                        $addedValueAmount[] = $dayPrice_added_value;

                    }
                }
            }

            $total = array_sum($total); // 20389.5*2 = 40779
            $addedValueAmount = array_sum($addedValueAmount); // 20389.5*2 = 40779

            $isReservedBefore = Reservation::where('user_id', $user->id)
                ->where('hall_id', $hall->id)->whereNull('re_status')->first();

            $data = [
                're_no' => $re_no,
                're_way' => $hall->reservation_way,
                'services' => $request->services ? $request->services : [],
                'added_services' => $request->added_services ? $request->added_services : [],
                'person_count' => $request->person_count ? $request->person_count : null,
                'total' => $total,
                'added_value_amount' => $addedValueAmount,
                're_days' => $userSelectedDays,
                're_date_from' => date('Y-m-d', strtotime($userSelectedDays[0])),
                're_date_to' => date('Y-m-d', strtotime(array_last($userSelectedDays))),
//                    're_date_from' => date('Y-m-d', strtotime($request->re_date_from)),
//                    're_date_to' => date('Y-m-d', strtotime($request->re_date_to)),
                'user_id' => $user->id,
                'provider_id' => $hall->provider->id,
                'hall_id' => $hall->id,
                'occasion_id' => $request->occasion_id,
            ];

            if ($isReservedBefore){
                unset($data['re_no']);
                $isReservedBefore->update($data);
            } else {
                $reserevation = Reservation::create($data);
            }


            return response()->json(['url' => route('reservation.payNow', $reserevation->id ?? $isReservedBefore->id)]);

//            if ($hall->reservation_way == 'direct'){
//                return response()->json(['url' => route('reservation.payNow', $reserevation->id)]);
//            }
//            if ($hall->reservation_way == 'accept_request'){
//                return response()->json(['url' => route('user.profile')]);
//            }
        }

    }


    public function payNow(Reservation $reservation)
    {
        $user = Auth::user();

        if ($user->role != 'user' || $reservation->user_id != $user->id){
            return redirect()->route('home');
        }

        if (in_array($reservation->re_status, ['confirmed', 'reject', 'canceled', 'unconfirmed', 'finished'])){
            return redirect()->route('home');
        }

        $hall = Hotel::find($reservation->hall_id);
        $hallAddedServices = is_string($hall->added_services) ? json_decode($hall->added_services) : $hall->added_services;
        $addedServices = [];
        $addedValue = array_key_exists('added_value', settings()) ? settings('added_value') : 15;


        foreach ($hallAddedServices as $key => $hallAddedService) {
            if ($reservation->added_services[$key] == $hallAddedService->id){
                $addedServices[] = $hallAddedService;
            }
        }

        $reservationServices = is_string($reservation->services) ? json_decode($reservation->services, true) : $reservation->services;
        $services = count($reservationServices) ? Service::withDescription($reservationServices) : [];

        return view($this->view.'pay_now', compact('reservation', 'hall', 'services', 'addedServices', 'addedValue'));
    }

    public function sendReservationRequest(Reservation $reservation)
    {
        $route = route('user.profile');
        $reservation->update(['re_status' => 'unconfirmed']);
        return response()->json(['message' => __('reservations.request_send_successfully'), 'route' => $route, 'send_request' => true]);
    }

    /**
     * Change reservation status foreach user and provider
     * @param Request $request
     * @param $reservation
     * @return \Illuminate\Http\JsonResponse
     */
    public function reservationStatusOperation(Request $request, $reservation)
    {
        if ($request->ajax()){
            $reservation = Reservation::find($reservation);
            $user = Auth::user();
            $errors = [];
            $cancelledFrom = null;
            $reStatus = null;

            if ($user->role == 'user'){
                $cancelledFrom = 'user';
                $reStatus = 'canceled';
                if (!$reservation || $reservation->user_id != $user->id){
                    $errors[] = __('reservations.reservation_not_found');
                }
            }
            if ($user->role == 'provider'){
                if (!$reservation || $reservation->provider_id != $user->id){
                    $errors[] = __('reservations.reservation_not_found');
                }
                if (!in_array( $request->re_status, ['canceled', 'reject', 'waiting_for_pay'])){
                    $errors[] = __('reservations.unknown_reservation_status');
                }
                $reStatus = $request->re_status;
                $cancelledFrom = in_array($request->re_status, ['canceled', 'reject']) ? 'provider' : null;
            }

            if (time() >= strtotime($reservation->re_date_from)){
                $errors[] =  __('reservations.cannot_do_reservation_action');
            }

            if (count($errors)){
                return response()->json(['errors' => $errors[0]]);
            }

            $reservation->update(['re_status' => $reStatus, 'canceled_from' => $cancelledFrom]);


            // waiting_for_pay => accept, [reject, canceled]
//            NotificationHelper::sendNotification('', '');

            return response()->json(['message' => __('reservations.reservation_action_done')]);

        }
    }

    public function invitation(Request $request, $reservationId)
    {
        if ($request->ajax()){
            $data = [];
            $user =  Auth::user();
            $reservation = Reservation::where('id', $reservationId)
                ->where('user_id', $user->id)->where('re_status', 'confirmed')->first();


            if ($reservation->person_count == $reservation->invitation_count){
                return response()->json(['errors' => __('reservations.invitation_limit')]);
            }

            $emailRule = $request->email ? 'required|email' : 'nullable';
            $phoneRule = $request->phone ? 'required|regex:/^(05){1}([0-9]{8})$/' : 'nullable';

            $validation = Validator::make($request->all(),
                [
                    'email' => $emailRule,
                    'phone' => $phoneRule,
                ]
                , [], [
                    'email' => __('reservations.email'),
                    'phone' => __('reservations.phone'),
                ]);

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

            }

            if ($request->email){
                $data['title'] = __('reservations.invitation_title');
                $data['user'] = $request->email;
                $data['inviting_name'] =$user->name;
//                try{
//                    InvitationJob::dispatch(new InvitationMail($data, view('web.members.emails.invitations')));
//                } catch (\Exception $e){
//
//                }
            }



            $invitations = $reservation->invitations ? $reservation->invitations : [];
            $invitations[] = $request->email ?? $request->phone;
            $reservation->update([
                'invitation_count' => ($reservation->invitation_count+1),
                'invitations' => $invitations,
            ]);

            return response()->json(['message' => __('reservations.invitation_successfully'), 'email_phone' => $request->email ?? $request->phone]);
        }
    }
}
