<?php

namespace App\Console\Commands\ChannelManager;

use App\Core\Mail\CancelBookingMail;
use App\Core\Mail\LogMail;
use App\Core\Mail\ModifiedBookingMail;
use App\Core\Service\BookingContactService;
use App\Core\Service\BookingPaymentService;
use App\Core\Service\BookingRoomService;
use App\Core\Service\BookingService;
use App\Core\Service\ChannelManager\Reseliva;
use App\Core\Service\ChannelManagerBookingService;
use App\Core\Service\ChannelManagerMappingService;
use App\Core\Service\ChannelManagerPropertyMappingService;
use App\Core\Service\ChannelManagerPropertyRateMappingService;
use App\Core\Service\ChannelManagerService;
use App\Core\Service\NewBookingMailService;
use App\Core\Service\PropertyRoomAvailabilityService;
use App\Exceptions\ApiErrorException;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Console\Command;
use Illuminate\Mail\Mailer;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ReservationPullService extends Command
{
    protected $signature = 'cron:reservation-pull-service';

    protected $description = '';
    protected $mailer;
    protected $channelService;
    protected $channelManagerPropertyMappingService;
    protected $bookingService;
    protected $propertyRoomAvailabilityService;
    protected $newBookingMailService;

    public function __construct(
        Mailer $mailer,
        ChannelManagerMappingService $channelManagerMappingService,
        ChannelManagerPropertyMappingService $channelManagerPropertyMappingService,
        BookingService $bookingService,
        BookingContactService $bookingContactService,
        BookingRoomService $bookingRoomService,
        BookingPaymentService $bookingPaymentService,
        PropertyRoomAvailabilityService $propertyRoomAvailabilityService,
        NewBookingMailService $newBookingMailService,
        ChannelManagerService $channelManagerService,
        ChannelManagerBookingService $channelManagerBookingService
    )
    {
        parent::__construct();
        $this->mailer = $mailer;
        $this->channelManagerMappingService = $channelManagerMappingService;
        $this->channelManagerPropertyMappingService = $channelManagerPropertyMappingService;
        $this->bookingService = $bookingService;
        $this->bookingContactService = $bookingContactService;
        $this->bookingRoomService = $bookingRoomService;
        $this->bookingPaymentService = $bookingPaymentService;
        $this->propertyRoomAvailabilityService = $propertyRoomAvailabilityService;
        $this->newBookingMailService = $newBookingMailService;
        $this->channelManagerService = $channelManagerService;
        $this->channelManagerBookingService = $channelManagerBookingService;
    }

    public function getDateByDay($dates = [])
    {

        $dateByDay = [];

        $diffInDays = Carbon::parse($dates['checkIn'])->floatDiffInDays(Carbon::parse($dates['checkOut']));

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

        return $dateByDay;

    }

    public function createBooking($channelCode, $param)
    {

        $response = ['status' => false, 'message' => ''];

        DB::beginTransaction();

        try {


            $channelService = App::make("App\Core\Service\ChannelManager\\{$channelCode}");

            $bookingCode = getCodeGenerate('BKG');

            $param['booking']['booking_code'] = $bookingCode;
            $param['booking']['extra_param'] = json_encode($param['channel_manager']);
            $bookingCreate = $this->bookingService->create($param['booking']);
            //$bookingCreate['status'] = 'success';//TODO: Delete
            //$bookingCreate['data']['id'] = 1106;

            if ($bookingCreate['status'] != 'success') {
                throw new ApiErrorException('Booking could not be made, Reservation: ' . $param['booking']['search_key']);
            }

            $param['booking']['id'] = $bookingCreate['data']['id'];

            //INSERT CONTACT DATA
            $bookingContactCreateParam = [
                'booking_id' => $bookingCreate['data']['id'],
                'name' => $param['contact']['name'],
                'surname' => $param['contact']['surname'],
                'phone_code' => $param['contact']['phone_code'],
                'phone_number' => $param['contact']['phone_number'],
                'email' => $param['contact']['email'],
                'country_code' => fillOnUndefined($param['contact'], 'country_code'),
                'note' => !empty($param['contact']['note']) ? $param['contact']['note'] : null,
                'language_code' => fillOnUndefined($param['contact'], 'language', 'en'),
                'extra_param' => fillOnUndefined($param['contact'], 'extra_param'),
                'status' => 1
            ];

            $bookingContactCreate = $this->bookingContactService->create($bookingContactCreateParam);
            //$bookingContactCreate['status'] = 'success';

            if ($bookingContactCreate['status'] != 'success') {
                throw new ApiErrorException('Booking Contact could not be made');
            }

            //INSERT ROOM DATA
            foreach ($param['room'] as $roomOrder => $room) {

                $bookingRoomCreateParam = [
                    'booking_id' => $bookingCreate['data']['id'],
                    'room_order_number' => ($roomOrder + 1),
                    'occupancy_code' => $room['occupancy_code'],
                    'checkin_date' => $room['checkin_date'], //$room['checkin'],
                    'checkout_date' => $room['checkout_date'],//$room['checkout'],
                    'rate_key' => fillOnUndefined($room, 'rate_key'),
                    'rate_key_code' => fillOnUndefined($room, 'rate_key_code'),
                    'availability_id' => 1,
                    'availability_code' => 'ROM',
                    'room_id' => $room['room_id'],
                    'room_name' => $room['room_name'],
                    'room_rate_mapping_id' => $room['room_rate_mapping_id'],
                    'room_rate_name' => $room['room_rate_name'],
                    'cancellation_policy' => fillOnUndefined($room, 'cancellation_policy'),
                    'payment_type_code' => fillOnUndefined($room, 'payment_type_code', 'CHN'),
                    'daily_amount' => fillOnUndefined($room, 'daily_amount'),
                    'extra_param' => fillOnUndefined($room, 'extra_param'),
                    'rate_detail' => fillOnUndefined($room, 'rate_detail'),
                    'total' => $room['total'],
                    'currency_code' => $room['currency_code'],
                    'status' => fillOnUndefined($room, 'status', 1),
                ];

                $bookingRoomCreate = $this->bookingRoomService->create($bookingRoomCreateParam);
                //$bookingRoomCreate['status'] = 'success';

                if ($bookingRoomCreate['status'] != 'success') {
                    throw new ApiErrorException('Booking Room could not be made');
                }


                /* ROOM AVAILABILITY */
                $dateByDay = [];
                $dateByDay = $this->getDateByDay(['checkIn' => $room['checkin_date'], 'checkOut' => $room['checkout_date']]);
                foreach ($dateByDay as $day) {

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

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

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

                    foreach ($getPropertyRoomAndRoomRateAvailability['data'] as $roomAvailability) {
                        $roomAvailabilityUpdated = $roomAvailability['availability'] <= 0 ? 0 : ($roomAvailability['availability'] - 1);
                        $this->propertyRoomAvailabilityService->update($roomAvailability['id'], ['availability' => $roomAvailabilityUpdated]);
                    }

                }

                /* ROOM AVAILABILITY */

            }


            //INSERT PAYMENT DATA
            $bookingPaymentCreateParam = [
                'booking_id' => $bookingCreate['data']['id'],
                'payment_code' => fillOnUndefined($param['payment'], 'payment_code'),
                'payment_type_code' => fillOnUndefined($param['payment'], 'payment_type_code'),//Type: CHN
                'payment_source_code' => fillOnUndefined($param['payment'], 'payment_source_code'),
                'extra_param' => fillOnUndefined($param['payment'], 'extra_param'),
                'total' => fillOnUndefined($param['payment'], 'total'),
                'currency_code' => fillOnUndefined($param['payment'], 'currency_code'),
                'status' => fillOnUndefined($param['payment'], 'status'),//Type: 2
            ];

            $bookingPaymentCreate = $this->bookingPaymentService->create($bookingPaymentCreateParam);
            //$bookingPaymentCreate['status'] = 'success';

            if ($bookingPaymentCreate['status'] != 'success') {
                throw new ApiErrorException('Booking Payment could not be made');
            }
            //INSERT PAYMENT DATA


            //INSERT CHANNEL PAYMENT DATA
            if (isset($param['payment_channel']) && !empty($param['payment_channel'])) {

                $bookingPaymentDataCreateParam = [
                    'booking_id' => $bookingCreate['data']['id'],
                    'type' => fillOnUndefined($param['payment_channel'], 'type'),
                    'data' => fillOnUndefined($param['payment_channel'], 'data'),
                    'status' => fillOnUndefined($param['payment_channel'], 'status', 1),
                ];

                $bookingPaymentDataCreate = $this->bookingPaymentService->createPaymentData($bookingPaymentDataCreateParam);

                if ($bookingPaymentDataCreate['status'] != 'success') {
                    throw new ApiErrorException('Booking Channel Payment could not be made');
                }
            }
            //INSERT CHANNEL PAYMENT DATA

            $reservationConfirmParam = $channelService->reservationConfirmParam($param['channel_manager']['property_id'], $param['channel_manager']['booking_id'], $bookingCode, $param);
            $reservationConfirm = $channelService->reservationConfirm($reservationConfirmParam);

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


            //PUSH CHANNEL MANAGER QUEUE
            /*
            538	Euphoria Hotel Batumi
            541	Intourist Palace Hotel & SPA
            545	Metro Sky Tower Hotel
            546	Legend Hotel Batumi Convention Center & Spa
            548	Legend Business Hotel Batumi
            549	Euphoria Apartments
            550	City Hotel Batumi
             */
            /*if (in_array($bookingCreate['data']['property_id'], [546])) {

                $channelManagerBookingParam = [
                    'property_id' => $bookingCreate['data']['property_id'],
                    'booking_id' => $bookingCreate['data']['id'],
                    'channel_manager_id' => $bookingCreate['data']['channel_manager_id'],
                    'type' => 'Booking',
                ];

                $this->channelManagerBookingService->create($channelManagerBookingParam);

            }*/

            $channelManagerPropertyMappingCriteria = [
                'criteria' =>
                    [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $bookingCreate['data']['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) {

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

                    $channelManagerBookingCreateParam = [
                        'property_id' => $bookingCreate['data']['property_id'],
                        'booking_id' => $bookingCreate['data']['id'],
                        'channel_manager_id' => $channelPropertyData['channel_manager_id'],
                        'type' => 'Booking',
                    ];

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

                }

            }
            //PUSH CHANNEL MANAGER QUEUE

            DB::commit();

            $mailParams = ['booking_id' => $bookingCreate['data']['id']];
            $this->newBookingMailService->process($mailParams);

            $response['status'] = true;
            $response['data'] = $param;

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

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

        return $response;

    }

    public function modifiedBooking($channelCode, $param)
    {

        $response = ['status' => false, 'message' => ''];

        DB::beginTransaction();

        try {

            $channelService = App::make("App\Core\Service\ChannelManager\\{$channelCode}");

            $bookingCode = null;

            $bookingDetailParam = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $param['booking']['property_id']],
                    ['field' => 'search_key', 'condition' => '=', 'value' => $param['booking']['search_key']],
                    //['field' => 'channel_manager_id', 'condition' => '=', 'value' => $param['booking']['channel_manager_id']],
                ],
                'with' => ['bookingRoom', 'bookingContact', 'bookingChannel', 'bookingPayment'],
                'firstRow' => true
            ];

            $bookingDetail = $this->bookingService->select($bookingDetailParam);

            if ($bookingDetail['status'] != 'success') {
                throw new ApiErrorException(lang('Booking could not be found, Reservation: ' . $param['booking']['search_key']));
            }

            if (!empty($bookingDetail['data'])) {

                $bookingCode = $bookingDetail['data']['booking_code'];

                $param['booking']['id'] = $bookingDetail['data']['id'];
                $param['booking']['booking_code'] = $bookingDetail['data']['booking_code'];

                $bookingUpdateParam = [
                    'channel_booking_code' => fillOnUndefined($param['booking'], 'channel_booking_code'),
                    'search_key' => $param['booking']['search_key'],
                    'checkin_date' => $param['booking']['checkin_date'],
                    'checkout_date' => $param['booking']['checkout_date'],
                    'payment_type_code' => $param['booking']['payment_type_code'],
                    'total' => $param['booking']['total'],
                    'currency_code' => $param['booking']['currency_code'],
                ];

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

                $bookingContactUpdateParam = [
                    'name' => $param['contact']['name'],
                    'surname' => $param['contact']['surname'],
                    'phone_code' => $param['contact']['phone_code'],
                    'phone_number' => $param['contact']['phone_number'],
                    'email' => $param['contact']['email'],
                    'country_code' => !empty($param['contact']['country_code']) ? $param['contact']['country_code'] : null,
                    'note' => !empty($param['contact']['note']) ? $param['contact']['note'] : null,
                    'language_code' => fillOnUndefined($param['contact'], 'language_code', 'en')
                ];

                $bookingContactUpdate = $this->bookingContactService->update($bookingDetail['data']['booking_contact']['id'], $bookingContactUpdateParam);

                foreach ($bookingDetail['data']['booking_room'] as $roomOrder => $room) {

                    foreach ($param['room'] as $roomOrderChannel => $roomChannel) {

                        if ($roomOrder == $roomOrderChannel) {

                            $bookingRoomUpdateParam = [
                                'occupancy_code' => $roomChannel['occupancy_code'],
                                'checkin_date' => $roomChannel['checkin_date'],
                                'checkout_date' => $roomChannel['checkout_date'],
                                'room_id' => $roomChannel['room_id'],
                                'room_name' => $roomChannel['room_name'],
                                'room_rate_mapping_id' => $roomChannel['room_rate_mapping_id'],
                                'room_rate_name' => $roomChannel['room_rate_name'],
                                'rate_detail' => json_encode($roomChannel),
                                'total' => $roomChannel['total'],
                                'currency_code' => $roomChannel['currency_code'],
                                'daily_amount' => fillOnUndefined($roomChannel, 'daily_amount'),
                            ];

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

                            /* ROOM AVAILABILITY */
                            //Eğer odaya ait tarihler farklı ise buraya gelecek.
                            if (($room['checkin_date'] != $roomChannel['checkin_date']) || ($room['checkout_date'] != $roomChannel['checkout_date'])) {

                                $dateByDay = [];
                                $dateByDay['update'] = [];
                                $dateByDay['current'] = $this->getDateByDay(['checkIn' => $room['checkin_date'], 'checkOut' => $room['checkout_date']]);
                                $dateByDay['modified'] = $this->getDateByDay(['checkIn' => $roomChannel['checkin_date'], 'checkOut' => $roomChannel['checkout_date']]);

                                foreach ($dateByDay['current'] as $date) {
                                    $dateByDay['update'][$date] = !isset($dateByDay['update'][$date]) ? 0 : $dateByDay['update'][$date];
                                    $dateByDay['update'][$date]++;
                                }

                                foreach ($dateByDay['modified'] as $date) {
                                    $dateByDay['update'][$date] = !isset($dateByDay['update'][$date]) ? 0 : $dateByDay['update'][$date];
                                    $dateByDay['update'][$date]--;
                                }

                                ksort($dateByDay['update']);
                                foreach ($dateByDay['update'] as $day => $availabilityModified) {

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

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

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

                                    foreach ($getPropertyRoomAndRoomRateAvailability['data'] as $roomAvailability) {

                                        $roomAvailabilityUpdated = 0;
                                        $roomAvailabilityUpdated = $roomAvailability['availability'] + $availabilityModified;
                                        if($roomAvailabilityUpdated < 0) {
                                            $roomAvailabilityUpdated = 0;
                                        }

                                        $this->propertyRoomAvailabilityService->update($roomAvailability['id'], ['availability' => $roomAvailabilityUpdated]);
                                    }

                                }
                            }
                            /* ROOM AVAILABILITY */

                        }
                    }

                }

                //Added New Room Case
                if (count($bookingDetail['data']['booking_room']) != count($param['room']) && count($param['room']) > count($bookingDetail['data']['booking_room']) ) {

                    foreach ($param['room'] as $roomOrderChannel => $roomChannel) {

                        foreach ($bookingDetail['data']['booking_room'] as $roomOrder => $room) {

                            if ($roomOrder != $roomOrderChannel) {

                                $bookingRoomCreateParam = [
                                    'booking_id' => $bookingDetail['data']['id'],
                                    'room_order_number' => ($roomOrderChannel + 1),
                                    'occupancy_code' => $roomChannel['occupancy_code'],
                                    'checkin_date' => $roomChannel['checkin_date'], //$room['checkin'],
                                    'checkout_date' => $roomChannel['checkout_date'],//$room['checkout'],
                                    'rate_key' => fillOnUndefined($roomChannel, 'rate_key'),
                                    'rate_key_code' => fillOnUndefined($roomChannel, 'rate_key_code'),
                                    'availability_id' => 1,
                                    'availability_code' => 'ROM',
                                    'room_id' => $roomChannel['room_id'],
                                    'room_name' => $roomChannel['room_name'],
                                    'room_rate_mapping_id' => $roomChannel['room_rate_mapping_id'],
                                    'room_rate_name' => $roomChannel['room_rate_name'],
                                    'cancellation_policy' => fillOnUndefined($roomChannel, 'cancellation_policy'),
                                    'payment_type_code' => fillOnUndefined($roomChannel, 'payment_type_code', 'CHN'),
                                    'daily_amount' => fillOnUndefined($roomChannel, 'daily_amount'),
                                    'extra_param' => fillOnUndefined($roomChannel, 'extra_param'),
                                    'rate_detail' => fillOnUndefined($roomChannel, 'rate_detail'),
                                    'total' => $roomChannel['total'],
                                    'currency_code' => $roomChannel['currency_code'],
                                    'status' => fillOnUndefined($roomChannel, 'status', 1),
                                ];

                                $bookingRoomCreate = $this->bookingRoomService->create($bookingRoomCreateParam);

                            }
                        }

                    }
                }

                //UPDATE PAYMENT DATA
                $bookingPaymentUpdateParam = [
                    'payment_type_code' => fillOnUndefined($param['payment'], 'payment_type_code'),
                    'payment_source_code' => fillOnUndefined($param['payment'], 'payment_source_code'),
                    'extra_param' => fillOnUndefined($param['payment'], 'extra_param'),
                    'total' => fillOnUndefined($param['payment'], 'total'),
                    'currency_code' => fillOnUndefined($param['payment'], 'currency_code')
                ];

                $bookingPaymentUpdate = $this->bookingPaymentService->update($bookingDetail['data']['booking_payment']['id'], $bookingPaymentUpdateParam);
                //UPDATE PAYMENT DATA


                //INSERT CHANNEL PAYMENT DATA
                if (isset($param['payment_channel']) && !empty($param['payment_channel'])) {

                    $bookingPaymentDataCreateParam = [
                        'booking_id' => $bookingDetail['data']['id'],
                        'type' => fillOnUndefined($param['payment_channel'], 'type'),
                        'data' => fillOnUndefined($param['payment_channel'], 'data'),
                        'status' => fillOnUndefined($param['payment_channel'], 'status', 1),
                    ];

                    $bookingPaymentDataCreate = $this->bookingPaymentService->createPaymentData($bookingPaymentDataCreateParam);

                    if ($bookingPaymentDataCreate['status'] != 'success') {
                        throw new ApiErrorException('Booking Channel Payment could not be made');
                    }
                }
                //INSERT CHANNEL PAYMENT DATA


            } else {
                return $this->createBooking($channelCode, $param);
            }

            $bookingCode = is_null($bookingCode) ? 'ENW' . $param['booking']['search_key'] : $bookingCode;

            $reservationConfirmParam = $channelService->reservationConfirmParam($param['channel_manager']['property_id'], $param['channel_manager']['booking_id'], $bookingCode, $param);
            $reservationConfirm = $channelService->reservationConfirm($reservationConfirmParam);

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


            $notificationModifiedToPropertyUser = [
                'booking_id' => $param['booking']['id'],
            ];

            $this->mailer->onQueue('modifiedBookingMail', new ModifiedBookingMail($notificationModifiedToPropertyUser));

            $response['status'] = true;
            $response['data'] = $param;

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

        if ($response['status']) {

            //PUSH CHANNEL MANAGER QUEUE
            $channelManagerPropertyMappingCriteria = [
                'criteria' =>
                    [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $bookingDetail['data']['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) {

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

                    $channelManagerBookingCreateParam = [
                        'property_id' => $bookingDetail['data']['property_id'],
                        'booking_id' => $bookingDetail['data']['id'],
                        'channel_manager_id' => $channelPropertyData['channel_manager_id'],
                        'type' => 'Modify',
                    ];

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

                }

            }
            //PUSH CHANNEL MANAGER QUEUE

            DB::commit();

        } else {
            DB::rollBack();
        }

        return $response;

    }

    public function cancelBooking($channelCode, $param)
    {

        $response = ['status' => false, 'message' => ''];

        DB::beginTransaction();

        try {

            $channelService = App::make("App\Core\Service\ChannelManager\\{$channelCode}");

            $bookingCode = null;

            $bookingDetailParam = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $param['booking']['property_id']],
                    ['field' => 'search_key', 'condition' => '=', 'value' => $param['booking']['search_key']],
                    //['field' => 'channel_manager_id', 'condition' => '=', 'value' => $param['booking']['channel_manager_id']],
                ],
                'with' => ['bookingRoom', 'bookingContact', 'bookingChannel'],
                'firstRow' => true
            ];

            $bookingDetail = $this->bookingService->select($bookingDetailParam);

            if ($bookingDetail['status'] != 'success') {
                throw new ApiErrorException(lang('Booking could not be found, Reservation: ' . $param['booking']['search_key']));
            }

            if (!empty($bookingDetail['data'])) {

                $bookingCode = $bookingDetail['data']['booking_code'];

                $param['booking']['id'] = $bookingDetail['data']['id'];
                $param['booking']['booking_code'] = $bookingDetail['data']['booking_code'];

                $this->bookingService->update($bookingDetail['data']['id'], ['status' => 0]);

                foreach ($bookingDetail['data']['booking_room'] as $roomOrder => $room) {

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

                    /* ROOM AVAILABILITY */
                    $dateByDay = [];
                    $dateByDay = $this->getDateByDay(['checkIn' => $room['checkin_date'], 'checkOut' => $room['checkout_date']]);
                    foreach ($dateByDay as $day) {

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

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

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

                        foreach ($getPropertyRoomAndRoomRateAvailability['data'] as $roomAvailability) {
                            $roomAvailabilityUpdated = $roomAvailability['availability'] <= 0 ? 1 : ($roomAvailability['availability'] + 1);
                            $this->propertyRoomAvailabilityService->update($roomAvailability['id'], ['availability' => $roomAvailabilityUpdated]);
                        }

                    }

                    /* ROOM AVAILABILITY */

                }

            }

            $bookingCode = is_null($bookingCode) ? 'ENW' . $param['booking']['search_key'] : $bookingCode;

            $reservationConfirmParam = $channelService->reservationConfirmParam($param['channel_manager']['property_id'], $param['channel_manager']['booking_id'], $bookingCode, $param);
            $reservationConfirm = $channelService->reservationConfirm($reservationConfirmParam);

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

            $notificationCancelToPropertyUser = [
                'booking_id' => $param['booking']['id'],
            ];

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

            $response['status'] = true;
            $response['data'] = $param;

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

        if ($response['status']) {

            //PUSH CHANNEL MANAGER QUEUE
            $channelManagerPropertyMappingCriteria = [
                'criteria' =>
                    [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $bookingDetail['data']['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) {

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

                    $channelManagerBookingCreateParam = [
                        'property_id' => $bookingDetail['data']['property_id'],
                        'booking_id' => $bookingDetail['data']['id'],
                        'channel_manager_id' => $channelPropertyData['channel_manager_id'],
                        'type' => 'Cancel',
                    ];

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

                }

            }
            //PUSH CHANNEL MANAGER QUEUE

            DB::commit();

        } else {
            DB::rollBack();
        }

        return $response;

    }

    public function handle()
    {

        try {


            $this->info(date('Y-m-d H:i:s') . ' : Start');

            $channelManagerCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ],
                    'orderBy' => [
                        ['field' => 'id', 'value' => 'ASC']
                    ]
                ];

            $channelManager = $this->channelManagerService->select($channelManagerCriteria);

            $channelManagerList = [];
            if ($channelManager['status'] == 'success' && !empty($channelManager['data'])) {
                $channelManagerList = $channelManager['data'];
            }


            //CHANNEL MANAGER
            foreach ($channelManagerList as $channelKey => $channel) {

                $this->info(date('Y-m-d H:i:s') . ' : Channel Start: ' . $channel['name']);

                if (!class_exists("App\Core\Service\ChannelManager\\{$channel['name']}")) {
                    $this->error(date('Y-m-d H:i:s') . ' : Channel: ' . $channel['name'] . ' Class does not exist!');
                    continue;
                }

                $channelService = App::make("App\Core\Service\ChannelManager\\{$channel['name']}");

                $channelManagerPropertyMappingCriteria = [
                    'criteria' =>
                        [
                            ['field' => 'status', 'condition' => '=', 'value' => 1],
                            ['field' => 'channel_manager_id', 'condition' => '=', 'value' => $channel['id']],
                            ['field' => 'channel_manager_property_id', 'condition' => '!=', 'value' => null],
                        ],
                    'with' => ['channelManagerRoomRate.propertyRoomRateMapping', 'property'],
                    'orderBy' => [
                        ['field' => 'property_id', 'value' => 'ASC']
                    ]
                ];

                //TODO: Channex limited hotels
                if ($channel['id'] == 2) {
                    $channexPullReservationPropertyIds = [71,313, /*538, 541, 545, 546, 548, 549, 550,*/ 672, 712, 785, 808, 790, 755, 901, 952, 912, 848, 1098, 1103, 1035];
                    $channelManagerPropertyMappingCriteria['whereIn'][] = ["field" => "property_id", "value" => $channexPullReservationPropertyIds];
                }

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

                //Eğer kanala ait bir otel yok ise devam et
                if ($channelManagerPropertyMapping['status'] != 'success' || empty($channelManagerPropertyMapping['data'])) {
                    continue;
                }

                if ($channelManagerPropertyMapping['status'] == 'success') {

                    //CHANNEL MANAGER PROPERTY
                    foreach ($channelManagerPropertyMapping['data'] as $propertyMapping) {

                        //Property
                        if (!in_array($propertyMapping['property']['id'],[623])) {
                            //continue;
                        }

                        $this->info(date('Y-m-d H:i:s') . ' : Property: ' . $propertyMapping['property']['id'] . ' - ' . $propertyMapping['property']['name']);

                        $reservationListParam = $channelService->reservationListParam($propertyMapping['channel_manager_property_id']);
                        $reservationList = $channelService->reservationList($reservationListParam);

                        //Eğer kanaldaki otele ait bir rezervasyon yok ise devam et
                        if (!$reservationList['status']) {
                            continue;
                        }

                        //CHANNEL MANAGER PROPERTY Reservation
                        foreach ($reservationList['data'] as $reservationKey => $reservation) {


                            $reservationPullFormatted = $channelService->reservationPullFormattedData($propertyMapping['property_id'], $propertyMapping['channel_manager_property_id'], $reservation);

                            if (!$reservationPullFormatted['status']) {
                                //Burada bi hata var demektir, mail atılsın ama sonraki işleme devam edilsin.

                                //$logMessage
                                $mailParams = [
                                    'title' => $channel['name'] . ' - ReservationPullService Error - reservationPullFormatted',
                                    'logMessage' => '<pre>' . print_r($reservationPullFormatted, true) . '</pre>'
                                ];

                                $this->mailer->onQueue('logMail', new LogMail($mailParams));
                                //$logMessage

                                $this->error(date('Y-m-d H:i:s') . ' : Property: ' . $propertyMapping['property']['id'] . ' - ' . $propertyMapping['property']['name'].' Error: reservationPullFormattedData');

                                continue;
                            }

                            //TODO: Eğer burada gelen kanal extranetwork ise alınmış gibi yapılıp diğer işleme geçilmeli
                            if (in_array($reservationPullFormatted['data']['channel_manager']['sub_channel'], ['ExtranetWork'])) {

                                $reservationConfirmParam = $channelService->reservationConfirmParam($reservationPullFormatted['data']['channel_manager']['property_id'], $reservationPullFormatted['data']['channel_manager']['booking_id'], 'ENW' . $reservationPullFormatted['data']['channel_manager']['booking_id'], $reservationPullFormatted['data']);
                                $reservationConfirm = $channelService->reservationConfirm($reservationConfirmParam);

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

                                continue;
                            }


                            $reservationPull = ['status' => false, 'message' => ''];


                            if ($reservationPullFormatted['type'] == 'createBooking') {
                                $reservationPull = $this->createBooking($channel['name'], $reservationPullFormatted['data']);
                            } elseif ($reservationPullFormatted['type'] == 'modifiedBooking') {

                                //If the modified reservation is not found, first create a reservation.
                                $bookingDetailParam = [
                                    'criteria' => [
                                        ['field' => 'property_id', 'condition' => '=', 'value' => $reservationPullFormatted['data']['booking']['property_id']],
                                        ['field' => 'search_key', 'condition' => '=', 'value' => $reservationPullFormatted['data']['booking']['search_key']],
                                    ],
                                    'firstRow' => true
                                ];

                                $bookingDetail = $this->bookingService->select($bookingDetailParam);

                                if (empty($bookingDetail['data'])) {
                                    $reservationPull = $this->createBooking($channel['name'], $reservationPullFormatted['data']);
                                } else {
                                    $reservationPull = $this->modifiedBooking($channel['name'], $reservationPullFormatted['data']);
                                }


                            } elseif ($reservationPullFormatted['type'] == 'cancelBooking') {
                                $reservationPull = $this->cancelBooking($channel['name'], $reservationPullFormatted['data']);
                            }

                            if ($reservationPull['status']) {
                                $this->info(date('Y-m-d H:i:s') . ' : Success ' . $reservationPullFormatted['type'] . ': ' . $reservationPull['data']['booking']['booking_code']);
                            } else {

                                //$logMessage
                                $mailParams = [
                                    'title' => $channel['name'] . ' - ReservationPullService Error - Booking',
                                    'logMessage' => '<pre>' . print_r(array_merge($reservationPullFormatted, $reservationPull), true) . '</pre>'
                                ];

                                $this->mailer->onQueue('logMail', new LogMail($mailParams));
                                //$logMessage

                                $this->error(date('Y-m-d H:i:s') . ' : Error: ' . $reservationPull['message']);
                            }


                        }

                    }


                }

                $this->info(PHP_EOL);
            }


            //dd($channelManagerList);

            $this->info(date('Y-m-d H:i:s') . ' : Finished');

        } catch (ApiErrorException $e) {
            $this->error(date('Y-m-d H:i:s') . ' : Error: ' . $e->getMessage());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $this->error(date('Y-m-d H:i:s') . ' : Error: ' . $message);
        }

    }

}
