<?php

namespace App\Console\Commands\ChannelManager;

use App\Core\Mail\LogMail;
use App\Core\Service\ChannelManager\Reseliva;
use App\Core\Service\ChannelManagerBookingService;
use App\Exceptions\ApiErrorException;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Console\Command;
use Illuminate\Mail\Mailer;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;

class ReservationPushService extends Command
{
    protected $signature = 'cron:reservation-push-service';

    protected $description = '';
    protected $channelService;
    protected $channelManagerBookingService;
    protected $typeMapping;

    public function __construct(
        Mailer $mailer,
        Reseliva $channelService,
        ChannelManagerBookingService $channelManagerBookingService
    )
    {
        parent::__construct();
        $this->mailer = $mailer;
        $this->channelService = $channelService;
        $this->channelManagerBookingService = $channelManagerBookingService;

        $this->typeMapping = [
            'Booking' => 'Book',
            'Modify' => 'Modify',
            'Cancel' => 'Cancel'
        ];

    }

    public function handle()
    {

        try {

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

            $pendingBookingCriteria = [
                'criteria' =>
                    [
                        ['field' => 'channel_manager_id', 'condition' => '=', 'value' => 1],
                        ['field' => 'is_pushed', 'condition' => '=', 'value' => null],
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ],
                'with' => ['bookingDetail.bookingContact', 'bookingDetail.bookingChannel', 'bookingDetail.bookingPayment', 'bookingDetail.bookingPaymentType', 'bookingDetail.bookingStatus', 'bookingDetail.bookingRoom.roomPax.paxCountry'],
                'orderBy' => [
                    ['field' => 'id', 'value' => 'ASC']
                ],
                'take' => 100
            ];

            $pendingBooking = $this->channelManagerBookingService->select($pendingBookingCriteria);

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

                $pendingBooking = $pendingBooking['data'];

                foreach ($pendingBooking as $booking) {


                    $bookingDetail = $booking['booking_detail'];

                    $type = $this->typeMapping[$booking['type']];

                    $serviceRequestName = 'BookingRetrieval';
                    $xmlResponse = new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><' . $serviceRequestName . 'RS></' . $serviceRequestName . 'RS>');

                    if (in_array($bookingDetail['status'], [0, 3])) {

                        $Bookings = $xmlResponse->addChild('Bookings');
                        $Booking = $Bookings->addChild('Booking');

                        if(Carbon::createFromTimestamp($booking['booking_detail']['created_at'])->lessThan(Carbon::parse('2022-04-01'))) {
                            $Booking->addAttribute('id', $bookingDetail['id']);
                        } else {
                            $Booking->addAttribute('id', $bookingDetail['booking_code']);
                        }

                        $Booking->addAttribute('type', 'Cancel');
                        $Booking->addAttribute('cancelDateTime', Carbon::createFromTimestamp($bookingDetail['updated_at'])->toISOString());

                        $Hotel = $Booking->addChild('Hotel');
                        $Hotel->addAttribute('id', $bookingDetail['property_id']);

                        foreach ($bookingDetail['booking_room'] as $room) {

                            $RoomStay = $Booking->addChild('RoomStay');
                            $RoomStay->addAttribute('roomTypeID', $room['room_id']);
                            $RoomStay->addAttribute('ratePlanID', $room['room_rate_mapping_id']);

                            $StayDate = $RoomStay->addChild('StayDate');
                            $StayDate->addAttribute('arrival', $room['checkin_date']);
                            $StayDate->addAttribute('departure', $room['checkout_date']);

                        }

                    } else {


                        $Bookings = $xmlResponse->addChild('Bookings');
                        $Booking = $Bookings->addChild('Booking');

                        if(Carbon::createFromTimestamp($booking['booking_detail']['created_at'])->lessThan(Carbon::parse('2022-04-01'))) {
                            $Booking->addAttribute('id', $bookingDetail['id']);
                        } else {
                            $Booking->addAttribute('id', $bookingDetail['booking_code']);
                        }

                        //Book ve Modify Aynı olacak, Cancel
                        if ($type == 'Book') {
                            $Booking->addAttribute('type', 'Book');
                            $Booking->addAttribute('createDateTime', Carbon::createFromTimestamp($bookingDetail['created_at'])->toISOString());
                        }

                        if ($type == 'Modify') {
                            $Booking->addAttribute('type', 'Modify');
                            $Booking->addAttribute('modifyDateTime', Carbon::createFromTimestamp($bookingDetail['updated_at'])->toISOString());
                        }

                        $Hotel = $Booking->addChild('Hotel');
                        $Hotel->addAttribute('id', $bookingDetail['property_id']);


                        foreach ($bookingDetail['booking_room'] as $room) {

                            $RoomStay = $Booking->addChild('RoomStay');
                            $RoomStay->addAttribute('roomTypeID', $room['room_id']);
                            $RoomStay->addAttribute('ratePlanID', $room['room_rate_mapping_id']);

                            $StayDate = $RoomStay->addChild('StayDate');
                            $StayDate->addAttribute('arrival', $room['checkin_date']);
                            $StayDate->addAttribute('departure', $room['checkout_date']);


                            $roomPaxCollect = collect($room['room_pax']);

                            $GuestCount = $RoomStay->addChild('GuestCount');
                            $GuestCount->addAttribute('adult', $roomPaxCollect->where('type', 'ADT')->count());

                            $diffInDays = Carbon::parse($room['checkin_date'])->diffInDays(Carbon::parse($room['checkout_date']));

                            //dd($room['total'], $diffInDays, $room);

                            $PerDayRates = $RoomStay->addChild('PerDayRates');
                            $PerDayRates->addAttribute('currency', $room['currency_code']);

                            $baseRateDaily = moneyDoubleFormatDecimal($room['total'] / $diffInDays);

                            $currentDate = $room['checkin_date'];
                            for ($i = 0; $i < $diffInDays; $i++) {
                                $PerDayRate = $PerDayRates->addChild('PerDayRate');
                                $PerDayRate->addAttribute('stayDate', $currentDate);
                                $PerDayRate->addAttribute('baseRate', $baseRateDaily);
                                $PerDayRate->addAttribute('hotelServiceFees', 0);

                                $currentDate = Carbon::parse($currentDate)->addDay()->toDateString();
                            }

                            $Total = $RoomStay->addChild('Total');
                            $Total->addAttribute('amountAfterTaxes', $room['total']);
                            $Total->addAttribute('amountOfTaxes', 0);
                            $Total->addAttribute('currency', $room['currency_code']);

                            $roomNotes['cancellationPolicy'] = 'Cancellation Policy: Refundable';
                            $cancellationPolicy = json_decode($room['cancellation_policy'],1);
                            if(!empty($cancellationPolicy) && is_array($cancellationPolicy)) {
                                if(isset($cancellationPolicy['isNonRefundable']) && $cancellationPolicy['isNonRefundable']) {
                                    $roomNotes['cancellationPolicy'] = 'Cancellation Policy: NonRefundable';
                                }
                            }

                            $roomNotes['payment'] = 'Payment: '.$bookingDetail['booking_payment_type']['name'];

                            $RoomStay->addChild('RoomNotes', implode('. ',$roomNotes));

                        }


                        $PrimaryGuest = $Booking->addChild('PrimaryGuest');

                        $Name = $PrimaryGuest->addChild('Name');
                        $Name->addAttribute('givenName', $bookingDetail['booking_contact']['name']);
                        $Name->addAttribute('surname', $bookingDetail['booking_contact']['surname']);

                        $Phone = $PrimaryGuest->addChild('Phone');
                        $Phone->addAttribute('countryCode', $bookingDetail['booking_contact']['phone_code']);
                        //$Phone->addAttribute('cityAreaCode');
                        $Phone->addAttribute('number', $bookingDetail['booking_contact']['phone_number']);

                        $PrimaryGuest->addChild('Email', $bookingDetail['booking_contact']['email']);


                        $Total = $Booking->addChild('Total');
                        $Total->addAttribute('amountAfterTaxes', $bookingDetail['total']);
                        $Total->addAttribute('amountOfTaxes', 0);
                        $Total->addAttribute('currency', $bookingDetail['currency_code']);


                        $Booking->addChild('SpecialRequest');
                        $Booking->addChild('BookingNotes', $bookingDetail['booking_contact']['note']);


                    }


                    $this->info(date('Y-m-d H:i:s') . ' : Booking Id: '. $booking['booking_id']. ' Push');


                    $xmlPayload = $xmlResponse->asXML();

                    $this->channelManagerBookingService->update($booking['id'], ['request' => $xmlPayload]);

                    $requestPostReservationPush = $this->channelService->requestPostReservationPush($xmlPayload);

                    $this->channelManagerBookingService->update($booking['id'], ['response' => $requestPostReservationPush['data']['xmlBase']]);


                    if ($requestPostReservationPush['status']) {

                        if($requestPostReservationPush['data']['Status'] == 'success') {
                            $this->info(date('Y-m-d H:i:s') . ' : Booking Id: '. $booking['booking_id']. ' Success');
                            $this->channelManagerBookingService->update($booking['id'], ['is_pushed' => 1]);
                        } else {

                            //$logMessage
                            $mailParams = [
                                'title' => 'ReservationPushService Error - requestPostReservationPush Error',
                                'logMessage' => '<pre>' . print_r(array_merge($booking, $requestPostReservationPush), true) . '</pre>'
                            ];

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

                        }


                    } else {

                        //$logMessage
                        $mailParams = [
                            'title' => 'ReservationPushService Error - requestPostReservationPush Error',
                            'logMessage' => '<pre>' . print_r(array_merge($booking, $requestPostReservationPush), true) . '</pre>'
                        ];

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

                        $this->info(date('Y-m-d H:i:s') . ' : Booking Id: '. $booking['booking_id']. ' Failed');
                    }

                }

            }


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

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

    }

}
