<?php

namespace App\Core\Service;

use App\Core\Repository\PropertyNonrefundable\PropertyNonrefundableRepository;
use App\Core\Validator\PropertyNonrefundable\PropertyNonrefundableAddValidator;
use App\Core\Repository\PropertyRoomRateChannelMapping\PropertyRoomRateChannelMappingRepository;
use App\Core\Repository\PropertyChannelMapping\PropertyChannelMappingRepository;

use App;
use Illuminate\Support\Facades\Log;
use Exception;
use App\Exceptions\ApiErrorException;
use Illuminate\Support\Facades\Config;
use phpDocumentor\Reflection\Types\Collection;
use Illuminate\Support\Facades\DB;


class PropertyNonrefundableService
{

    private $propertyNonrefundableRepository;
    private $propertyNonrefundableAddValidator;
    private $propertyRoomRateChannelMappingRepository;
    private $propertyChannelMappingRepository;


    public function __construct(
        PropertyNonrefundableRepository $propertyNonrefundableRepository,
        PropertyNonrefundableAddValidator $propertyNonrefundableAddValidator,
        PropertyRoomRateChannelMappingRepository $propertyRoomRateChannelMappingRepository,
        PropertyChannelMappingRepository $propertyChannelMappingRepository




    )
    {
        $this->propertyNonrefundableRepository = $propertyNonrefundableRepository;
        $this->propertyNonrefundableAddValidator = $propertyNonrefundableAddValidator;
        $this->propertyRoomRateChannelMappingRepository = $propertyRoomRateChannelMappingRepository ;
        $this->propertyChannelMappingRepository = $propertyChannelMappingRepository;
    }


    public function select($param = [], $column = ['*'])
    {

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

        try {

            $data = $this->propertyNonrefundableRepository->findByCriteria($param, $column);
            $response = [
                'status' => true,
                'data' => $data,
            ];

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

        return output($response);
    }

    public function createForm($params = [])
    {

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

        try {

            $roomRateChannelMappingRequest= [
              'criteria' => [
                  ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']]
              ],
                'whereIn' => [
                    ['field' => 'channel_id', 'value' => $params['channels']]
                ],
                'with' => ['propertyRoomRateMapping.propertyRoomRate', 'propertyRoomRateMapping.propertyRoom', 'propertyChannel'],
            ];

            $roomRateChannelMappingResponse = $this->propertyRoomRateChannelMappingRepository->findByCriteria($roomRateChannelMappingRequest) ;
            $roomRateChannelMappings = $roomRateChannelMappingResponse ? $roomRateChannelMappingResponse : [] ;
            $roomRates = [] ;

            $channels = [] ;

            foreach ( $roomRateChannelMappings as $roomRateChannelMapping) {
                $channels[] =  [
                    'id' => $roomRateChannelMapping['property_channel']['id'],
                    'name' => $roomRateChannelMapping['property_channel']['name'],
                    'logo' => $roomRateChannelMapping['property_channel']['logo'],
                ];
                $roomRates[$roomRateChannelMapping['room_rate_mapping_id']] = [
                    'room_rate_mapping_id' => $roomRateChannelMapping['room_rate_mapping_id'],
                    'name' => $roomRateChannelMapping['property_room_rate_mapping']['property_room']['name'] . ' - '. $roomRateChannelMapping['property_room_rate_mapping']['property_room_rate']['name'],
                    'room_id' => $roomRateChannelMapping['property_room_rate_mapping']['property_room']['id'],
                    'room_name' => $roomRateChannelMapping['property_room_rate_mapping']['property_room']['name'],
                    'rate_id' => $roomRateChannelMapping['property_room_rate_mapping']['property_room_rate']['id'],
                    'rate_name' => $roomRateChannelMapping['property_room_rate_mapping']['property_room_rate']['name'],
                ];
            }

            array_multisort(
                array_column($roomRates, 'room_name'), SORT_ASC,
                array_column($roomRates, 'rate_name'), SORT_ASC,
                $roomRates
            );

            $channels = collect($channels)->unique('id')->sort()->values()->toArray();

            $responseData = [
                'channels' => $channels,
                'room_rate_mapping' => $roomRates,
            ];
            $response = [
                'status' => true,
                'data' => $responseData,
            ];

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

        return output($response);
    }

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

        try {

            DB::beginTransaction();

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

            $roomRateChannelMappingRequest= [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']]
                ],
                'whereIn' => [
                    ['field' => 'channel_id', 'value' => $params['channels']]
                ],
            ];

            $roomRateChannelMappingResponse = $this->propertyRoomRateChannelMappingRepository->findByCriteria($roomRateChannelMappingRequest) ;
            $roomRateChannelMappings = $roomRateChannelMappingResponse ? $roomRateChannelMappingResponse : [] ;

            $rateChannel = [] ;
            foreach ($roomRateChannelMappings as $roomRateChannelMapping) {
                $rateChannel[$roomRateChannelMapping['room_rate_mapping_id'].'|'.$roomRateChannelMapping['channel_id']] =[
                    "id" => $roomRateChannelMapping['id'],
                    "property_id" => $roomRateChannelMapping['property_id'],
                    "channel_id" => $roomRateChannelMapping['channel_id'],
                    "room_rate_mapping_id" => $roomRateChannelMapping['room_rate_mapping_id'],
                ];
            }

            $propertyChannelMappingRequest= [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']]
                ],
                'whereIn' => [
                    ['field' => 'channel_id', 'value' => $params['channels']]
                ],
            ];

            $propertyChannelMappingResponse = $this->propertyChannelMappingRepository->findByCriteria($propertyChannelMappingRequest) ;
            $propertyChannelMappings = $propertyChannelMappingResponse ? $propertyChannelMappingResponse : [] ;



            $propertyChannel = [] ;
            foreach ($propertyChannelMappings as $propertyChannelMapping) {
                $propertyChannel[$propertyChannelMapping['channel_id']] =[
                    "id" => $propertyChannelMapping['id'],
                    "property_id" => $propertyChannelMapping['property_id'],
                    "channel_id" => $propertyChannelMapping['channel_id'],
                ];
            }


            $roomRateMappings = fillOnUndefined($params, 'room_rate_mapping', []) ;
            $channels = fillOnUndefined($params, 'channels', []) ;
            $storeData = [] ;
            foreach ( $roomRateMappings as $roomRateMapping) {
                foreach ($channels as $channel) {
                    $checkChannelKey = $roomRateMapping['room_rate_mapping_id'].'|'.$channel ;
                    if(isset($rateChannel[$checkChannelKey])) {
                        if (isset($propertyChannel[$channel])) {
                            $storeData[] = [
                                'property_id' => $params['property_id'],
                                'channel_id' => $channel,
                                'channel_mapping_id' => $propertyChannel[$channel]['id'],
                                'room_rate_mapping_id' => $roomRateMapping['room_rate_mapping_id'],
                                'action_type' => $roomRateMapping['action_type'],
                                'value_type' => $roomRateMapping['value_type'],
                                'value' => $roomRateMapping['value'],
                                'status' => 1,
                                'created_by' => fillOnUndefined($params, "user_id"),
                                'updated_by' => fillOnUndefined($params, "user_id"),
                                'created_at' => time(),
                                'updated_at' => time(),
                            ];
                        }
                    }
                }
            }

            $roomRates = collect($params['room_rate_mapping'])->keyBy('room_rate_mapping_id')->keys()->toArray();
            $params['delete_room_rates'] = $roomRates;
            $nonrefundableDeleteStatus = $this->deleteChannelsWithRatesNonrefundableData($params) ;
            if($nonrefundableDeleteStatus['status'] != "success"){
                throw new ApiErrorException($nonrefundableDeleteStatus['message']);
            }

            $addNonrefundableStatus = $this->propertyNonrefundableRepository->insert($storeData);
            if($addNonrefundableStatus['status'] != "success"){
                throw new Exception('api-unknown_error');
            }

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

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

        return output($response);
    }

    public function deleteChannelsWithRatesNonrefundableData($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {
            $nonrefundableRequest= [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']]
                ],
                'whereIn' => [
                    ['field' => 'channel_id', 'value' => $params['channels']]
                ],
            ];

            $nonrefundableResponse = $this->propertyNonrefundableRepository->findByCriteria($nonrefundableRequest) ;
            $nonrefundableData = $nonrefundableResponse ? $nonrefundableResponse : [] ;
            $roomRates = $params['delete_room_rates'];
            $deleteNonrefundableData = collect($nonrefundableData)->whereIn('room_rate_mapping_id', $roomRates)->values();
            $deleteIds = $deleteNonrefundableData->keyBy('id')->keys()->toArray();
            if($deleteIds){
                $nonrefundableDeleteStatus = $this->propertyNonrefundableRepository->destroy($deleteIds) ;
                if($nonrefundableDeleteStatus['status'] != "success"){
                    throw new Exception('api-unknown_error');
                }
            }

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

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

        return output($response);
    }

    public function getNonrefundableData($params = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {
            $nonrefundableRequest= [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']]
                ],
                'whereIn' => [
                    ['field' => 'channel_id', 'value' => $params['channels']]
                ],
                'with' => ['propertyChannel', 'propertyRoomRateMapping.propertyRoomRate', 'propertyRoomRateMapping.propertyRoom']
            ];
            $nonrefundableResponse = $this->propertyNonrefundableRepository->findByCriteria($nonrefundableRequest, ['id', 'property_id', 'channel_id', 'channel_mapping_id', 'room_rate_mapping_id', 'action_type', 'value_type', 'value']) ;
            $nonrefundableData = $nonrefundableResponse ? $nonrefundableResponse : [] ;
            $nonrefundableCollection = collect($nonrefundableData) ;

            $channelList = $nonrefundableCollection->unique('channel_id')->map(function ($value){
                return $value['property_channel'];
            })->sortBy('name')->values()->toArray();

            $responseData = [] ;
            foreach ($channelList as $channel) {
                $channelData = $nonrefundableCollection->where('channel_id', '=', $channel['id'])->values()->toArray();
                $channelItem = $channel ;
                $responseChannelData = [] ;
                foreach ($channelData as $data) {
                    $dataItem = $data ;
                    $dataItem['name'] = $data['property_room_rate_mapping']['property_room']['name'] . ' - ' . $data['property_room_rate_mapping']['property_room_rate']['name'];
                    $dataItem['room_name'] = $data['property_room_rate_mapping']['property_room']['name'];
                    $dataItem['rate_name'] = $data['property_room_rate_mapping']['property_room_rate']['name'];
                    unset($dataItem['property_room_rate_mapping']);
                    unset($dataItem['property_channel']);
                    $responseChannelData[] = $dataItem;
                }
                $responseChannelData = collect($responseChannelData)->values()->toArray();

                array_multisort(
                    array_column($responseChannelData, 'room_name'), SORT_ASC,
                    array_column($responseChannelData, 'rate_name'), SORT_ASC,
                    $responseChannelData
                );

                $channelItem['nonrefundable_data'] = $responseChannelData;
                $responseData[] = $channelItem ;
            }



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

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

        return output($response);
    }

}
