<?php

namespace App\Console\Commands\ChannelManager;

use App\Core\Mail\LogMail;
use App\Core\Service\ChannelManager\Reseliva;
use App\Core\Service\ChannelManagerLogService;
use App\Core\Service\ChannelManagerPropertyMappingService;
use App\Core\Service\ChannelManagerService;
use App\Core\Service\PropertyChannelMappingService;
use App\Core\Service\PropertyRoomAvailabilityQueueService;
use App\Core\Service\PropertyRoomAvailabilityService;
use App\Core\Service\PropertyRoomRateChannelMappingService;
use App\Core\Service\PropertyRoomRatePriceService;
use App\Core\Service\PropertyRoomService;
use App\Exceptions\ApiErrorException;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Console\Command;
use Illuminate\Mail\Mailer;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ReselivaAvailRateUpdateService extends Command
{
    protected $signature = 'cron:reseliva-availrateupdate-service';

    protected $description = '';
    protected $mailer;

    public function __construct(
        Mailer $mailer,
        PropertyRoomService $propertyRoomService,
        PropertyRoomRatePriceService $propertyRoomRatePriceService,
        ChannelManagerLogService $channelManagerLogService,
        ChannelManagerPropertyMappingService $channelManagerPropertyMappingService,
        PropertyRoomRateChannelMappingService $propertyRoomRateChannelMappingService,
        PropertyChannelMappingService $propertyChannelMappingService,
        PropertyRoomAvailabilityService $propertyRoomAvailabilityService
    )
    {
        parent::__construct();
        $this->mailer = $mailer;
        $this->propertyRoomService = $propertyRoomService;
        $this->propertyRoomRatePriceService = $propertyRoomRatePriceService;
        $this->channelManagerLogService = $channelManagerLogService;
        $this->channelManagerPropertyMappingService = $channelManagerPropertyMappingService;
        $this->propertyRoomRateChannelMappingService = $propertyRoomRateChannelMappingService;
        $this->propertyChannelMappingService = $propertyChannelMappingService;
        $this->propertyRoomAvailabilityService = $propertyRoomAvailabilityService;
    }

    public function propertyChannelMapping($propertyId, $channelId)
    {

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

        try {

            $propertyChannelMappingCriteria = [
                'criteria' => [
                    ['field' => 'channel_id', 'condition' => '=', 'value' => $channelId],
                    ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                ],
                'firstRow' => true
            ];


            $propertyChannelMapping = $this->propertyChannelMappingService->select($propertyChannelMappingCriteria);

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

            $response = [
                'status' => true,
                'data' => $propertyChannelMapping['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 channelPropertyRoomRate($propertyId, $channelId)
    {

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

        try {

            $requestParam = [
                'criteria' => [
                    ['field' => 'channel_id', 'condition' => '=', 'value' => $channelId],
                    ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                ],
                'with' => [
                    'propertyRoomRateMapping.propertyRoomRate.propertyRoomRateAccommodation',
                    'propertyRoomRateMapping.propertyRoom.propertyRoomType',
                ]
            ];

            $getChannelPropertyRoomRate = $this->propertyRoomRateChannelMappingService->select($requestParam);

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

            $response = [
                'status' => true,
                'data' => $getChannelPropertyRoomRate['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 channelManagerPropertyCheck($propertyId, $channelId)
    {

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

        try {

            $requestParam =
                [
                    'criteria' =>
                        [
                            ['field' => 'status', 'condition' => '=', 'value' => 1],
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                            ['field' => 'channel_manager_id', 'condition' => '=', 'value' => $channelId],
                        ],
                    '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'];

            if (!is_null($channelManagerPropertyMapping['channel_manager_property_id'])) {
                throw new ApiErrorException('This hotel can only be updated by ENW');
            }

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

    }

    public function handle()
    {

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

        $channelId = 1;
        $channelManagerId = 1;

        $channelManagerLogCriteria = [
            'criteria' => [
                ['field' => 'id', 'condition' => '=', 'value' => 32670],
                ['field' => 'service', 'condition' => '=', 'value' => 'AvailRateUpdate'],
                ['field' => 'status', 'condition' => '=', 'value' => null],
            ],
            'orderBy' => [
                ['field' => 'id', 'value' => 'ASC']
            ]
        ];

        $channelManagerLog = $this->channelManagerLogService->select($channelManagerLogCriteria);

        if ($channelManagerLog['status'] && !empty($channelManagerLog['data'])) {

            foreach ($channelManagerLog['data'] as $logData) {

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

                $payloadXML = simplexml_load_string($logData['request']);
                $payloadParam = json_decode(json_encode($payloadXML), 1);

                try {

                    $propertyId = $payloadParam['Hotel']['@attributes']['id'];


                    $channelManagerPropertyCheck = $this->channelManagerPropertyCheck($propertyId, $channelId);
                    if (!$channelManagerPropertyCheck['status']) {
                        throw new ApiErrorException($channelManagerPropertyCheck['message']);
                    }

                    $channelPropertyRoomRate = $this->channelPropertyRoomRate($propertyId, $channelId);
                    if (!$channelPropertyRoomRate['status']) {
                        throw new ApiErrorException($channelPropertyRoomRate['message']);
                    }

                    $channelPropertyRoomRate = $channelPropertyRoomRate['data'];
                    $channelPropertyRoomRateCollect = collect($channelPropertyRoomRate);


                    $propertyChannelMapping = $this->propertyChannelMapping($propertyId, $channelId);
                    if (!$propertyChannelMapping['status']) {
                        throw new ApiErrorException($propertyChannelMapping['message']);
                    }

                    $propertyChannelMapping = $propertyChannelMapping['data'];


                    $availRateUpdates = singleElementXMLArray($payloadParam['AvailRateUpdate']);

                    DB::beginTransaction();

                    foreach ($availRateUpdates as $availRateUpdate) {

                        $dateRange = [];
                        $dateRange['startDate'] = $availRateUpdate['DateRange']['@attributes']['from'];
                        $dateRange['finishDate'] = $availRateUpdate['DateRange']['@attributes']['to'];

                        if (Carbon::parse($dateRange['startDate'])->isBefore(Carbon::now()->toDateString()) || Carbon::parse($dateRange['finishDate'])->isBefore(Carbon::now()->toDateString())) {
                            throw new ApiErrorException('Dates to be updated cannot be earlier than today');
                        }

                        $roomTypes = singleElementXMLArray($availRateUpdate['RoomType']);

                        $this->info(date('Y-m-d H:i:s') . ' : ' . $dateRange['startDate'] . ' - ' . $dateRange['finishDate']);

                        foreach ($roomTypes as $roomType) {

                            $roomId = $roomType['@attributes']['id'];

                            $roomCheck = $channelPropertyRoomRateCollect->where('property_room_rate_mapping.room_id', $roomId)->isEmpty();
                            if ($roomCheck) {
                                throw new ApiErrorException('Tanımlı ya da aktif olmayan oda');
                            }


                            $totalInventoryAvailable = null;
                            if (isset($roomType['Inventory']['@attributes']['totalInventoryAvailable'])) {
                                $totalInventoryAvailable = $roomType['Inventory']['@attributes']['totalInventoryAvailable'];
                            }


                            $requestParamBase = [
                                'property_id' => fillOnUndefined($propertyChannelMapping, 'property_id'),
                                'channel_id' => fillOnUndefined($propertyChannelMapping, 'channel_id'),
                                'availability_type_id' => fillOnUndefined($propertyChannelMapping, 'property_availability_type_id', 1),
                                'start_date' => $dateRange['startDate'],
                                'end_date' => $dateRange['finishDate'],
                                'include_days' => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
                            ];

                            if (!is_null($totalInventoryAvailable)) {

                                $requestParams = [];
                                $requestParams = $requestParamBase;
                                $requestParams['update_type'] = 'availability';
                                $requestParams['value'] = $totalInventoryAvailable;
                                $requestParams['room_rates'] = [
                                    ['room_id' => $roomId]
                                ];

                                $propertyRoomRateMapping = $this->propertyRoomAvailabilityService->bulkUpdate($requestParams);

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

                                $this->info(date('Y-m-d H:i:s') . ' : Update Type: ' . $requestParams['update_type']);
                            }


                            if (isset($roomType['RatePlan'])) {

                                $ratePlans = singleElementXMLArray($roomType['RatePlan']);

                                foreach ($ratePlans as $ratePlan) {

                                    $roomRateMappingId = $ratePlan['@attributes']['id'];

                                    $isCloseRoomRateMappingSale = null;
                                    if (isset($ratePlan['@attributes']['closed'])) {
                                        $isCloseRoomRateMappingSale = $ratePlan['@attributes']['closed'] == 'true' ? true : false;
                                    }

                                    $channelRoomRateMappingCheck = $channelPropertyRoomRateCollect->where('room_rate_mapping_id', $roomRateMappingId)->isEmpty();
                                    if ($channelRoomRateMappingCheck) {
                                        throw new ApiErrorException('Tanımlı ya da aktif olmayan oda konaklama');
                                    }


                                    $roomRates = [
                                        'room_id' => $roomId,
                                        'room_rate_mapping_id' => [
                                            $roomRateMappingId
                                        ]
                                    ];


                                    $paramsListChannel = [];
                                    $paramsListChannel[] = 1;
                                    //CONNECTED CHANNEL RATE UPDATE
                                    $propertyChannelMappingConnectedCriteria = [
                                        'criteria' => [
                                            ['field' => 'property_id', 'condition' => '=', 'value' => $requestParamBase['property_id']],
                                            ['field' => 'connected_channel_id', 'condition' => '=', 'value' => $requestParamBase['channel_id']],
                                            ['field' => 'status', 'condition' => '=', 'value' => 1],
                                        ],
                                        'with' => ['channel']
                                    ];

                                    $propertyChannelMappingConnected = $this->propertyChannelMappingService->select($propertyChannelMappingConnectedCriteria);
                                    if ($propertyChannelMappingConnected['status'] == 'success') {

                                        foreach ($propertyChannelMappingConnected['data'] as $channel) {

                                            if (!is_null($channel['channel']['parent_id'])) {
                                                continue;
                                            }

                                            $paramsListChannel[] = $channel['channel_id'];

                                        }

                                    }
                                    //CONNECTED CHANNEL RATE UPDATE


                                    foreach ($paramsListChannel as $paramChannelId) {


                                        //Eğer Rate var ise currency check yapılmalı ve PerDay var mı check edilmeli, burada sonra günceleme yaptırılabilri
                                        if (isset($ratePlan['Rate'])) {

                                            $currency = $ratePlan['Rate']['@attributes']['currency'];

                                            $currencyCheck = ($currency == $propertyChannelMapping['currency_code']) ? true : false;

                                            if (!$currencyCheck) {
                                                throw new ApiErrorException('Kanal döviz kuru ile eşleşmeyen döviz kuru, kanal döviz kuru: ' . $propertyChannelMapping['currency_code']);
                                            }

                                            $channelRoomRateMapping = $channelPropertyRoomRateCollect->where('room_rate_mapping_id', $roomRateMappingId)->first();

                                            $amountPerDay = $ratePlan['Rate']['PerDay']['@attributes']['rate'];

                                            $requestParams = [];
                                            $requestParams = $requestParamBase;
                                            $requestParams['update_type'] = 'rate';
                                            $requestParams['value'] = $amountPerDay;
                                            $requestParams['room_rates'] = [$roomRates];

                                            $requestParams['channel_id'] = $paramChannelId;

                                            $propertyRoomRateMapping = $this->propertyRoomRatePriceService->bulkUpdate($requestParams);

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

                                            $this->info(date('Y-m-d H:i:s') .
                                                ' : Update Type: ' .$requestParams['update_type'].
                                                ' : Channel ID: '. $requestParams['channel_id'].
                                                ' : Room ID: '. $roomRates['room_id']
                                            );
                                        }


                                        //Room Rate Stop Sale
                                        if (!is_null($isCloseRoomRateMappingSale)) {
                                            $requestParams = [];
                                            $requestParams = $requestParamBase;
                                            $requestParams['update_type'] = 'rate_stop_sell';
                                            $requestParams['value'] = $isCloseRoomRateMappingSale ? 1 : 0;
                                            $requestParams['room_rates'] = [$roomRates];

                                            $requestParams['channel_id'] = $paramChannelId;

                                            $propertyRoomRateMapping = $this->propertyRoomRatePriceService->bulkUpdate($requestParams);

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

                                            $this->info(date('Y-m-d H:i:s') . ' : Update Type: ' . $requestParams['update_type']);
                                        }


                                        //Kısıtlamalar var ise min los
                                        if (isset($ratePlan['Restrictions'])) {

                                            //Minimum Konaklama Gün Sayısı
                                            if (isset($ratePlan['Restrictions']['@attributes']['minLOS'])) {

                                                $minStay = $ratePlan['Restrictions']['@attributes']['minLOS'];

                                                $requestParams = [];
                                                $requestParams = $requestParamBase;
                                                $requestParams['update_type'] = 'min_stay';
                                                $requestParams['value'] = $minStay;
                                                $requestParams['room_rates'] = [$roomRates];

                                                $requestParams['channel_id'] = $paramChannelId;

                                                $propertyRoomRateMapping = $this->propertyRoomRatePriceService->bulkUpdate($requestParams);

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

                                                $this->info(date('Y-m-d H:i:s') . ' : Update Type: ' . $requestParams['update_type']);

                                            }

                                        }

                                    }


                                }

                            }


                        }

                    }

                    $response['status'] = true;

                    $updateDataLog = [
                        'response' => json_encode($response),
                        'status' => 1
                    ];


                    $channelManagerLog = $this->channelManagerLogService->update($logData['id'], $updateDataLog);

                    DB::commit();

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

                //TODO: mail
                if (!$response['status']) {
                    DB::rollBack();
                }

            }

        }


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


    }
}
