<?php


namespace App\Core\Service\ChannelManager;


use App\Core\Mail\LogMail;
use App\Core\Service\BookingService;
use App\Core\Service\ChannelManagerMappingService;
use App\Core\Service\ChannelManagerPropertyMappingService;
use App\Core\Service\PropertyChannelMappingService;
use App\Core\Service\PropertyChannelService;
use App\Core\Service\PropertyRoomRateChannelMappingService;
use App\Exceptions\ApiErrorException;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Mail\Mailer;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use Exception;


class HyperGuest
{

    private $statusMapping;
    private $paymentTypeMapping;
    private $channelManagerId;
    private $channelManagerName;
    private $mailer;

    public function __construct(
        Client $restClient,
        Mailer $mailer,
        BookingService $bookingService,
        ChannelManagerPropertyMappingService $channelManagerPropertyMappingService,
        ChannelManagerMappingService $channelManagerMappingService,
        PropertyChannelService $propertyChannelService,
        PropertyChannelMappingService $propertyChannelMappingService,
        PropertyRoomRateChannelMappingService $propertyRoomRateChannelMappingService
    )
    {
        $this->restClient = $restClient;
        $this->mailer = $mailer;
        $this->reservationPushUrl = 'https://book-api.hyperguest.com';
        $this->bearerToken = '63d51938dc3749788ac3e88ea6d58950';

        $this->channelManagerId = 10;
        $this->channelManagerName = 'HyperGuest';
        $this->bookingService = $bookingService;
        $this->channelManagerPropertyMappingService = $channelManagerPropertyMappingService;
        $this->channelManagerMappingService = $channelManagerMappingService;
        $this->propertyChannelService = $propertyChannelService;
        $this->propertyChannelMappingService = $propertyChannelMappingService;
        $this->propertyRoomRateChannelMappingService = $propertyRoomRateChannelMappingService;

        $this->paymentTypeMapping = [
            'CRD' => 'bank_transfer',
            'HTL' => 'external'
        ];

    }

    public function requestPost($method, $xmlPayload)
    {
        $response = ['status' => false, 'message' => ''];

        try {

            $this->restClient = new Client(['http_errors' => false]);

            $parameter = [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Authorization' => 'Bearer ' . $this->bearerToken
                ]
            ];

            if (!empty($jsonPayload)) {
                $parameter['body'] = $jsonPayload;
            }

            $request = $this->restClient->request('POST', $this->url . $method, $parameter);

            $getResponseBody = $request->getBody();
            $getResponse = $getResponseBody->getContents();
            $getResponse = json_decode($getResponse, 1);

            if ($request->getStatusCode() != 200) {
                $errors = singleElementArray($getResponse['errors']);
                $firstError = reset($errors);
                throw new ApiErrorException($firstError['code'] . ': ' . $firstError['title']);
            }

            $response = ["status" => true, 'message' => '', "data" => fillOnUndefined($getResponse, '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 $response;

    }

    public function requestPostReservationPushParam($propertyId, $bookingId, $type, $param = [])
    {

        $jsonResponse = null;

        try {

            $bookingDetail = $param['booking_detail'];

            $requestParam = [
                'criteria' =>
                    [
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                        ['field' => 'channel_manager_id', 'condition' => '=', 'value' => $this->channelManagerId],
                    ],
                'with' => ['channelManagerRoomRate.propertyRoomRateMapping'],
                'firstRow' => true
            ];

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

            if ($channelManagerPropertyMapping['status'] != 'success' || empty($channelManagerPropertyMapping['data'])) {
                throw new ApiErrorException('Property Room Rate not found');
            }

            $channelManagerPropertyMapping = $channelManagerPropertyMapping['data'];


            $jsonResponse = [];
            $jsonResponse['dates']['from'] = $bookingDetail['checkin_date'];
            $jsonResponse['dates']['to'] = $bookingDetail['checkout_date'];

            $jsonResponse['propertyId'] = $channelManagerPropertyMapping['channel_manager_property_id'];


            //$jsonResponse['reservation']['code'] = $bookingDetail['booking_code'];
            //$jsonResponse['reservation']['status'] = $type;

            //$jsonResponse['reservation']['time'] = Carbon::createFromTimestamp($param['booking_detail']['created_at'])->toDateTimeString();

            $jsonResponse['leadGuest']['birthDate'] = '1980-01-01';


            $jsonResponse['leadGuest']['contact']['address'] = 'N/A';
            $jsonResponse['leadGuest']['contact']['city'] = 'N/A';
            $jsonResponse['leadGuest']['contact']['country'] = !empty($bookingDetail['booking_contact']['country_code']) ? $bookingDetail['booking_contact']['country_code'] : 'TR';
            $jsonResponse['leadGuest']['contact']['email'] = $bookingDetail['booking_contact']['email'];
            $jsonResponse['leadGuest']['contact']['phone'] = $bookingDetail['booking_contact']['phoneFormatted'];
            $jsonResponse['leadGuest']['contact']['state'] = 'N/A';
            $jsonResponse['leadGuest']['contact']['zip'] = 'N/A';

            $jsonResponse['leadGuest']['name']['first'] = $bookingDetail['booking_contact']['name'];
            $jsonResponse['leadGuest']['name']['last'] = $bookingDetail['booking_contact']['surname'];

            $jsonResponse['leadGuest']['title'] = 'Mr';

            $jsonResponse['reference']['agency'] = $bookingDetail['booking_code'];//'Extranetwork';


            $jsonResponse['paymentDetails']['type'] = isset($this->paymentTypeMapping[$bookingDetail['payment_type_code']]) ? $this->paymentTypeMapping[$bookingDetail['payment_type_code']] : $this->paymentTypeMapping['HTL'];
            //$jsonResponse['paymentDetails']['details']['number'] = null;
            //$jsonResponse['paymentDetails']['details']['cvv'] = null;
            //$jsonResponse['paymentDetails']['details']['expiry']['month'] = null;
            //$jsonResponse['paymentDetails']['details']['name']['first'] = null;
            //$jsonResponse['paymentDetails']['details']['name']['last'] = null;


            $jsonResponse['rooms'] = [];


            $roomKey = 0;
            foreach ($bookingDetail['booking_room'] as $roomKey => $roomDetail) {

                /*$occupancy = occupancyCodeParser($roomDetail['occupancy_code']);
                $diffInDays = Carbon::parse($roomDetail['checkin_date'])->diffInDays(Carbon::parse($roomDetail['checkout_date']));
                */

                $roomPax = [];
                foreach ($roomDetail['room_pax'] as $pax) {
                    $roomPax[] = [
                        'birthDate' => $pax['birth_date'],
                        /*'contact' => [
                            'address' => null,
                            'city' => null,
                            'country' => $pax['citizen'],
                            'email' => null,
                            'phone' => null,
                            'state' => null,
                            'zip' => null,
                        ],*/
                        'name' => [
                            'first' => $pax['name'],
                            'last' => $pax['surname'],
                        ],
                        //'title' => null
                    ];
                }

                $channelRoom = collect($channelManagerPropertyMapping['channel_manager_room_rate'])->where('property_room_rate_mapping.room_id', $roomDetail['room_id'])->first();
                $channelRoomRate = collect($channelManagerPropertyMapping['channel_manager_room_rate'])->where('property_room_rate_mapping_id', $roomDetail['room_rate_mapping_id'])->first();

                $jsonResponse['rooms'][$roomKey] = [
                    'roomCode' => $channelRoom['channel_manager_room_id'],
                    'rateCode' => $channelRoomRate['channel_manager_room_rate_id'],
                    'expectedPrice' => [
                        'amount' => $roomDetail['total'],
                        'currency' => $roomDetail['currency_code'],
                    ],
                    'guests' => $roomPax,
                    'specialRequests' => [
                        $roomDetail['room_name'], $roomDetail['room_rate_name'],
                    ]

                ];

            }


            $metaNotes = [];

            $metaNotes[] = [
                'key' => 'Source',
                'value' => 'Extranetwork',
            ];

            $metaNotes[] = [
                'key' => 'BookingId',
                'value' => $bookingDetail['id'],
            ];

            $metaNotes[] = [
                'key' => 'BookingCode',
                'value' => $bookingDetail['booking_code'],
            ];

            $metaNotes[] = [
                'key' => 'ChannelBookingCode',
                'value' => !empty($bookingDetail['channel_booking_code']) ? $bookingDetail['channel_booking_code'] : false,
            ];

            $metaNotes[] = [
                'key' => 'Channel',
                'value' => $bookingDetail['booking_channel']['name'],
            ];

            $metaNotes[] = [
                'key' => 'Payment',
                'value' => $bookingDetail['booking_payment_type']['code'] . ': ' . $bookingDetail['booking_payment_type']['name'],
            ];

            $metaNotes[] = [
                'key' => 'Status',
                'value' => $bookingDetail['booking_status']['name'],
            ];

            if (!empty($bookingDetail['booking_contact']['note'])) {
                $metaNotes[] = [
                    'key' => 'Note',
                    'value' => $bookingDetail['booking_contact']['note'],
                ];
            }

            $jsonResponse['meta'] = $metaNotes;
            $jsonResponse['isTest'] = (App::environment() == 'production') ? false : true;
            $jsonResponse['groupBooking'] = false;

            return json_encode($jsonResponse);


        } catch (ApiErrorException | Exception $e) {

            $jsonResponse = null;

            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
        }


        return $jsonResponse;

    }

    public function requestPostReservationPush($jsonPayload)
    {
        $response = ['status' => false, 'message' => ''];


        $jsonPayloadArray = json_decode($jsonPayload, 1);
        $status = collect($jsonPayloadArray['meta'])->where('key', 'Status')->pluck('value')->first();
        $bookingId = collect($jsonPayloadArray['meta'])->where('key', 'BookingId')->pluck('value')->first();
        $bookingCode = collect($jsonPayloadArray['meta'])->where('key', 'BookingCode')->pluck('value')->first();
        $channelBookingCode = collect($jsonPayloadArray['meta'])->where('key', 'ChannelBookingCode')->pluck('value')->first();

        if ($status == 'Booking') {
            $method = '/2.0/booking/create';
        } elseif ($status == 'Cancel/Refund') {
            $method = '/2.0/booking/cancel';
        }

        if ($status == 'Cancel/Refund') {
            $jsonResponse = [
                'bookingId' => $channelBookingCode,
                'reason' => 'N/A',
                'simulation' => false,
            ];
            $jsonPayload = json_encode($jsonResponse);
        }

        try {

            $this->restClient = new Client(['http_errors' => false]);

            $parameter = [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Authorization' => 'Bearer ' . $this->bearerToken
                ]
            ];


            //$jsonPayload = '{"dates":{"from":"2024-08-30","to":"2024-08-31"},"propertyId":"90365","leadGuest":{"birthDate":"1980-01-01","contact":{"address":false,"city":false,"country":"TR","email":"cem@test.com","phone":"+4932121321","state":false,"zip":false},"name":{"first":"cem","last":"test"},"title":"Mr"},"reference":{"agency":"BKG240730-5VI02ISW"},"paymentDetails":{"type":"external"},"rooms":[{"roomCode":"DBL","rateCode":"BB","expectedPrice":{"amount":200.75,"currency":"EUR"},"guests":[{"birthDate":"1988-07-20","name":{"first":"dsada","last":"sadsa"}},{"birthDate":"1988-07-24","name":{"first":"sad","last":"sadfds"}}],"specialRequests":["Standart Room With Sea View","Bed and Breakfast"]}],"meta":[{"key":"Source","value":"Extranetwork"},{"key":"BookingId","value":46502},{"key":"BookingCode","value":"BKG240730-5VI02ISW"},{"key":"ChannelBookingCode","value":false},{"key":"Channel","value":"Web Booking Engine"},{"key":"Payment","value":"HTL: Pay at Hotel"},{"key":"Status","value":"Booking"},{"key":"Note","value":"asdasd"}],"isTest":true,"groupBooking":false}';

            if (!empty($jsonPayload)) {
                $parameter['body'] = $jsonPayload;
            }


            $request = $this->restClient->request('POST', $this->reservationPushUrl . $method, $parameter);

            $getResponseBody = $request->getBody();
            $getResponse = $getResponseBody->getContents();
            $getResponse = json_decode($getResponse, 1);

            //dd(json_encode($getResponse));

            //Log::debug($method);
            //Log::debug($parameter);
            //Log::debug(json_encode($getResponse));
            //Log::debug($request->getStatusCode());

            if ($request->getStatusCode() != 200) {

                if (isset($getResponse['error'])) {
                    if (is_array($getResponse['errorDetails']) && !empty($getResponse['errorDetails'])) {
                        $errors = $getResponse['errorDetails'];
                        $firstError = reset($errors);
                        throw new ApiErrorException($firstError['message']);
                    } elseif (!empty($getResponse['errorDetails'])) {
                        throw new ApiErrorException($getResponse['errorDetails']);
                    } else {
                        throw new ApiErrorException($getResponse['error']);
                    }

                } else {
                    $errors = singleElementArray($getResponse);
                    $firstError = reset($errors);
                    throw new ApiErrorException($firstError['errorCode'] . ': ' . $firstError['errorDetails']);
                }

            }

            if ($status == 'Booking') {
                $channelBookingCodeUpdate = $this->bookingService->update($bookingId, ['channel_booking_code' => $getResponse['content']['bookingId']]);
            }


            $response = ['status' => true, 'message' => '', 'response' => json_encode($getResponse)];

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

    }

    public function reservationListParam($propertyId)
    {

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

        return $response;
    }

    public function reservationList($propertyId)
    {

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

        return $response;
    }

    public function roomAvailabilityPush($propertyId)
    {

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

        return $response;
    }

}
