<?php


namespace App\Core\Service;

use App\Core\Repository\PropertyChannelMapping\PropertyChannelMappingRepository;
use App\Core\Validator\PropertyChannelMapping\PropertyChannelMappingAddValidator;
use App\Core\Validator\PropertyChannelMapping\PropertyChannelMappingRemoveValidator;
use App\Core\Validator\PropertyChannelMapping\PropertyChannelMappingUpdateValidator ;
use App\Core\Validator\PropertyChannelMapping\PropertyChannelSetupValidator;
use App\Core\Repository\PropertyBookingType\PropertyBookingTypeRepository ;
use App\Core\Repository\PropertyBookingPaymentType\PropertyBookingPaymentTypeRepository ;
use App\Core\Repository\PropertyAvailabilityType\PropertyAvailabilityTypeRepository;
use App\Core\Repository\PropertyRoomPricingType\PropertyRoomPricingTypeRepository;
use App\Core\Repository\PropertyRoom\PropertyRoomRepository;
use App\Core\Repository\PropertyRoomRateChannelMapping\PropertyRoomRateChannelMappingRepository;
use App\Core\Validator\PropertyChannelSetup\PropertyChannelSetupAddValidator;
use App\Core\Validator\PropertyChannelSetup\PropertyChannelSetupUpdateValidator;
use App\Core\Validator\PropertyChannelSetup\PropertyChannelSetupWithMissingParametersAddValidator;
use App\Core\Service\PropertyRoomAvailabilityService;
use App\Core\Repository\PropertyRoomRatePrice\PropertyRoomRatePriceRepository;
use App\Core\Repository\PropertyChannel\PropertyChannelTaxRepository;

use Carbon\Carbon;
use Illuminate\Http\Request;
use App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Config;
use Exception;
use App\Exceptions\ApiErrorException;


class PropertyChannelMappingService
{
    private $propertyChannelMappingRepository;
    private $propertyChannelMappingAddValidator;
    private $propertyChannelMappingRemoveValidator;
    private $propertyChannelMappingUpdateValidator;
    private $propertyChannelSetupValidator;
    private $propertyBookingTypeRepository;
    private $propertyBookingPaymentTypeRepository;
    private $propertyAvailabilityTypeRepository;
    private $propertyRoomPricingTypeRepository;
    private $propertyRoomRepository;
    private $propertyRoomRateChannelMappingRepository;
    private $propertyChannelSetupAddValidator;
    private $propertyChannelSetupUpdateValidator;
    private $propertyRoomAvailabilityService;
    private $propertyBookingEngineService;
    private $propertyChannelSetupWithMissingParametersAddValidator;

    const STATUS_PENDING = 2;

    public function __construct
    (
        Request $request,
        PropertyChannelSetupValidator $propertyChannelSetupValidator ,
        PropertyChannelMappingAddValidator $propertyChannelMappingAddValidator,
        PropertyChannelMappingRemoveValidator $propertyChannelMappingRemoveValidator,
        PropertyChannelMappingRepository $propertyChannelMappingRepository,
        PropertyChannelMappingUpdateValidator $propertyChannelMappingUpdateValidator,
        PropertyBookingTypeRepository $propertyBookingTypeRepository,
        PropertyAvailabilityTypeRepository $propertyAvailabilityTypeRepository,
        PropertyBookingPaymentTypeRepository $propertyBookingPaymentTypeRepository,
        PropertyRoomRepository $propertyRoomRepository,
        PropertyRoomRateChannelMappingRepository $propertyRoomRateChannelMappingRepository,
        PropertyRoomPricingTypeRepository $propertyRoomPricingTypeRepository,
        PropertyChannelSetupAddValidator $propertyChannelSetupAddValidator,
        PropertyRoomAvailabilityService $propertyRoomAvailabilityService,
        PropertyChannelSetupUpdateValidator $propertyChannelSetupUpdateValidator,
        PropertyBookingEngineService $propertyBookingEngineService,
        PropertyChannelSetupWithMissingParametersAddValidator $propertyChannelSetupWithMissingParametersAddValidator,
        PropertyRoomService $propertyRoomService,
        PropertyRoomRatePriceService $propertyRoomRatePriceService,
        PropertyRoomRatePriceRepository $propertyRoomRatePriceRepository,
        PropertyChannelTaxRepository $propertyChannelTaxRepository
    )
    {
        $this->request = $request;
        $this->propertyChannelMappingRepository = $propertyChannelMappingRepository;
        $this->propertyChannelMappingAddValidator = $propertyChannelMappingAddValidator;
        $this->propertyChannelMappingRemoveValidator = $propertyChannelMappingRemoveValidator;
        $this->propertyChannelMappingUpdateValidator = $propertyChannelMappingUpdateValidator;
        $this->propertyChannelSetupValidator = $propertyChannelSetupValidator ;
        $this->propertyBookingTypeRepository = $propertyBookingTypeRepository;
        $this->propertyBookingPaymentTypeRepository = $propertyBookingPaymentTypeRepository;
        $this->propertyAvailabilityTypeRepository = $propertyAvailabilityTypeRepository ;
        $this->propertyRoomPricingTypeRepository = $propertyRoomPricingTypeRepository ;
        $this->propertyRoomRepository = $propertyRoomRepository ;
        $this->propertyRoomRateChannelMappingRepository = $propertyRoomRateChannelMappingRepository ;
        $this->propertyChannelSetupAddValidator = $propertyChannelSetupAddValidator ;
        $this->propertyChannelSetupUpdateValidator = $propertyChannelSetupUpdateValidator ;
        $this->propertyRoomAvailabilityService = $propertyRoomAvailabilityService ;
        $this->propertyBookingEngineService = $propertyBookingEngineService;
        $this->propertyChannelSetupWithMissingParametersAddValidator = $propertyChannelSetupWithMissingParametersAddValidator;
        $this->propertyRoomService = $propertyRoomService;
        $this->propertyRoomRatePriceService = $propertyRoomRatePriceService;
        $this->propertyRoomRatePriceRepository = $propertyRoomRatePriceRepository;
        $this->propertyChannelTaxRepository = $propertyChannelTaxRepository;

    }


    public function select($param = [], $column = ['*'])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {
            $data = $this->propertyChannelMappingRepository->findByCriteria($param, $column);
            $response['status'] = 1;
            $response['data'] = $data;

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

        return output($response);
    }

    public function create($param = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            $propertyChannelMappingData =
                [
                    "channel_id" => fillOnUndefined($param, "user_id"),
                    "property_id" => fillOnUndefined($param, "property_id"),
                    "status" => fillOnUndefined($param, "status", 0),
                    "created_by" => fillOnUndefined($param, "created_by"),
                    "updated_by" => fillOnUndefined($param, "created_by"),

                ];


            $propertyCreateResult = $this->propertyChannelMappingRepository->create($propertyChannelMappingData);

            if ($propertyCreateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }

            $response['status'] = 1;
            $response['data'] = $propertyCreateResult["data"];

        } 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();
        }

        return output($response);
    }

    public function update($id, $param = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {


            $updateResult = $this->propertyChannelMappingRepository->update($id, $param);
            if ($updateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }
            $updateData = $updateResult["data"];
            $response = [
                'status' => true,
                'data' => $updateData,
            ];

        } 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();
        }

        return output($response);
    }

    public function addPropertyChannelMapping($params)
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            $validationResult = $this->propertyChannelMappingAddValidator->validate($params);

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

            $criteria =
                [
                    "criteria" =>
                        [
                            ["field" => "property_id", "condition" => "=", "value" => $params['property_id']]
                        ]
                ];
            $oldMappingList = $this->propertyChannelMappingRepository->findByCriteria($criteria, ['id', 'property_id', 'channel_id', 'status']);


            foreach ($params['channels'] as $addChannel) {

                $checkData = collect($oldMappingList)
                    ->where('property_id' , '=', $params['property_id'])
                    ->where('channel_id', '=', $addChannel)
                    ->first();

                if(!$checkData){
                    $addPropertyChannelMappingData = [
                        "property_id" => $params['property_id'],
                        "channel_id" => $addChannel,
                        "status" => 1,
                        "created_by" => $params['user_id'],
                        "updated_by" => $params['user_id'],
                    ];
                    $createStatus =   $this->propertyChannelMappingRepository->create($addPropertyChannelMappingData);
                    if($createStatus['status'] != 'success'){
                        throw new Exception('api-unknown_error');
                    }
                }else{

                    $updatePropertyChannelMappingData = [
                        "status" => 1,
                        "updated_by" => $params['user_id']
                    ];
                    $updateResult = $this->propertyChannelMappingRepository->update($checkData['id'], $updatePropertyChannelMappingData) ;
                    if($updateResult['status'] != 'success'){
                        throw new Exception('api-unknown_error');
                    }

                }
            }

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

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

        return output($response);
    }

    public function getPropertyChannelMapping($params)
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

                $getPropertyCriteria = [
                  'criteria' => [
                      ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                      ['field' => 'status', 'condition' => '=', 'value' => 1],
                  ],
                    'with' => ['channel.propertyChannelCategory', 'property']

                ];

                $getChannels = $this->propertyChannelMappingRepository->findByCriteria($getPropertyCriteria, ['id', 'property_id', 'channel_id']) ;

            $response = ['status' => 1 , 'message' => '', 'data' => ['property_channel_mapping' => $getChannels]];

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

        return output($response);
    }

    public function removePropertyChannelMapping($params)
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

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

            foreach ($params['channels'] as $removeChannel) {


                $updatePropertyCriteria = [
                    'criteria' => [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id'] ],
                        ['field' => 'channel_id', 'condition' => '=', 'value' => $removeChannel],
                    ]

                ];

                $updatePropertyChannelMappingData = [
                    "status" => 0,
                    "updated_by" => $params['user_id'],
                    "updated_at" => time()
                ];

                $updateResult = $this->propertyChannelMappingRepository->updateWhere($updatePropertyCriteria, $updatePropertyChannelMappingData) ;
                if($updateResult['status'] != 'success'){
                    throw new Exception('api-unknown_error');
                }
            }

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

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

        return output($response);
    }

    public function updatePropertyChannelMapping($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try
        {
            $validationResult = $this->propertyChannelMappingUpdateValidator->validate($params);

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

            $addPropertyChannelMapping = [];
            $addChannelList = collect($params['property_channel'])
                ->where('is_selected' ,'=', true);
            $addChannelIds = $addChannelList->keyBy("id")->keys()->toArray();

            $removeChannelList = collect($params['property_channel'])
                ->where('is_selected' ,'=', false);

            $removeChannelIds = $removeChannelList->keyBy("id")->keys()->toArray();

            $checkPropertyMappingRequest = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                ],
                "whereIn" => [
                    ["field" => "channel_id", "value" => $addChannelIds]
                ]
            ];
            $checkPropertyMappingResponse = $this->propertyChannelMappingRepository->findByCriteria($checkPropertyMappingRequest,['id', 'property_id', 'channel_id']);

            $checkPropertyMappingResponse = $checkPropertyMappingResponse ? $checkPropertyMappingResponse : [] ;


            $checkPropertyMappingCollect = collect($checkPropertyMappingResponse);

            foreach ($addChannelList->toArray() as $key => $param)
            {
                $checkPropertyMapping = $checkPropertyMappingCollect->where('property_id', '=', $params['property_id'])
                    ->where('channel_id', '=', $param['id'])
                    ->first() ;
                if(!$checkPropertyMapping){
                    $addPropertyChannelMapping[] =
                        [
                            'property_id' => $params['property_id'],
                            'channel_id' => fillOnUndefined($param, 'id'),
                            'created_by' => $params['user_id'],
                            'updated_by' => $params['user_id'],
                        ];
                }else{
                    $updatePropertyChannelMapping =
                        [
                            'status' => 1,
                            'updated_by' => $params['user_id'],
                        ];

                    $response = $this->propertyChannelMappingRepository->update($checkPropertyMapping['id'], $updatePropertyChannelMapping);
                    if ($response['status'] != 'success') {
                        throw new Exception('api-unknown_error');
                    }
                }
            }
            $response = $this->propertyChannelMappingRepository->insert($addPropertyChannelMapping);
            if ($response['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }

            if($removeChannelIds){

                $findCriteria = [
                    'criteria' => [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ],
                    "whereIn" =>
                        [
                            ["field" => "channel_id", "value" => $removeChannelIds]
                        ]
                ];
                $deletePropertyChannelMapping = $this->propertyChannelMappingRepository->findByCriteria($findCriteria);
                $deleteThisIds = [];
                foreach ($deletePropertyChannelMapping as $deleteThisItem){

                    $updatePropertyChannelMapping =
                        [
                            'status' => 0,
                            'updated_by' => $params['user_id'],
                        ];
                    $response = $this->propertyChannelMappingRepository->update($deleteThisItem['id'], $updatePropertyChannelMapping);
                    if ($response['status'] != 'success') {
                        throw new Exception('api-unknown_error');
                    }
                }
            }

            if ($response['status'] != 'success') {
                throw new ApiErrorException(lang('Data is not added')) ;
            }

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

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

        return output($response);
    }

    public function addPropertyChannelSetup($params)
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            DB::beginTransaction();

            $criteria =
                [
                    "criteria" =>
                        [
                            ["field" => "property_id", "condition" => "=", "value" => $params['property_id']],
                            ["field" => "channel_id", "condition" => "=", "value" => $params['channel_id']],
                        ],
                    'firstRow' => true
                ];
            $oldMappingList = $this->propertyChannelMappingRepository->findByCriteria($criteria);

            $roomCriteria = [
                "criteria" =>
                    [
                        ["field" => "property_id", "condition" => "=", "value" => $params['property_id']]
                    ],
                'with' => ['propertyRoomRateMapping.propertyRoomRate']
            ];

            $rooms = $this->propertyRoomRepository->findByCriteria($roomCriteria) ;
            $rooms = $rooms ? $rooms : [] ;

            $roomRateMappingIds = [] ;
            foreach ($rooms as $room) {
                foreach ($room['property_room_rate_mapping'] as $item) {
                    if(!in_array($params['channel_id'],[5]) && $item['property_room_rate']['name'] == 'Best Available Rate') {
                        continue;
                    }
                    $roomRateMappingIds[] = $item['id'] ;
                }
            }

            if(!$oldMappingList){

                $addPropertyChannelMappingData = [
                    "property_id" => $params['property_id'],
                    "channel_id" => $params['channel_id'],
                    "currency_code" => $params['currency_code'],
                    "property_booking_type_id" => $params['booking_type_id'],
                    "property_availability_type_id" => $params['availability_type_id'],
                    "property_room_pricing_type_id" => $params['room_pricing_type_id'],
                    "connected_channel_id" => fillOnUndefined($params,'connected_channel_id'),
                    "connected_channel_action" => fillOnUndefined($params,'connected_channel_action'),
                    "contract_file" => null,
                    'token' => getGuid(),
                    "status" => 1,
                    "created_by" => $params['user_id'],
                    "updated_by" => $params['user_id'],
                ];


                if($params['contract_file'] != null) {

                    $contractFileUploadParams = [
                        'property_id' => $params['property_id'],
                        'contract_file' => $params['contract_file'],
                        'channel_id' => $params['channel_id'],
                    ];

                    $contractFileUpload = $this->propertyBookingEngineService->contractFileUpload($contractFileUploadParams);
                    if ($contractFileUpload['status'] != 'success') {
                        throw new Exception('api-unknown_error');
                    }

                    $addPropertyChannelMappingData["contract_file"] = $contractFileUpload["data"]["contract_file_path"];

                }



                $validationResult = $this->propertyChannelSetupAddValidator->validate($params);

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

                $createStatus =   $this->propertyChannelMappingRepository->create($addPropertyChannelMappingData);

                if($createStatus['status'] != 'success'){
                    throw new Exception('api-unknown_error');
                }

                $roomRateChannelMappingData = [] ;

                foreach ($roomRateMappingIds as $roomRateMappingId) {
                    $roomRateChannelMappingData[] = [
                        "property_id" => $params['property_id'],
                        "channel_id" => $params['channel_id'],
                        "room_rate_mapping_id" => $roomRateMappingId,
                        "has_date" => 0,
                        "status" => 1,
                        "created_by" => $params['user_id'],
                        "updated_by" => $params['user_id'],
                        "created_at" => time(),
                        "updated_at" => time(),
                    ];
                }

                if($roomRateChannelMappingData){
                    $insertRoomRateChannelMappingResult = $this->propertyRoomRateChannelMappingRepository->insert($roomRateChannelMappingData);
                    if ($insertRoomRateChannelMappingResult['status'] != 'success') {
                        throw new Exception('api-unknown_error');
                    }
                }

                $channelTokenParam = [
                    "property_id" => $params['property_id'],
                    "channel_id" => $params['channel_id'],
                    "created_by" => $params['user_id'],
                    "updated_by" => $params['user_id'],
                ];

                $createBookingEngineToken = $this->propertyBookingEngineService->createBookingEngineToken($channelTokenParam);
                if ($createBookingEngineToken['status'] != 'success') {
                    throw new ApiErrorException($createBookingEngineToken['message']);
                }


            }else{

                $updatePropertyChannelMappingData = [
                    "currency_code" => $params['currency_code'],
                    "property_booking_type_id" => $params['booking_type_id'],
                    "property_availability_type_id" => $params['availability_type_id'],
                    "property_room_pricing_type_id" => $params['room_pricing_type_id'],
                    "connected_channel_id" => fillOnUndefined($params,'connected_channel_id'),
                    "connected_channel_action" => fillOnUndefined($params,'connected_channel_action'),
                    "updated_by" => $params['user_id'],
                    "status" => 1,
                    "updated_at" => time(),
                ];

                $validationResult = $this->propertyChannelSetupUpdateValidator->validate($params);

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

                if($params['contract_file'] != null){
                    $contractFileUploadParams = [
                        'property_id' => $params['property_id'],
                        'channel_id' => $params['channel_id'],
                        'contract_file' => $params['contract_file'],
                    ];

                    $contractFileUpload = $this->propertyBookingEngineService->contractFileUpload($contractFileUploadParams);
                    if ($contractFileUpload['status'] != 'success') {
                        throw new Exception('api-unknown_error');
                    }

                    $updatePropertyChannelMappingData["contract_file"] = $contractFileUpload["data"]["contract_file_path"];
                }



                $updateStatus =   $this->update($oldMappingList['id'], $updatePropertyChannelMappingData);

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

                if ($oldMappingList['property_availability_type_id'] != $params['availability_type_id']) {
                    $dropParams = [
                        'property_id' => $params['property_id'],
                        'channel_id' => $params['channel_id'],
                    ];
                    $deleteOldAvailability = $this->propertyRoomAvailabilityService->dropPropertyChannelGuaranteedAndLimitedAvailability($dropParams);
                    if ($deleteOldAvailability['status'] != 'success') {
                        throw new ApiErrorException($deleteOldAvailability['message']);
                    }
                }

                $channelTokenParam = [
                    "property_id" => $params['property_id'],
                    "channel_id" => $params['channel_id'],
                    "updated_by" => $params['user_id'],
                ];

                $reactivateBookingEngineToken = $this->propertyBookingEngineService->reactivateBookingEngineToken($channelTokenParam);
                if ($reactivateBookingEngineToken['status'] != 'success') {
                    throw new ApiErrorException($reactivateBookingEngineToken['message']);
                }
            }

            //Booking Engine Channel - Channel Manager Replication
            if($params['channel_id'] == 1 && !empty($params['connected_channel_id']) && $params['connected_channel_id'] == 5) {


                //Delete Old Prices
                $oldRoomRatesCriteria = [
                    'criteria' => [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                        ['field' => 'channel_id', 'condition' => '=', 'value' => $params['channel_id']],
                        ['field' => 'date', 'condition' => '>=', 'value' => Carbon::now()->toDateString()],
                    ]
                ];

                $oldRoomRates = $this->propertyRoomRatePriceRepository->findbyCriteria($oldRoomRatesCriteria, ['id']);
                if(!empty($oldRoomRates)) {
                    $oldRoomRatePriceIds = collect($oldRoomRates)->pluck('id')->toArray();
                    $deleteRoomRatePrices = $this->propertyRoomRatePriceRepository->destroy($oldRoomRatePriceIds);
                    if($deleteRoomRatePrices['status'] != 'success') {
                        throw new ApiErrorException($deleteRoomRatePrices['message']);
                    }
                }
                //Delete Old Prices

                $getPropertyRoomInventoryParam = [
                    'property_id' => $params['property_id'],
                    'channel_id' => 5,
                    'start_date' => Carbon::now()->toDateString(),
                    'end_date' => Carbon::now()->addYear()->subDay()->toDateString(),
                ];

                $getPropertyRoomInventory = $this->propertyRoomService->getPropertyRoomInventory($getPropertyRoomInventoryParam);
                if($getPropertyRoomInventory['status'] != 'success'){
                    throw new ApiErrorException($getPropertyRoomInventory['message']);
                }

                $getPropertyRoomInventory = $getPropertyRoomInventory['data'];

                $roomRateReplicationParam = [
                    'property_id' => $params['property_id'],
                    'channel_id' => 1,
                    'user_id' => $params['user_id'],
                    'availability' => [],
                    'rates' => []
                ];

                foreach ($getPropertyRoomInventory as $roomInventory) {
                    foreach ($roomInventory['property_room_rate_mapping'] as $propertyRoomRate) {
                        if(isset($propertyRoomRate['prices'][1])) {
                            foreach ($propertyRoomRate['prices'][1]['price'] as $date => $price) {
                                $roomRateKey = '1|'.$roomInventory['id'].'|'.$propertyRoomRate['id'].'|'.$date;
                                //availability_type_id|property_room_id|room_rate_mapping_id|2022-06-22
                                if(!is_null($price['value'])) {
                                    $roomRateReplicationParam['rates'][$roomRateKey] = [
                                        'setup_type_id' => '1',
                                        'room_id' => $roomInventory['id'],
                                        'room_rate_mapping_id' => $propertyRoomRate['id'],
                                        'date' => $date,
                                        'amount' => fillOnUndefined($price,'value', ''),
                                    ];
                                }
                            }
                        }
                    }
                }

                $roomRateReplication = $this->propertyRoomRatePriceService->roomRateUpdate($roomRateReplicationParam);
                if ($roomRateReplication['status'] != 'success') {
                    throw new ApiErrorException($roomRateReplication['message']);
                }

            }

            //Booking Engine Channel - Channel Manager Replication

            $response = ['status' => 1 , 'message' => '', 'data' => []];
            DB::commit();

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

        return output($response);
    }

    public function getPropertyChannelSetup($params)
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            $bookingTypeCriteria =
                [
                    "criteria" =>
                        [
                            ["field" => "status", "condition" => "=", "value" => 1],
                        ],

                ];
            $bookingTypes = $this->propertyBookingTypeRepository->findByCriteria($bookingTypeCriteria, ['id', 'name', 'language_key', 'code', 'icon']);
            $bookingTypes = $bookingTypes ? $bookingTypes : [];


            $availabilityTypeCriteria =
                [
                    "criteria" =>
                        [
                            ["field" => "status", "condition" => "=", "value" => 1],
                        ],

                ];
            $availabilityTypes = $this->propertyAvailabilityTypeRepository->findByCriteria($availabilityTypeCriteria, ['id', 'name', 'language_key', 'code', 'icon']);
            $availabilityTypes = $availabilityTypes ? $availabilityTypes : [];


            $criteria =
                [
                    "criteria" =>
                        [
                            ["field" => "status", "condition" => "=", "value" => 1]
                        ]
                ];
            $propertyRoomPricingTypes = $this->propertyRoomPricingTypeRepository->findByCriteria($criteria);
            $propertyRoomPricingTypes = $propertyRoomPricingTypes ? $propertyRoomPricingTypes : [];



            $getChannelMappingRequest = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ['field' => 'channel_id', 'condition' => '=', 'value' => $params['channel_id']],
                ],
                'firstRow' => 1
            ];
            $getChannelMappingResponse = $this->select($getChannelMappingRequest) ;

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

            $propertyBookingTypeId = NULL;
            $propertyAvailabilityTypeId = NULL;
            $propertyRoomPricingTypeId = NULL;
            $propertyContractFile = NULL;
            if(!empty($getChannelMappingResponse['data'])){
                $propertyBookingTypeId = $getChannelMappingResponse['data']['property_booking_type_id'];
                $propertyAvailabilityTypeId = $getChannelMappingResponse['data']['property_availability_type_id'];
                $propertyRoomPricingTypeId = $getChannelMappingResponse['data']['property_room_pricing_type_id'];

                if(!empty($getChannelMappingResponse['data']['contract_file'])){
                    $propertyContractFile = Config::get('app.propertyFilesUrl').$propertyContractFile.$getChannelMappingResponse['data']['contract_file'];
                }
            }

            $bookingList = [] ;
            $propertyRoomPricingTypeList = [] ;
            $availabilityList = [] ;
            $bulkUpdateOptions = [];

            foreach ($bookingTypes as $bookingType) {
                $bookingList[] = [
                    "booking_type_id" =>  $bookingType['id'],
                    "name" =>  $bookingType['name'],
                    "language_key" =>  $bookingType['language_key'],
                    "icon" =>  $bookingType['icon'],
                    "is_selected" =>  $bookingType['id'] === $propertyBookingTypeId ? true : false,
                ];
            }



            foreach ($availabilityTypes as $availabilityType) {
                $availabilityList[] = [
                    "availability_type_id" =>  $availabilityType['id'],
                    "name" =>  $availabilityType['name'],
                    "language_key" =>  $availabilityType['language_key'],
                    "icon" =>  $availabilityType['icon'],
                    "is_selected" =>  $availabilityType['id'] === $propertyAvailabilityTypeId ? true : false,
                ];

            }

            $roomAvailability = collect($availabilityList)->where('availability_type_id',1)->first();
            $limitedAvailability = collect($availabilityList)->where('availability_type_id',2)->first();
            $guaranteedAvailability = collect($availabilityList)->where('availability_type_id',3)->first();

            foreach ($availabilityList as $index => $availabilityListItem){
                if($propertyAvailabilityTypeId === 1){

                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => $roomAvailability['language_key'],
                        "type" =>  "availability",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => $roomAvailability['language_key'],
                        "type" =>  "rate",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => $roomAvailability['language_key'],
                        "type" =>  "room_stop_sell",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => $roomAvailability['language_key'],
                        "type" =>  "rate_stop_sell",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => $roomAvailability['language_key'],
                        "type" =>  "min_stay",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];


                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => 'enw-input-quick_pricing',
                        "type" =>  "quick_pricing",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];

                    break;
                }else if($propertyAvailabilityTypeId === 2){

                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => $roomAvailability['language_key'],
                        "type" =>  "availability",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $limitedAvailability['name'],
                        "language_key" => $limitedAvailability['language_key'],
                        "type" =>  "availability",
                        "availability_type_id" => $limitedAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $limitedAvailability['name'],
                        "language_key" => $limitedAvailability['language_key'],
                        "type" =>  "rate",
                        "availability_type_id" => $limitedAvailability['availability_type_id']
                    ];
                    break;
                }else if($propertyAvailabilityTypeId === 3){

                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => $roomAvailability['language_key'],
                        "type" =>  "availability",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $roomAvailability['name'],
                        "language_key" => $roomAvailability['language_key'],
                        "type" =>  "rate",
                        "availability_type_id" => $roomAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $guaranteedAvailability['name'],
                        "language_key" => $guaranteedAvailability['language_key'],
                        "type" =>  "availability",
                        "availability_type_id" => $guaranteedAvailability['availability_type_id']
                    ];

                    $bulkUpdateOptions[] = [
                        "name" => $guaranteedAvailability['name'],
                        "language_key" => $guaranteedAvailability['language_key'],
                        "type" =>  "rate",
                        "availability_type_id" => $guaranteedAvailability['availability_type_id']
                    ];
                    break;
                }

            }

            foreach ($propertyRoomPricingTypes as $propertyRoomPricingType) {
                $propertyRoomPricingTypeList[] = [
                    "room_pricing_type_id" =>  $propertyRoomPricingType['id'],
                    "name" =>  $propertyRoomPricingType['name'],
                    "language_key" =>  $propertyRoomPricingType['language_key'],
                    "icon" =>  $propertyRoomPricingType['icon'],
                    "is_selected" =>  $propertyRoomPricingType['id'] === $propertyRoomPricingTypeId ? true : false,
                ];
            }

            $responseData = [
                'property_id' => $params['property_id'],
                'channel_id' => $params['channel_id'],
                'booking' => $bookingList,
                'room_price_type' => $propertyRoomPricingTypeList,
                'availability' => $availabilityList,
                'bulk_update_options' => $bulkUpdateOptions,
                'contract_file_url' => $propertyContractFile
            ];

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

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

        return output($response);
    }

    public function checkPropertyChannelMapping($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {
            $getMapping = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ['field' => 'channel_id', 'condition' => '=', 'value' => $params['channel_id']],
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                ]
            ];
            $data = $this->propertyChannelMappingRepository->findByCriteria($getMapping);
            if(!$data){
                throw new ApiErrorException('api-unknown_error');
            }
            $response['status'] = 1;
            $response['data'] = $data;

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

        return output($response);
    }

    public function addPropertyChannelSetupWithMissingParameters($params){

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

        try {

            $criteria =
                [
                    "criteria" =>
                        [
                            ["field" => "property_id", "condition" => "=", "value" => $params['property_id']],
                            ["field" => "channel_id", "condition" => "=", "value" => $params['channel_id']],
                        ],
                    'firstRow' => true
                ];
            $oldMappingList = $this->propertyChannelMappingRepository->findByCriteria($criteria);

            if($oldMappingList){

                //UPDATE
                $updatePropertyChannelMappingData = [
                    "updated_by" => $params['user_id'],
                    "status" => self::STATUS_PENDING,
                    "updated_at" => time(),
                ];

                $createdOrUpdatedResponse = $this->update($oldMappingList['id'], $updatePropertyChannelMappingData);
                if($createdOrUpdatedResponse['status'] != 'success'){
                    throw new ApiErrorException($createdOrUpdatedResponse['message']);
                }

            }else{

                //CREATE
                $addPropertyChannelMappingData = [
                    "property_id" => $params['property_id'],
                    "channel_id" => $params['channel_id'],
                    "currency_code" => null,
                    "property_booking_type_id" => null,
                    "property_availability_type_id" => null,
                    "property_room_pricing_type_id" => null,
                    "status" => self::STATUS_PENDING,
                    "created_by" => $params['user_id'],
                    "updated_by" => $params['user_id'],
                ];

                $validationResult = $this->propertyChannelSetupWithMissingParametersAddValidator->validate($addPropertyChannelMappingData);

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

                $createdOrUpdatedResponse = $this->propertyChannelMappingRepository->create($addPropertyChannelMappingData);
                if($createdOrUpdatedResponse['status'] != 'success'){
                    throw new Exception('api-unknown_error');
                }

            }

            if(!empty($createdOrUpdatedResponse['data'])){
                $response['data'] = [
                    "property_id" => $createdOrUpdatedResponse['data']['property_id'],
                    "channel_id" => $createdOrUpdatedResponse['data']['channel_id'],
                    "currency_code" => $createdOrUpdatedResponse['data']['currency_code'],
                    "property_booking_type_id" => $createdOrUpdatedResponse['data']['property_booking_type_id'],
                    "property_availability_type_id" => $createdOrUpdatedResponse['data']['property_availability_type_id'],
                    "property_room_pricing_type_id" => $createdOrUpdatedResponse['data']['property_room_pricing_type_id'],
                    "status" => $createdOrUpdatedResponse['data']['status']
                ];
            }

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

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

        return output($response);

    }

    public function getPropertyChildChannel($params){

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

        try {

            $getPropertyCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                ],
                'with' => ['channel']

            ];
            $getChannels = $this->propertyChannelMappingRepository->findByCriteria($getPropertyCriteria) ;

            $childDatas = collect($getChannels)->where('channel.channel_category_id', 4)
                ->where('channel.parent_id', '!=', null)->toArray();

            $responseData = [];

            if(!empty($childDatas)){

                foreach ($childDatas as $childData){
                    $responseData[] = [
                        'channel_mapping_id' => $childData['id'],
                        'property_id' => $childData['property_id'],
                        'channel_id' => $childData['channel_id'],
                        'status' => $childData['status'],
                        'channel_name' => $childData['channel']['name'],
                        'channel_logo' => $childData['channel']['logo']

                    ];
                }

            }

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

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

        return output($response);

    }

    public function getPropertyChannelMappingForChannelGroup($params)
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            $getChannelMappingCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ['field' => 'property_availability_type_id', 'condition' => '=', 'value' => 1],
                ],
                'whereIn' => [
                    ['field' => 'channel_id', 'value' => $params['channel_ids']]
                ]
            ];

            $getChannels = $this->propertyChannelMappingRepository->findByCriteria($getChannelMappingCriteria) ;
            if(!$getChannels){
                throw new ApiErrorException('api-unknown_error');
            }
            $response = ['status' => 1 , 'message' => '', 'data' => $getChannels];

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

        return output($response);
    }

    public function getOnlyPropertyChannelMapping($params)
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            $getChannelMappingCriteria = [
                'criteria' => [
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ['field' => 'channel_id', 'condition' => '=', 'value' => $params['channel_id']],
                ],
                'firstRow' => 1
            ];

            $getChannels = $this->propertyChannelMappingRepository->findByCriteria($getChannelMappingCriteria) ;
            if(!$getChannels){
                throw new ApiErrorException('api-unknown_error');
            }
            $response = ['status' => 1 , 'message' => '', 'data' => $getChannels];

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

        return output($response);
    }

}
