<?php

namespace App\Http\Controllers\V1;


use App\Core\Mail\CancelBookingMail;
use App\Http\Controllers\Controller;
use App\Core\Service\BookingService;
use App\Core\Service\PropertyBookingEngineService;
use App\Core\Service\BookingTicketService;
use App\Core\Service\ChannelManagerPropertyMappingService;
use App\Core\Service\ChannelManagerBookingService;
use App\Core\Service\BookingRoomService;
use App\Core\Service\PropertyRoomAvailabilityService;
use App\Core\Validator\Booking\BookingUpdateValidator;
use App\Export\PropertyBookingListExport;
use App\Core\Service\NewBookingMailService;


use Carbon\Carbon;
use Illuminate\Http\Request;

use App;
use Illuminate\Mail\Mailer;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Exception;
use App\Exceptions\ApiErrorException;
use Illuminate\Support\Facades\Config;
use Maatwebsite\Excel\Facades\Excel;


class PropertyBookingController extends Controller
{


    private $request;
    private $bookingService;
    private $propertyBookingEngineService;
    private $bookingTicketService;
    private $bookingUpdateValidator;


    public function __construct(
        Request $request,
        Mailer $mailer,
        BookingService $bookingService,
        BookingRoomService $bookingRoomService,
        PropertyBookingEngineService $propertyBookingEngineService,
        BookingTicketService $bookingTicketService,
        ChannelManagerPropertyMappingService $channelManagerPropertyMappingService,
        ChannelManagerBookingService $channelManagerBookingService,
        PropertyRoomAvailabilityService $propertyRoomAvailabilityService,
        BookingUpdateValidator $bookingUpdateValidator,
        NewBookingMailService $newBookingMailService
    )
    {
        $this->request = $request;
        $this->mailer = $mailer;
        $this->bookingService = $bookingService;
        $this->bookingRoomService = $bookingRoomService;
        $this->propertyBookingEngineService = $propertyBookingEngineService;
        $this->bookingTicketService = $bookingTicketService;
        $this->channelManagerPropertyMappingService = $channelManagerPropertyMappingService;
        $this->channelManagerBookingService = $channelManagerBookingService;
        $this->propertyRoomAvailabilityService = $propertyRoomAvailabilityService;
        $this->bookingUpdateValidator = $bookingUpdateValidator;
        $this->newBookingMailService = $newBookingMailService;
    }

    public function getPropertyBookingList(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $getPropertyBooking = $this->bookingService->getBookingList($params);
            if ($getPropertyBooking['status'] != "success") {
                throw new ApiErrorException($getPropertyBooking['message']);
            }

            if (isset($params['excelExport']) && $params['excelExport']) {


                foreach ($getPropertyBooking['data'] as $bookingKey => $booking) {

                    $dataTableData[$bookingKey]['booking_channel'] = $booking['booking_channel']['name'];
                    $dataTableData[$bookingKey]['booking_code'] = $booking['booking_code'];
                    $dataTableData[$bookingKey]['name_surname'] = $booking['booking_contact']['nameSurname'];
                    $dataTableData[$bookingKey]['checkin_date'] = $booking['checkin_date'];
                    $dataTableData[$bookingKey]['checkout_date'] = $booking['checkout_date'];
                    $dataTableData[$bookingKey]['payment_type'] = $booking['booking_payment_type']['name'];
                    $dataTableData[$bookingKey]['total'] = $booking['total'];
                    $dataTableData[$bookingKey]['currency_code'] = $booking['currency_code'];
                    $dataTableData[$bookingKey]['status'] = $booking['booking_status']['name'];
                    $dataTableData[$bookingKey]['reservation_time'] = Carbon::createFromTimestamp($booking['reservation_time'])->toDateTimeString();

                }


                $fileNameHash = [
                    'property_id' => $params['property_id'],
                    'channel_id' => fillOnUndefined($params['filter'], 'channel_id'),
                    'booking_code' => fillOnUndefined($params['filter'], 'booking_code'),
                    'payment_type_code' => fillOnUndefined($params['filter'], 'payment_type_code'),
                    'status' => fillOnUndefined($params['filter'], 'status'),
                    'date_type' => fillOnUndefined($params['filter'], 'date_type'),
                    'date_range' => fillOnUndefined($params['filter'], 'date_range'),
                ];

                $fileName = 'PropertyBookingList-' . md5(implode('-', $fileNameHash)) . '.xlsx';
                $fileNamePath = 'excel/' . $fileName;
                $fileNamePublic = config('app.url') . '/' . $fileNamePath;

                $excelStore = Excel::store(new PropertyBookingListExport($dataTableData), $fileNamePath, 'public');

                if (!$excelStore) {
                    throw new ApiErrorException(lang('Mapping data not found'));
                }

                $data = [
                    'url' => $fileNamePublic
                ];

                //Delete files older than 1 hours
                $excelFileDir = public_path('excel');
                foreach (glob($excelFileDir . '/' . "*") as $file) {
                    if (filemtime($file) < time() - 3600) { // 6 hours 21600
                        unlink($file);
                    }
                }

                $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $data];

            } else {
                $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => ['booking' => $getPropertyBooking['data']]];
            }


        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }

    public function getPropertyBookingListFilter(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $getPropertyBookingFilter = $this->bookingService->getPropertyBookingListFilter($params);
            if ($getPropertyBookingFilter['status'] != "success") {
                throw new ApiErrorException($getPropertyBookingFilter['message']);
            }

            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $getPropertyBookingFilter['data']];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }

    public function getPropertyBookingDetail(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $bookingDetail = $this->bookingService->getBookingDetail($params);
            if ($bookingDetail['status'] != "success") {
                throw new ApiErrorException($bookingDetail['message']);
            }

            //BOOKING ADDON
            $bookingAddons = $bookingDetail['data']['booking_addon'];
            unset($bookingDetail['data']['booking_addon']);

            $bookingAddonList = [];
            foreach ($bookingAddons as $bookingAddon) {

                $bookingAddonAttributeList = [];
                $isHasAttribute = false;
                $attributeArray = [];
                if (!empty($bookingAddon['property_channel_addon']['property_addon']['attributeArray'])) {
                    $isHasAttribute = true;
                    $attributeArray = $bookingAddon['property_channel_addon']['property_addon']['attributeArray'];
                    $bookingAddonAttributes = json_decode($bookingAddon['attribute'], 1);
                    if (!is_null($bookingAddonAttributes)) {
                        foreach ($bookingAddonAttributes as $key => $bookingAddonAttribute) {
                            foreach ($bookingAddonAttribute as $bookingAddonAttributeKey => $bookingAddonAttributeValue) {

                                if (isset($bookingAddon['property_channel_addon']['property_addon']['attributeArray'][$bookingAddonAttributeKey])) {
                                    $bookingAddonAttributeList[] = [
                                        'key' => $bookingAddonAttributeKey,
                                        'name' => $bookingAddon['property_channel_addon']['property_addon']['attributeArray'][$bookingAddonAttributeKey]['name'],
                                        'language_key' => $bookingAddon['property_channel_addon']['property_addon']['attributeArray'][$bookingAddonAttributeKey]['language_key'],
                                        'value' => $bookingAddonAttributeValue,
                                    ];
                                }

                            }
                        }
                    }
                }

                $bookingAddonList[] = [
                    'id' => $bookingAddon['id'],
                    'booking_id' => $bookingAddon['booking_id'],
                    'property_channel_addon_id' => $bookingAddon['property_channel_addon_id'],
                    'count' => $bookingAddon['count'],
                    'amount' => $bookingAddon['amount'],
                    'total' => $bookingAddon['total'],
                    'min_stay' => $bookingAddon['property_channel_addon']['min_stay'],
                    'currency_code' => $bookingAddon['currency_code'],
                    'name' => $bookingAddon['property_channel_addon']['property_addon']['fact']['name'],
                    'title' => $bookingAddon['property_channel_addon']['title'],
                    'language_key' => $bookingAddon['property_channel_addon']['property_addon']['fact']['language_key'],
                    'icon' => $bookingAddon['property_channel_addon']['property_addon']['fact']['icon'],
                    'isHasAttribute' => $isHasAttribute,
                    'attributeArray' => $attributeArray,
                    'attribute' => $bookingAddonAttributeList
                ];

            }

            $bookingDetail['data']['booking_addon'] = $bookingAddonList;
            //BOOKING ADDON

            //DAILY AMOUNT BY ROOM
            foreach ($bookingDetail['data']['booking_room'] as $roomKey => $roomDetail) {

                if (!empty($roomDetail['room_rate_mapping']['property_room'])) {
                    $bookingDetail['data']['booking_room'][$roomKey]['room_name'] = $roomDetail['room_rate_mapping']['property_room']['name'];
                }

                if (!empty($roomDetail['room_rate_mapping']['property_room_rate'])) {
                    $bookingDetail['data']['booking_room'][$roomKey]['room_rate_name'] = $roomDetail['room_rate_mapping']['property_room_rate']['name'];
                }

                $diffInDays = Carbon::parse($roomDetail['checkin_date'])->diffInDays(Carbon::parse($roomDetail['checkout_date']));
                $baseRateDaily = moneyDoubleFormatDecimal($roomDetail['total'] / $diffInDays);

                $roomDailyAmount = [];


                if (!empty($roomDetail['daily_amount'])) {
                    $roomDetailDailyAmount = json_decode($roomDetail['daily_amount'], 1);
                    if (!empty($roomDetailDailyAmount) && isset($roomDetailDailyAmount)) {
                        foreach ($roomDetailDailyAmount as $roomRateAmount) {
                            $roomDailyAmount[] = [
                                'date' => $roomRateAmount['date'],
                                'amount' => $roomRateAmount['amount'],
                                'currency_code' => $roomRateAmount['currency_code'],
                            ];
                        }
                    }
                }

                if (empty($roomDailyAmount)) {
                    $roomRateDetail = is_array($roomDetail['rate_detail']) ? $roomDetail['rate_detail'] : json_decode($roomDetail['rate_detail'], 1);
                    if (!empty($roomRateDetail) && isset($roomRateDetail['days'])) {
                        foreach ($roomRateDetail['days'] as $roomRateDay => $roomRateAmount) {
                            $roomDailyAmount[] = [
                                'date' => Carbon::parse($roomRateDay)->toDateString(),
                                'amount' => $roomRateAmount,
                                'currency_code' => $roomDetail['currency_code'],
                            ];
                        }
                    }
                }

                if (empty($roomDailyAmount)) {
                    $currentDate = $roomDetail['checkin_date'];
                    for ($i = 0; $i < $diffInDays; $i++) {
                        $roomDailyAmount[] = [
                            'date' => $currentDate,
                            'amount' => $baseRateDaily,
                            'currency_code' => $roomDetail['currency_code'],
                        ];
                        $currentDate = Carbon::parse($currentDate)->addDay()->toDateString();
                    }
                }

                $bookingDetail['data']['booking_room'][$roomKey]['daily_amount'] = $roomDailyAmount;

                $extraParam = null;
                if (!empty($roomDetail['extra_param'])) {
                    $extraParamDecode = json_decode($roomDetail['extra_param'], 1);

                    foreach ($extraParamDecode as $extraParamKey => $extraParamValue) {

                        $extraParamTitle = explode('_', $extraParamKey);
                        foreach ($extraParamTitle as $extraParamTitleKey => $extraParamTitleValue) {
                            $extraParamTitle[$extraParamTitleKey] = ucwords($extraParamTitleValue);
                        }
                        $extraParamTitle = implode(' ', $extraParamTitle);

                        $extraParam[$extraParamKey] = [
                            'title' => $extraParamTitle,
                            'value' => $extraParamValue,
                        ];
                    }

                }

                $bookingDetail['data']['booking_room'][$roomKey]['extra_param'] = $extraParam;
                $bookingDetail['data']['booking_room'][$roomKey]['occupancyFormatted'] = occupancyCodeFormatted($roomDetail['occupancy_code']);

            }
            //DAILY AMOUNT BY ROOM


            if (empty($bookingDetail['data']['is_viewed'])) {
                $this->bookingService->update($params['booking_id'], ['is_viewed' => 1]);
            }

            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => ['booking_detail' => $bookingDetail['data']]];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);

    }

    public function sendBookingEmail(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $bookingDetail = $this->bookingService->getBookingDetail($params);
            if ($bookingDetail['status'] != "success") {
                throw new ApiErrorException($bookingDetail['message']);
            }

            if (!in_array($bookingDetail['data']['status'], [0,1])) {
                throw new ApiErrorException('Only active and canceled reservation emails can be sent');
            }

            if (in_array($bookingDetail['data']['status'], [0])) {
                $mailParams = ['booking_id' => $params['booking_id']];
                $this->mailer->onQueue('cancelBookingMail', new CancelBookingMail($mailParams));
            }

            if (in_array($bookingDetail['data']['status'], [1])) {
                $mailParams = ['booking_id' => $params['booking_id']];
                $this->newBookingMailService->process($mailParams);
            }


            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => []];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);

    }

    public function bookEngineDashboard(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $getPropertyBookingEngine = $this->propertyBookingEngineService->bookEngineDashboard($params);
            if ($getPropertyBookingEngine['status'] != "success") {
                throw new ApiErrorException($getPropertyBookingEngine['message']);
            }

            $responseData['booking_engine'] = $getPropertyBookingEngine['data'];


            //Cache
            $getBookingDetailedListCacheKey = md5('getBookingDetailedList-' . $params['property_id']);
            if (Cache::has($getBookingDetailedListCacheKey)) {
                $responseDataCache = Cache::get($getBookingDetailedListCacheKey);

                $responseData['all_booking_count'] = $responseDataCache['all_booking_count'];
                $responseData['success_booking_count'] = $responseDataCache['success_booking_count'];
                $responseData['pre_booking_count'] = $responseDataCache['pre_booking_count'];
                $responseData['conversion_rate'] = $responseDataCache['conversion_rate'];
                $responseData['total_pax_count'] = $responseDataCache['total_pax_count'];

            } else {

                $getPropertyBooking = $this->bookingService->getBookingDetailedList($params);
                if ($getPropertyBooking['status'] != "success") {
                    throw new ApiErrorException($getPropertyBooking['message']);
                }

                $bookings = collect($getPropertyBooking['data']);
                $channelBookings = $bookings->where('channel_id', '=', 1);
                $getBookingEngineBookings = $channelBookings->all();
                $paxCountArray = $channelBookings->where('status', '=', 1)->map(function ($booking) {
                    $roomPaxCount = collect($booking['booking_room'])->map(function ($room) {
                        return collect($room['room_pax'])->count();
                    })->values()->first();
                    return [
                        'booking_id' => $booking['id'],
                        'room_pax_count' => $roomPaxCount,
                    ];

                })->values()->all();

                $totalPaxCount = collect($paxCountArray)->sum('room_pax_count');

                $allBookingCount = $channelBookings->count();
                $preBookingCount = $channelBookings->where('status', '=', 2)->count();
                $successBookingCount = $channelBookings->where('status', '=', 1)->count();

                $conversionRate = $allBookingCount > 0 ? ($successBookingCount * 100) / $allBookingCount : 0;

                $responseData['all_booking_count'] = $allBookingCount;
                $responseData['success_booking_count'] = $successBookingCount;
                $responseData['pre_booking_count'] = $preBookingCount;
                $responseData['conversion_rate'] = number_format($conversionRate, 2);
                $responseData['total_pax_count'] = $totalPaxCount;

            }


            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $responseData];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);

    }

    public function bookingEngineContractUpload(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            $params =
                [
                    "property_id" => $request->input('property_id'),
                    "contract_file" => $request->file('contract_file'),
                    "user_id" => $this->request->auth->id
                ];

            $uploadResponse = $this->propertyBookingEngineService->contractFileUpload($params);
            if ($uploadResponse['status'] != "success") {
                throw new ApiErrorException($uploadResponse['message']);
            }


            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $uploadResponse['data']];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);

    }

    public function getPropertyTransactionList(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $getPropertyTransaction = $this->bookingService->getTransactionList($params);
            if ($getPropertyTransaction['status'] != "success") {
                throw new ApiErrorException($getPropertyTransaction['message']);
            }

            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => ['transactions' => $getPropertyTransaction['data']]];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }

    public function updateBooking(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            DB::beginTransaction();

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            if (!isset($params['property_id'])) {
                $params = $this->request->requestParams;
            }

            $validationResult = $this->bookingUpdateValidator->validate($params);
            if ($validationResult->errors()->first()) {
                $errors = $validationResult->errors()->all();
                throw new ApiErrorException($errors);
            }

            $bookingstatusList = $this->bookingService->getBookingstatusList();
            $bookingstatusListCollect = collect($bookingstatusList['data']);
            if ($bookingstatusListCollect->where('id', $params['status'])->count() <= 0) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $bookingRequest = [
                'criteria' => [
                    ['field' => 'id', 'condition' => '=', 'value' => $params['booking_id']],
                ],
                'with' => ['bookingRoom','propertyBookingEngineSearch'],
                'firstRow' => true
            ];

            $booking = $this->bookingService->select($bookingRequest);

            if ($booking['status'] != 'success') {
                throw new ApiErrorException($booking['message']);
            }

            if (empty($booking['data'])) {
                throw new ApiErrorException('Booking not found.');
            }

            $booking = $booking['data'];

            $isNonRefundable = false;
            if($params['status'] == 0) {
                foreach ($booking['booking_room'] as $roomDetail) {
                    $cancellationPolicy = json_decode($roomDetail['cancellation_policy'],1);
                    if(!empty($cancellationPolicy) && is_array($cancellationPolicy)) {
                        if(isset($cancellationPolicy['isNonRefundable']) && $cancellationPolicy['isNonRefundable']) {
                            $isNonRefundable = true;
                            break;
                        }
                    }
                }
            }

            //Trivago Check
            /*if(isset($booking['property_booking_engine_search']['referrer']) && $booking['property_booking_engine_search']['referrer'] == 'trivago:trivago') {
                if($isNonRefundable) {
                    throw new ApiErrorException('Refunds are not permitted for non-refundable transactions received through Trivago.');
                }
            }*/


            $bookingUpdateParam = [];
            $bookingUpdateAvailableColumns = ['total', 'status', 'currency_code'];
            foreach ($params as $param => $value) {
                if (in_array($param, $bookingUpdateAvailableColumns)) {
                    $bookingUpdateParam[$param] = $value;
                }
            }

            $action = null;
            $percentage = 1;

            if ($booking['status'] == 0) {
                $percentage = 0;
            } elseif ($bookingUpdateParam['total'] > $booking['total']) {
                $action = 'INC';
                $percentage = ($bookingUpdateParam['total'] - $booking['total']) / $booking['total'] * 100;
            } else {
                $action = 'DEC';
                $percentage = ($booking['total'] - $bookingUpdateParam['total']) / $booking['total'] * 100;
            }

            $bookingUpdate = $this->bookingService->update($booking['id'], $bookingUpdateParam);

            if ($bookingUpdate['status'] != 'success') {
                throw new ApiErrorException($booking['message']);
            }


            foreach ($booking['booking_room'] as $room) {

                if (!is_null($action)) {

                    $totalAmount = $room['total'];
                    $affectedAmount = ($room['total'] * $percentage) / 100;

                    if ($action == 'INC') {
                        $totalAmount = $totalAmount + $affectedAmount;
                    }
                    if ($action == 'DEC') {
                        $totalAmount = $totalAmount - $affectedAmount;
                    }

                    $bookingRoomUpdate = $this->bookingRoomService->update($room['id'], ['total' => $totalAmount]);

                    if ($bookingUpdate['status'] != 'success') {
                        throw new ApiErrorException($bookingRoomUpdate['message']);
                    }

                }

                //Availability Decrease
                if (in_array($params['status'], [0, 3]) && $booking['status'] == 1) {

                    $dateByDay = [];
                    $diffInDays = Carbon::parse($room['checkin_date'])->floatDiffInDays(Carbon::parse($room['checkout_date']));
                    for ($i = 0; $i < $diffInDays; $i++) {
                        $dateByDay[] = Carbon::parse($room['checkin_date'])->addDay($i)->format('Y-m-d');
                    }

                    foreach ($dateByDay as $day) {

                        $requestParam = [
                            'criteria' => [
                                ['field' => 'property_id', 'condition' => '=', 'value' => $booking['property_id']],
                                ['field' => 'property_room_id', 'condition' => '=', 'value' => $room['room_id']],
                                ['field' => 'availability_type_id', 'condition' => '=', 'value' => 1],
                                ['field' => 'date', 'condition' => '=', 'value' => $day]
                            ],
                            'firstRow' => true,
                        ];

                        $dateAvailability = $this->propertyRoomAvailabilityService->select($requestParam);

                        if ($dateAvailability['status'] == 'success') {
                            $currentAvailability = $dateAvailability['data']['availability'];
                            $currentAvailability = $currentAvailability + 1;
                            $this->propertyRoomAvailabilityService->update($dateAvailability['data']['id'], ['availability' => $currentAvailability]);
                        }

                    }


                }

            }


            //PUSH CHANNEL MANAGER QUEUE
            //if ($booking['channel_id'] == 1) {

            $type = 'Modify';

            if (in_array($params['status'], [1, 2, 3])) {
                $type = 'Modify';
            }

            if (in_array($params['status'], [0])) {
                $type = 'Cancel';
            }

            $channelManagerPropertyMappingCriteria = [
                'criteria' =>
                    [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $booking['property_id']],
                        ['field' => 'channel_manager_property_id', 'condition' => '=', 'value' => null],
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ]
            ];

            $channelManagerPropertyMapping = $this->channelManagerPropertyMappingService->select($channelManagerPropertyMappingCriteria);

            if ($channelManagerPropertyMapping['status'] == 'success' && !empty($channelManagerPropertyMapping['data'])) {

                foreach ($channelManagerPropertyMapping['data'] as $channelPropertyData) {

                    $extraParamDecode = json_decode($booking['extra_param'], 1);

                    if($channelPropertyData['channel_manager_id'] == 11 && !isset($extraParamDecode['trv_reference'])) {
                        continue;
                    }

                    //Yandex
                    if(in_array($channelPropertyData['channel_manager_id'],[13])) {
                        continue;
                    }

                    $channelManagerBookingCreateParam = [
                        'property_id' => $booking['property_id'],
                        'booking_id' => $booking['id'],
                        'channel_manager_id' => $channelPropertyData['channel_manager_id'],
                        'type' => $type,
                    ];

                    $channelManagerBookingCreate = $this->channelManagerBookingService->create($channelManagerBookingCreateParam);

                }

            }

            //}
            //PUSH CHANNEL MANAGER QUEUE


            //Booking Ticket Log
            $bookingTicketRequest = [
                'criteria' => [
                    ['field' => 'booking_id', 'condition' => '=', 'value' => $booking['id']],
                ],
                'firstRow' => true
            ];

            $bookingTicket = $this->bookingTicketService->select($bookingTicketRequest, ['id']);

            $userId = isset($this->request->auth->id) ? $this->request->auth->id : 1;

            $createBookingTicketParams = [];
            if (empty($bookingTicket['data'])) {

                $createBookingTicketParams = [
                    'booking_id' => $booking['id'],
                    'code' => getTicketCodeGenerate('TCK'),
                    'user_id' => $userId,
                    'is_log' => true,
                    'log' => json_encode($booking),
                    'status' => 1
                ];

            } else {

                $createBookingTicketParams = [
                    'parent_id' => $bookingTicket['data']['id'],
                    'booking_id' => $booking['id'],
                    'user_id' => $userId,
                    'is_log' => true,
                    'log' => json_encode($booking),
                    'status' => 1
                ];

            }

            $bookingTicketCreate = $this->bookingTicketService->create($createBookingTicketParams);
            //Booking Ticket Log

            if ($type == 'Cancel') {
                $notificationCancelToPropertyUser = [
                    'booking_id' => $booking['id'],
                ];

                $this->mailer->onQueue('cancelBookingMail', new CancelBookingMail($notificationCancelToPropertyUser));
            }


            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => ['transactions' => $bookingUpdate['data']]];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }

        if ($response['status']) {
            DB::commit();
        } else {
            DB::rollBack();
        }

        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }

    public function getBookingPayment(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $params['user_id'] = $this->request->auth->id;

            $getBookingPayment = $this->bookingService->getBookingPayment($params);
            if ($getBookingPayment['status'] != "success") {
                throw new ApiErrorException($getBookingPayment['message']);
            }

            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $getBookingPayment['data']];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);

    }


}
