<?php

namespace App\Core\Service;

use App\Core\Repository\PropertyRoomAvailability\PropertyRoomAvailabilityRepository;
use App\Core\Repository\PropertyChannel\PropertyChannelRepository;
use App\Core\Repository\PropertyRoomRateMapping\PropertyRoomRateMappingRepository;
use App\Core\Repository\Property\PropertyRepository;
use App\Core\Repository\PropertyRoomConnected\PropertyRoomConnectedRepository;

use App\Core\Validator\PropertyRoomAvailability\PropertyRoomAvailabilityAddValidator;
use App\Core\Validator\PropertyRoomAvailability\PropertyRoomAvailabilityUpdateValidator;
use App\Core\Validator\PropertyRoomAvailability\PropertyRoomAvailabilityDeleteValidator;
use App\Core\Validator\PropertyRoomAvailability\PropertyRoomAvailabilityBulkUpdateValidator;
use App\Core\Validator\PropertyRoomAvailability\PropertyRoomAvailabilityBulkInsertValidator;


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

class PropertyRoomAvailabilityService
{

    private $propertyRoomAvailabilityRepository;
    private $propertyRoomService;

    private $propertyRoomAvailabilityAddValidator;
    private $propertyRoomAvailabilityUpdateValidator;
    private $propertyRoomAvailabilityDeleteValidator;
    private $propertyRoomAvailabilityBulkUpdateValidator;
    private $propertyRoomAvailabilityBulkInsertValidator;

    private $propertyChannelRepository;
    private $propertyRoomRateMappingRepository;
    private $propertyRepository;
    private $propertyRoomConnectedRepository;


    public function __construct(

        PropertyRoomAvailabilityRepository $propertyRoomAvailabilityRepository,
        PropertyRoomService $propertyRoomService,
        PropertyRoomAvailabilityAddValidator $propertyRoomAvailabilityAddValidator,
        PropertyRoomAvailabilityUpdateValidator $propertyRoomAvailabilityUpdateValidator,
        PropertyRoomAvailabilityDeleteValidator $propertyRoomAvailabilityDeleteValidator,
        PropertyRoomAvailabilityBulkUpdateValidator $propertyRoomAvailabilityBulkUpdateValidator,
        PropertyRoomAvailabilityBulkInsertValidator $propertyRoomAvailabilityBulkInsertValidator,

        PropertyChannelRepository $propertyChannelRepository,
        PropertyRoomRateMappingRepository $RoomAvailabilityMappingRepository,
        PropertyRepository $propertyRepository,
        PropertyRoomConnectedRepository $propertyRoomConnectedRepository
    )
    {

        $this->propertyRoomAvailabilityRepository = $propertyRoomAvailabilityRepository;
        $this->propertyRoomAvailabilityAddValidator = $propertyRoomAvailabilityAddValidator;
        $this->propertyRoomAvailabilityUpdateValidator = $propertyRoomAvailabilityUpdateValidator;
        $this->propertyRoomAvailabilityDeleteValidator = $propertyRoomAvailabilityDeleteValidator;
        $this->propertyRoomAvailabilityBulkUpdateValidator = $propertyRoomAvailabilityBulkUpdateValidator;
        $this->propertyRoomAvailabilityBulkInsertValidator = $propertyRoomAvailabilityBulkInsertValidator;
        $this->propertyRoomService = $propertyRoomService;

        $this->propertyChannelRepository = $propertyChannelRepository;
        $this->propertyRoomRateMappingRepository = $RoomAvailabilityMappingRepository;
        $this->propertyRepository = $propertyRepository;
        $this->propertyRoomConnectedRepository = $propertyRoomConnectedRepository;


    }


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


            $startDate = Carbon::parse($params['start_date']);
            $endDate = Carbon::parse($params['end_date']);
            $diffInDays = $startDate->diffInDays($endDate);
            $availabilityTypeId = fillOnUndefined($params, 'availability_type_id', 1);
            $propertyId = fillOnUndefined($params, 'property_id', 0);

            $includeDays = fillOnUndefined($params, 'include_days', []);
            $insertData = [];

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

            if ($params["update_type"] == "availability") {
                $updateColumn = "availability";
            } elseif ($params["update_type"] == "room_stop_sell") {
                $updateColumn = "stop_sell";
            }


            $updateData = [
                $updateColumn => $params['value'],
                'updated_by' => fillOnUndefined($params, "user_id", 0),
                'updated_at' => Carbon::now()->timestamp
            ];

            $selectIds = $this->selectRoomRateIds($params);
            if ($selectIds['status'] != 'success') {
                throw new ApiErrorException('array error');
            }
            $selectIds = $selectIds['data'];

            $RoomAvailabilityMappingRequest = [
                'whereIn' => [
                    ['field' => 'id', 'value' => $selectIds['room_rate_mapping_ids']],
                ]
            ];
            $selectedRoomRateMapping = $this->propertyRoomRateMappingRepository->findByCriteria($RoomAvailabilityMappingRequest);
            $selectedRoomRateMapping = $selectedRoomRateMapping ? $selectedRoomRateMapping : [];
            $selectedRoomRateMapping = collect($selectedRoomRateMapping);



            $oldRoomAvailabilitiesCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                    ['field' => 'date', 'condition' => '>=', 'value' => $params['start_date']],
                    ['field' => 'date', 'condition' => '<=', 'value' => $params['end_date']],
                ]
            ];

            $oldRoomAvailability = $this->propertyRoomAvailabilityRepository->findbyCriteria($oldRoomAvailabilitiesCriteria);
            $oldRoomAvailability = $oldRoomAvailability ? $oldRoomAvailability : [];
            $updateThis = [];
            $deleteThis = [];
            $newAvailabilityArray = [];

            foreach ($params['room_rates'] as $RoomAvailability) {
                $startDate = Carbon::parse($params['start_date']);
                for ($i = 0; $i <= $diffInDays; $i++) {
                    if ($availabilityTypeId == 1) {
                        $checkKey = $RoomAvailability['room_id'] . "||" . $startDate->format('Y-m-d') . "||" . $params['availability_type_id'];;
                        $newAvailabilityArray[$checkKey] = [
                            'property_id' => $propertyId,
                            'property_room_id' => $RoomAvailability['room_id'],
                            'availability_type_id' => $availabilityTypeId,
                            'date' => $startDate->format('Y-m-d'),
                            $updateColumn => fillOnUndefined($params, 'value', 0),
                        ];
                    } else {
                        foreach ($RoomAvailability['room_rate_mapping_id'] as $RoomAvailabilityMapping) {
                            $checkKey = $RoomAvailability['room_id'] . "|" . $RoomAvailabilityMapping . "|" . $startDate->format('Y-m-d') . "|" . $params['channel_id'] . "|" . $params['availability_type_id'];
                            $newAvailabilityArray[$checkKey] = [
                                'property_id' => $propertyId,
                                'property_room_id' => $RoomAvailability['room_id'],
                                'availability_type_id' => $availabilityTypeId,
                                'date' => $startDate->format('Y-m-d'),
                                $updateColumn => fillOnUndefined($params, 'value', 0),
                                'room_rate_mapping_id' => $RoomAvailabilityMapping,
                            ];
                        }
                    }
                    $startDate = $startDate->addDay();
                }
            }

            $oldRoomAvailabilityKeys = [];
            foreach ($oldRoomAvailability as $oldAvailability) {
                $oldAvailabilityKey = $oldAvailability['property_room_id'] . "|" . $oldAvailability['room_rate_mapping_id'] . "|" . $oldAvailability['date'] . "|" . $oldAvailability['channel_id'] . "|" . $oldAvailability['availability_type_id'];
                $oldAvailability[$updateColumn] = isset($newAvailabilityArray[$oldAvailabilityKey]) ? $newAvailabilityArray[$oldAvailabilityKey][$updateColumn] : $oldAvailability[$updateColumn];

                $oldRoomAvailabilityKeys[$oldAvailabilityKey][] = $oldAvailability;
            }

            //Sistemdeki benzer id listesi, mysql null unique index hatası için
            foreach ($oldRoomAvailabilityKeys as $availabilityKey => $oldRoomAvailability) {

                if(count($oldRoomAvailability) > 1) {
                    $oldRoomAvailabilityKeys[$availabilityKey] = last($oldRoomAvailability);
                    $otherAvailabilityRowIds = collect($oldRoomAvailability)->whereNotIn('id', [$oldRoomAvailabilityKeys[$availabilityKey]['id']])->pluck('id')->toArray();
                    $oldRoomAvailabilityKeys[$availabilityKey] = last($oldRoomAvailability);
                    $oldRoomAvailabilityKeys[$availabilityKey]['otherIds'] = $otherAvailabilityRowIds;
                } else {
                    $oldRoomAvailabilityKeys[$availabilityKey] = reset($oldRoomAvailability);
                }

            }

            $quotaCollection = collect($oldRoomAvailabilityKeys)
                ->whereIn('availability_type_id', [0, 3]);

            foreach ($params['room_rates'] as $RoomAvailability) {
                $startDate = Carbon::parse($params['start_date']);

                for ($i = 0; $i <= $diffInDays; $i++) {

                    if (!in_array($startDate->shortEnglishDayOfWeek, $includeDays)) {
                        $startDate = $startDate->addDay();
                        continue;
                    }


                    $insertDataItem = [
                        'property_id' => $propertyId,
                        'property_room_id' => $RoomAvailability['room_id'],
                        'availability_type_id' => $availabilityTypeId,
                        'date' => $startDate->format('Y-m-d'),
                        $updateColumn => fillOnUndefined($params, 'value', 0),
                        'status' => fillOnUndefined($params, "status", 1),
                        'created_by' => fillOnUndefined($params, "user_id", 0),
                        'updated_by' => fillOnUndefined($params, "user_id", 0),
                        'created_at' => Carbon::now()->timestamp,
                        'updated_at' => Carbon::now()->timestamp,
                    ];

                    if ("update_type" == "availability") {
                        if ($availabilityTypeId == 1 || $availabilityTypeId == 3) {
                            $poolKey = $RoomAvailability['room_id'] . "||" . $startDate->format('Y-m-d') . "||1";
                            $poolAvailability = isset($oldRoomAvailabilityKeys[$poolKey]['availability']) ? $oldRoomAvailabilityKeys[$poolKey]['availability'] : 0;
                            $totalGuaranteedQuota = $quotaCollection
                                ->where('date', '=', $startDate->format('Y-m-d'))
                                ->where('property_room_id', '=', $RoomAvailability['room_id'])
                                ->where('availability_type_id', '=', 3)
                                ->sum('availability');
                            if ($totalGuaranteedQuota > $poolAvailability) {
                                throw new ApiErrorException(" $propertyId - $RoomAvailability[room_id] - " . $startDate->format('Y-m-d') . " (" . $totalGuaranteedQuota . " < " . $poolAvailability . " ) Guaranteed availability total cannot be higher than Pool availability ");
                            }
                        }
                    }


                    if ($availabilityTypeId == 1) {
                        $insertDataItem['room_rate_mapping_id'] = null;
                        $checkKey = $RoomAvailability['room_id'] . "||" . $startDate->format('Y-m-d') . "||" . $params['availability_type_id'];;
                        if (isset($oldRoomAvailabilityKeys[$checkKey])) {
                            $updateThis[] = $oldRoomAvailabilityKeys[$checkKey]['id'];
                        } else {
                            $insertData[] = $insertDataItem;
                        }

                        if(isset($oldRoomAvailabilityKeys[$checkKey]['otherIds'])) {
                            foreach ($oldRoomAvailabilityKeys[$checkKey]['otherIds'] as $otherId) {
                                $deleteThis[] = $otherId;
                            }
                        }

                    } else {
                        $insertDataItem['channel_id'] = fillOnUndefined($params, 'channel_id', 1);
                        foreach ($RoomAvailability['room_rate_mapping_id'] as $RoomAvailabilityMapping) {
                            $insertDataItem['room_rate_mapping_id'] = $RoomAvailabilityMapping;
                            $checkKey = $RoomAvailability['room_id'] . "|" . $RoomAvailabilityMapping . "|" . $startDate->format('Y-m-d') . "|" . $params['channel_id'] . "|" . $params['availability_type_id'];
                            if (isset($oldRoomAvailabilityKeys[$checkKey])) {
                                $updateThis[] = $oldRoomAvailabilityKeys[$checkKey]['id'];
                            } else {
                                $insertData[] = $insertDataItem;
                            }
                        }

                    }
                    $startDate = $startDate->addDay();
                }
            }




            if ($deleteThis) {
                $destroyResult = $this->propertyRoomAvailabilityRepository->destroy($deleteThis);
                if ($destroyResult['status'] != 'success') {
                    throw new Exception('api-unknown_error');
                }
            }

            if ($updateThis) {
                $thisUpdateArrayChunk = array_chunk($updateThis, 1000);
                foreach ($thisUpdateArrayChunk as $updateIds) {
                    $data = $this->propertyRoomAvailabilityRepository->updateWhereIn($updateIds, $updateData);
                    if ($data['status'] != 'success') {
                        throw new Exception('api-unknown_error');
                    }
                }
            }

            $thisInsertArrayChunk = array_chunk($insertData, 1000);
            foreach ($thisInsertArrayChunk as $insertThis) {
                $data = $this->propertyRoomAvailabilityRepository->insert($insertThis);
                if ($data['status'] != 'success') {
                    throw new Exception('api-unknown_error');
                }
            }

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

            //Connected Room Case
            $roomAvailabilityUpdateForConnectedRoomParams = [
                'property_id' => $params['property_id'],
                'channel_id' => $params['channel_id'],
                'availability_type_id' => [$availabilityTypeId],
                'startDate' => $params['start_date'],
                'endDate' => $params['end_date']
            ];

            $this->roomAvailabilityUpdateForConnectedRooms($roomAvailabilityUpdateForConnectedRoomParams);
            //Connected Room Case

            $response = [
                'status' => true,
                'data' => null,
            ];

        } 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 selectRoomRateIds($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            $roomIds = [];
            $RoomAvailabilityIds = [];


            foreach ($params['room_rates'] as $RoomAvailability) {
                $roomIds[] = $RoomAvailability['room_id'];

                if (isset($RoomAvailability['room_rate_mapping_id'])) {
                    foreach ($RoomAvailability['room_rate_mapping_id'] as $RoomAvailabilityMapping) {
                        $RoomAvailabilityIds[] = $RoomAvailabilityMapping;
                    }
                }
            }
            $roomIds = array_unique($roomIds);
            $RoomAvailabilityIds = array_unique($RoomAvailabilityIds);
            $response = [
                'status' => true,
                'data' => [
                    'room_ids' => $roomIds,
                    'room_rate_mapping_ids' => $RoomAvailabilityIds,
                ],
            ];


        } 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 roomAvailabilityUpdate($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            $newMappingArray = $params ? $params : [];

            $validationResult = $this->propertyRoomAvailabilityBulkUpdateValidator->validate($newMappingArray);

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

            $newMappingArray = $newMappingArray['availability'];


            $newMappingCollect = collect($newMappingArray);
            $startDate = $newMappingCollect->min('date');
            $endDate = $newMappingCollect->max('date');
            $channelSetupTypes = $this->propertyRoomService->setChannelAvailabilityTypes(['property_id' => $params['property_id'], 'channel_id' => $params['channel_id']]);
            if ($channelSetupTypes['status'] != 'success') {
                throw new ApiErrorException($channelSetupTypes['message']);
            }
            $channelSetupTypes = $channelSetupTypes['data'];
            $forGeneralId = $channelSetupTypes['forGeneralId'];
            $forAvailabilityData = $channelSetupTypes['forAvailabilityData'];
            $forPriceData = $channelSetupTypes['forPriceData'];
            $channelWorkingAvailabilityType = $channelSetupTypes['channelAvailabilityWorkingType'];
            $getPriceDataIds = collect($forPriceData)->keyBy('id')->keys()->toArray();
            $getAvailabilityDataIds = collect($forAvailabilityData)->keyBy('id')->keys()->toArray();
            $getAvailabilityDataIds = array_unique(array_merge($forGeneralId, $getAvailabilityDataIds));

            $availabilityRequest = [
                'property_id' => $params['property_id'],
                'start_date' => $startDate,
                'end_date' => $endDate,
                'channel_id' => $params['channel_id'],
                'availability_type_id' => $getAvailabilityDataIds,
            ];

            $availabilityArray = $this->propertyRoomService->inventoryAvailabilityData($availabilityRequest);


            $oldMappingArray = [];
            foreach ($availabilityArray as $oldAvailability) {
                $mergeMappingKey = $oldAvailability['availability_type_id'] . '|' . $oldAvailability['room_id'] . '|' . $oldAvailability['room_rate_mapping_id'] . '|' . $oldAvailability['channel_id'] . '|' . $oldAvailability['date'];
                $oldMappingArray[$oldAvailability['availability_type_id'] . '|' . $oldAvailability['room_id'] . '|' . $oldAvailability['room_rate_mapping_id'] . '|' . $oldAvailability['channel_id'] . '|' . $oldAvailability['date']] = [
                    'id' => $oldAvailability['id'],
                    'room_id' => $oldAvailability['room_id'],
                    'room_rate_mapping_id' => $oldAvailability['room_rate_mapping_id'],
                    'availability_type_id' => $oldAvailability['availability_type_id'],
                    'channel_id' => $oldAvailability['channel_id'],
                    'date' => $oldAvailability['date'],
                    'availability' => isset($newMappingArray[$mergeMappingKey]['availability']) ? $newMappingArray[$mergeMappingKey]['availability'] : $oldAvailability['availability'],
                    'stop_sell' => $oldAvailability['stop_sell'],
                    'old_availability' => $oldAvailability['availability'],
                    'otherIds' => isset($oldAvailability['otherIds']) ? $oldAvailability['otherIds'] : [],
                ];
            }
            $quotaCollection = collect($oldMappingArray)
                ->whereIn('availability_type_id', [0, 3]);

            $deleteThis = [];
            $insertThis = [];
            foreach ($newMappingArray as $key => $newMapping) {

                $channelId = $newMappingArray[$key]['room_rate_mapping_id'] != null ? fillOnUndefined($params, 'channel_id') : null;

                // check pool availability overload quota


                $poolKey = '1|' . $newMapping['room_id'] . '|||' . $newMapping['date'];
                $poolAvailability = isset($oldMappingArray[$poolKey]['availability']) ? $oldMappingArray[$poolKey]['availability'] : 0;

                // Check Guaranteed Availability - Pool Availability
                if ($channelWorkingAvailabilityType == 3) {
                    $totalGuaranteedQuota = $quotaCollection
                        ->where('date', '=', $newMapping['date'])
                        ->where('room_id', '=', $newMapping['room_id'])
                        ->where('availability_type_id', '=', 3)
                        ->sum('availability');
                    if ($totalGuaranteedQuota > $poolAvailability) {
                        throw new ApiErrorException('Guaranteed availability total cannot be higher than Pool availability');
                    }
                }

                if (isset($newMapping['availability']) && $newMapping['availability'] === "") {
                    $newMapping['availability'] = 0;
                    $newMappingArray[$key]['availability'] = 0;
                }

                if (isset($newMapping['availability']) && $newMapping['availability'] === "") {
                    if (isset($oldMappingArray[$key])) {
                        $deleteThis[] = $oldMappingArray[$key]['id'];
                    }
                } else {

                    if (isset($newMappingArray[$key]['availability'])) {
                        $insertItemAvailability = $newMappingArray[$key]['availability'];
                    } elseif (isset($oldMappingArray[$key]['availability'])) {
                        $insertItemAvailability = $oldMappingArray[$key]['availability'];
                    } else {
                        $insertItemAvailability = 0;
                    }


                    if (isset($newMappingArray[$key]['stop_sell'])) {
                        $insertItemStopSell = $newMappingArray[$key]['stop_sell'];
                    } elseif (isset($oldMappingArray[$key]['stop_sell'])) {
                        $insertItemStopSell = $oldMappingArray[$key]['stop_sell'];
                    } else {
                        $insertItemStopSell = 0;
                    }

                    $insertItem = [
                        'property_id' => fillOnUndefined($params, 'property_id', 0),
                        'property_room_id' => fillOnUndefined($newMappingArray[$key], 'room_id', 0),
                        'room_rate_mapping_id' => $newMappingArray[$key]['room_rate_mapping_id'],
                        'channel_id' => $channelId,
                        'availability_type_id' => fillOnUndefined($newMappingArray[$key], 'setup_type_id', null),
                        'date' => fillOnUndefined($newMappingArray[$key], 'date', 0),
                        'availability' => $insertItemAvailability,
                        'stop_sell' => $insertItemStopSell,
                        'status' => fillOnUndefined($params, "status", 1),
                        'created_by' => fillOnUndefined($params, "user_id", 0),
                        'updated_by' => fillOnUndefined($params, "user_id", 0),
                        'created_at' => Carbon::now()->timestamp,
                        'updated_at' => Carbon::now()->timestamp,
                    ];


                    if (isset($oldMappingArray[$key])) {

                        if(isset($oldMappingArray[$key]['otherIds'])) {
                            foreach ($oldMappingArray[$key]['otherIds'] as $otherSimilarId) {
                                $deleteThis[] = $otherSimilarId;
                            }
                        }

                        if ($oldMappingArray[$key]['old_availability'] != $insertItem['availability'] || $oldMappingArray[$key]['stop_sell'] != $insertItem['stop_sell']) {
                            $deleteThis[] = $oldMappingArray[$key]['id'];

                            $insertThis[] = $insertItem;
                            /*
                            if( $newMappingArray[$key]['availability'] !== 0 ){
                                $insertThis[] = $insertItem ;
                            }
                            */
                        }
                    } else {

                        $insertThis[] = $insertItem;

                        /*
                        if($newMappingArray[$key]['availability'] !== 0){

                            $insertThis[] = $insertItem ;
                        }
                        */
                    }
                }

            }
            sort($deleteThis);


            if ($deleteThis) {
                $deleteAvailability = $this->propertyRoomAvailabilityRepository->destroy($deleteThis);
                if ($deleteAvailability['status'] != 'success') {
                    throw new Exception('api-unknown_error');
                }
            }

            $insertAvailability = $this->propertyRoomAvailabilityRepository->insert($insertThis);

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

            //Connected Room Case
            $roomAvailabilityUpdateForConnectedRoomParams = [
                'property_id' => $params['property_id'],
                'channel_id' => $params['channel_id'],
                'availability_type_id' => $getAvailabilityDataIds,
                'startDate' => $startDate,
                'endDate' => $endDate,
                'user_id' => fillOnUndefined($params, "user_id", 0)
            ];

            $this->roomAvailabilityUpdateForConnectedRooms($roomAvailabilityUpdateForConnectedRoomParams);
            //Connected Room Case

            $response = [
                'status' => true,
                'data' => null,
            ];

        } 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 dropPropertyChannelGuaranteedAndLimitedAvailability($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            $roomAvailabilityCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ['field' => 'channel_id', 'condition' => '=', 'value' => $params['channel_id']],
                    ['field' => 'date', 'condition' => '>=', 'value' => date('Y-m-d')],
                ],
                'whereIn' => [
                    ['field' => 'availability_type_id', 'value' => [2, 3]]
                ],
            ];
            $roomAvailability = $this->propertyRoomAvailabilityRepository->findbyCriteria($roomAvailabilityCriteria, ['id']);
            $roomAvailability = $roomAvailability ? $roomAvailability : [];
            $deleteThis = array_column($roomAvailability, 'id');

            if ($deleteThis) {
                $destroyResult = $this->propertyRoomAvailabilityRepository->destroy($deleteThis);
                if ($destroyResult['status'] != 'success') {
                    throw new Exception('api-unknown_error');
                }
            }

            $response = [
                'status' => true,
                'data' => null,
            ];

        } 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 select($param = [], $column = ['*'])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {
            $data = $this->propertyRoomAvailabilityRepository->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 update($id, $param = [])
    {


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


            $updateResult = $this->propertyRoomAvailabilityRepository->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 roomAvailabilityUpdateForConnectedRooms($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            if(is_null($params['startDate']) || is_null($params['endDate'])) {
                $response['status'] = true;
                return $response;
            }

            $diffInDays = Carbon::parse($params['startDate'])->diffInDays(Carbon::parse($params['endDate']));

            //Connected Room Case
            $propertyRoomConnectedCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                ],
                'with' => ['roomDetail']
            ];


            $propertyRoomConnected = $this->propertyRoomConnectedRepository->findbyCriteria($propertyRoomConnectedCriteria);
            $propertyRoomConnected = $propertyRoomConnected ? $propertyRoomConnected : [];

            $propertyRoomConnectedGrouped = collect($propertyRoomConnected)->groupBy('room_id')->toArray();

            $oldRoomAvailabilityCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ['field' => 'date', 'condition' => '>=', 'value' => $params['startDate']],
                    ['field' => 'date', 'condition' => '<=', 'value' => $params['endDate']],
                ]
            ];

            $oldRoomAvailability = $this->propertyRoomAvailabilityRepository->findbyCriteria($oldRoomAvailabilityCriteria);
            $oldRoomAvailability = $oldRoomAvailability ? collect($oldRoomAvailability) : [];


            foreach ($propertyRoomConnectedGrouped as $connectedRoomId => $connectedRooms) {

                $roomDetail = reset($connectedRooms)['room_detail'];


                if ($roomDetail['is_connected_room_availability'] != 1) {
                    continue;
                }

                //Güncellemede dikkat edilmesi gereken Oda ID leri
                $connectedRoomIds = pickItemFromArray('connected_room_id', $connectedRooms);

                //dd($params,$connectedRoomIds ,$oldRoomAvailability);

                for ($i = 0; $i <= $diffInDays; $i++) {

                    $date = Carbon::parse($params['startDate'])->addDays($i)->toDateString();


                    if (empty($oldRoomAvailability)) {
                        continue;
                    }

                    $issetCurrentRoomAvailability = $oldRoomAvailability
                        ->where('property_room_id', $connectedRoomId)
                        ->whereIn('availability_type_id', $params['availability_type_id'])
                        ->where('date', $date)->first();


                    $roomAvailabilityFromConnectedRooms = $oldRoomAvailability
                        ->whereIn('property_room_id', $connectedRoomIds)
                        ->whereIn('availability_type_id', $params['availability_type_id'])
                        ->where('date', $date)->sortBy('availability');

                    $roomAvailabilityFromConnectedRoomsIds = $roomAvailabilityFromConnectedRooms->pluck('property_room_id')->toArray();

                    $intersectRooms = array_intersect($roomAvailabilityFromConnectedRoomsIds, $connectedRoomIds);

                    if(count($intersectRooms) != count($connectedRoomIds)) {
                        continue;
                    }

                    $roomAvailabilityFromConnectedRooms = $roomAvailabilityFromConnectedRooms->first();
                    $roomAvailabilityFromConnectedRooms = fillOnUndefined($roomAvailabilityFromConnectedRooms, 'availability', 0);


                    //update
                    if (!empty($issetCurrentRoomAvailability)) {

                        $this->propertyRoomAvailabilityRepository->update($issetCurrentRoomAvailability['id'], ['availability' => $roomAvailabilityFromConnectedRooms]);

                    } else {

                        $insertItem = [
                            'property_id' => $params['property_id'],
                            'property_room_id' => $roomDetail['id'],
                            'room_rate_mapping_id' => null,
                            'channel_id' => !in_array(1,$params['availability_type_id']) ? $params['channel_id'] : null,
                            'availability_type_id' => !in_array(1,$params['availability_type_id']) ? reset($params['availability_type_id']) : 1,
                            'date' => $date,
                            'availability' => $roomAvailabilityFromConnectedRooms,
                            'stop_sell' => 0,
                            'status' => 1,
                            'created_by' => fillOnUndefined($params, "user_id", 0),
                            'updated_by' => fillOnUndefined($params, "user_id", 0),
                            'created_at' => Carbon::now()->timestamp,
                            'updated_at' => Carbon::now()->timestamp,
                        ];

                        $this->propertyRoomAvailabilityRepository->insert($insertItem);

                    }


                }

            }
            //Connected Room Case


            $response = [
                'status' => true,
            ];

        } 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 $response;
    }

}
