<?php

namespace App\Console\Commands\ChannelManager;

use App\Core\Mail\LogMail;
use App\Core\Service\ChannelManagerPropertyMappingService;
use App\Core\Service\PropertyBookingEngineService;
use App\Core\Service\PropertyChannelMappingService;
use App\Core\Service\PropertyRoomRateChannelMappingService;
use App\Core\Service\PropertyRoomRatePriceService;
use App\Exceptions\ApiErrorException;
use App\Http\Controllers\BookingEngine\V1\SearchController;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Console\Command;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
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 BestAvailableRateSyncService extends Command
{
    protected $signature = 'cron:bar-sync-service {--property_id=}';

    protected $description = '';
    protected $mailer;

    public function __construct(
        Mailer                                $mailer,
        ChannelManagerPropertyMappingService  $channelManagerPropertyMappingService,
        PropertyRoomRateChannelMappingService $propertyRoomRateChannelMappingService,
        PropertyBookingEngineService          $propertyBookingEngineService,
        PropertyRoomRatePriceService          $propertyRoomRatePriceService
    )
    {
        parent::__construct();
        $this->mailer = $mailer;
        $this->channelManagerPropertyMappingService = $channelManagerPropertyMappingService;
        $this->propertyRoomRateChannelMappingService = $propertyRoomRateChannelMappingService;
        $this->propertyBookingEngineService = $propertyBookingEngineService;
        $this->propertyRoomRatePriceService = $propertyRoomRatePriceService;
    }

    public function handle()
    {

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

        $requestParam =
            [
                'criteria' =>
                    [
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ['field' => 'channel_manager_id', 'condition' => '=', 'value' => 2],//Channex
                        ['field' => 'channel_manager_property_id', 'condition' => '!=', 'value' => null],
                    ],
                'with' => ['property']
            ];

        $howManyDays = 90;
        if (!is_null($this->option('property_id'))) {
            $requestParam['criteria'][] = ['field' => 'property_id', 'condition' => '=', 'value' => $this->option('property_id')];
            $howManyDays = 6 * 30;
        }

        $channelManagerPropertyMapping = $this->channelManagerPropertyMappingService->select($requestParam);
        $channelManagerPropertyMapping = $channelManagerPropertyMapping['status'] == 'success' ? $channelManagerPropertyMapping['data'] : [];

        foreach ($channelManagerPropertyMapping as $propertyMapping) {

            if ($propertyMapping['property']['status'] != 1) {
                $this->error(date('Y-m-d H:i:s') . ' : ' . $propertyMapping['property']['name']);
                continue;
            }


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

            try {

                $propertyRoomRateChannelMappingParam = [
                    'criteria' => [
                        ['field' => 'channel_id', 'condition' => '=', 'value' => 5],//Kanal Yöentimi
                        ['field' => 'property_id', 'condition' => '=', 'value' => $propertyMapping['property_id']],
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ],
                    'with' => [
                        'propertyRoomRateMapping.propertyRoomRate.propertyRoomRateAccommodation',
                        'propertyRoomRateMapping.propertyRoom.propertyRoomType',
                    ]
                ];

                $propertyRoomRateChannelMapping = $this->propertyRoomRateChannelMappingService->select($propertyRoomRateChannelMappingParam);
                $propertyRoomRateChannelMapping = $propertyRoomRateChannelMapping['status'] == 'success' ? $propertyRoomRateChannelMapping['data'] : [];
                $propertyRoomRateChannelMappingCollect = collect($propertyRoomRateChannelMapping);

                $propertyBookingEngineParam = [
                    'criteria' => [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $propertyMapping['property_id']],
                        ['field' => 'channel_id', 'condition' => '=', 'value' => 1],
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ],
                    'with' => ['channel', 'property.propertyBookingEngineToken'],
                    'firstRow' => 1
                ];

                $propertyBookingEngine = $this->propertyBookingEngineService->select($propertyBookingEngineParam, ['id', 'property_id', 'channel_id', 'token']);
                $propertyBookingEngine = $propertyBookingEngine['status'] == 'success' ? $propertyBookingEngine['data'] : [];

                if (empty($propertyBookingEngine)) {
                    $this->info(date('Y-m-d H:i:s') . ' : None Booking Engine!');
                    continue;
                }


                $searchController = App::make("App\Http\Controllers\BookingEngine\V1\SearchController");


                $roomRateFormatted = [];


                $today = Carbon::now()->startOfDay()->toDateTimeString();
                if (!is_null($this->option('property_id'))) {
                    $today = Carbon::now()->startOfDay()->toDateTimeString();
                } else {

                    //00:00 04:00 08:00 12:00 16:00 20:00
                    $processHour = (integer)Carbon::now()->format('H');

                    switch ($processHour) {

                        case ($processHour >= 0 && $processHour <= 2) :
                        case ($processHour > 8 && $processHour <= 10):
                        case ($processHour > 16 && $processHour <= 18):
                            $today = Carbon::now()->startOfDay()->toDateTimeString();
                            break;
                        case ($processHour > 2 && $processHour <= 4) :
                        case ($processHour > 10 && $processHour <= 12):
                        case ($processHour > 18 && $processHour <= 20) :
                            $today = Carbon::now()->startOfDay()->addDays($howManyDays)->toDateTimeString();
                            break;
                        case ($processHour > 4 && $processHour <= 6) :
                        case ($processHour > 12 && $processHour <= 14):
                        case ($processHour > 20 && $processHour <= 22) :
                            $today = Carbon::now()->startOfDay()->addDays($howManyDays * 2)->toDateTimeString();
                            break;
                        case ($processHour > 6 && $processHour <= 8) :
                        case ($processHour > 14 && $processHour <= 16):
                        case ($processHour > 22 && $processHour < 24) :
                            $today = Carbon::now()->startOfDay()->addDays($howManyDays * 3)->toDateTimeString();
                            break;

                    }

                }


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

                    $checkIn = Carbon::parse($today)->addDays($i)->toDateString();
                    $checkOut = Carbon::parse($checkIn)->addDay()->toDateString();

                    $searchRequestJson = [
                        'date' => [
                            'checkIn' => $checkIn,
                            'checkOut' => $checkOut,
                        ],
                        'rooms' => [
                            [
                                'adults' => 2,
                                'children' => 0,
                                'age' => [],
                            ]
                        ],
                        'property' => [],
                        'ipAddress' => '185.137.215.118',
                        'isMobile' => null,
                        'noneCacheSearch' => true,
                        'min_stay_disabled' => true
                    ];


                    $requestCreate = Request::create(null, null, [], [], [], [], json_encode($searchRequestJson));
                    $requestCreate->headers->set('channelId', '1');
                    $requestCreate->headers->set('bookingEnginePropertyId', $propertyMapping['property_id']);
                    $requestCreate->headers->set('channelToken', $propertyBookingEngine['channel']['token']);
                    $requestCreate->headers->set('bookingEngineToken', $propertyBookingEngine['property']['property_booking_engine_token']['token']);

                    $search = $searchController->search($requestCreate);
                    $search = json_decode(json_encode($search), 1);

                    $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn);

                    if ($search['original']['status'] == 200) {


                        if (empty($search['original']['data']['properties'])) {

                            //Rate Stop or Price 0 Case
                            foreach ($propertyRoomRateChannelMapping as $roomRateChannelMapping) {

                                $referenceRoomRateMapping = $propertyRoomRateChannelMappingCollect
                                    ->where('property_room_rate_mapping.room_id', $roomRateChannelMapping['property_room_rate_mapping']['room_id'])
                                    ->where('property_room_rate_mapping.property_room_rate.name', 'Best Available Rate')->first();

                                if (!empty($referenceRoomRateMapping)) {
                                    $roomRateKey = '1|' . $referenceRoomRateMapping['property_room_rate_mapping']['room_id'] . '|' . $referenceRoomRateMapping['property_room_rate_mapping']['id'] . '|' . $checkIn;
                                    $roomRateFormatted[$roomRateKey] = [
                                        'setup_type_id' => '1',
                                        'room_id' => $referenceRoomRateMapping['property_room_rate_mapping']['room_id'],
                                        'room_rate_mapping_id' => $referenceRoomRateMapping['property_room_rate_mapping']['id'],
                                        'date' => $checkIn,
                                        'amount' => 0
                                    ];
                                }
                            }
                            //Rate Stop or Price 0 Case

                            $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                            continue;
                        }

                        $property = reset($search['original']['data']['properties']);
                        if (empty($property)) {
                            $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                            continue;
                        }

                        if (!isset($property['availabilities'])) {
                            $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                            continue;
                        }

                        $propertyAvailability = reset($property['availabilities']);
                        if (empty($propertyAvailability)) {
                            $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                            continue;
                        }

                        /*dd($propertyAvailability['rooms']);

                        $propertyAvailabilityRoom = reset($propertyAvailability['rooms']);
                        if (empty($propertyAvailability)) {
                            $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                            continue;
                        }

                        $propertyAvailabilityRoom['rates'] = collect($propertyAvailabilityRoom['rates'])->sortBy('total')->toArray();
*/

                        foreach ($propertyAvailability['rooms'] as $roomId => $room) {
                            foreach ($room['rates'] as $roomRateInnerKey => $roomRate) {

                                /*$propertyAvailabilityRoomRate = reset($propertyAvailabilityRoom['rates']);
                                if (empty($propertyAvailabilityRoomRate)) {
                                    $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                                    continue;
                                }*/

                                $propertyAvailabilityRoomRatePrices = reset($roomRate['requestedRoomPrice']);
                                if (empty($propertyAvailabilityRoomRatePrices)) {
                                    $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                                    continue;
                                }

                                $propertyAvailabilityRoomRatePrice = reset($propertyAvailabilityRoomRatePrices['prices']);
                                if (empty($propertyAvailabilityRoomRatePrice)) {
                                    $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                                    continue;
                                }

                                $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['id'] . ' - ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - ' . $propertyAvailabilityRoomRatePrice['total']);


                                $referenceRoomRateMapping = $propertyRoomRateChannelMappingCollect
                                    ->where('property_room_rate_mapping.room_id', $roomId)
                                    ->where('property_room_rate_mapping.property_room_rate.name', 'Best Available Rate')->first();

                                if (empty($referenceRoomRateMapping)) {
                                    $this->info(date('Y-m-d H:i:s') . ' : None Best Available Rate! PropertyId: ' . $propertyMapping['property_id'] . ' Room: ' . $room['name']);
                                    continue;
                                }

                                /*if($referenceRoomRateMapping['property_room_rate_mapping']['id'] != 6003) {
                                    continue;
                                }*/


                                $roomRateKey = '1|' . $referenceRoomRateMapping['property_room_rate_mapping']['room_id'] . '|' . $referenceRoomRateMapping['property_room_rate_mapping']['id'] . '|' . $checkIn;

                                if (!isset($roomRateFormatted[$roomRateKey])) {
                                    $roomRateFormatted[$roomRateKey] = [
                                        'setup_type_id' => '1',
                                        'room_id' => $referenceRoomRateMapping['property_room_rate_mapping']['room_id'],
                                        'room_rate_mapping_id' => $referenceRoomRateMapping['property_room_rate_mapping']['id'],
                                        'date' => $checkIn,
                                        'amount' => $propertyAvailabilityRoomRatePrice['total']
                                    ];

                                }

                                if ($propertyAvailabilityRoomRatePrice['total'] < $roomRateFormatted[$roomRateKey]['amount']) {
                                    $roomRateFormatted[$roomRateKey]['amount'] = $propertyAvailabilityRoomRatePrice['total'];
                                }

                            }

                        }

                    } else {
                        $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['name'] . ' - ' . $checkIn . ' - NONE');
                    }

                }

                $requestParams = [
                    'property_id' => $propertyMapping['property_id'],
                    'channel_id' => 5,
                    'availability' => [],
                    'user_id' => 1,
                    'rates' => $roomRateFormatted
                ];

                $roomRateUpdate = $this->propertyRoomRatePriceService->roomRateUpdate($requestParams);

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

                $response['status'] = true;

                $this->info(date('Y-m-d H:i:s') . ' : ' . $propertyBookingEngine['property']['id'] . ' : ' . $propertyBookingEngine['property']['name'] . ' - Today: ' . $today . ' - OK');

                Log::debug($propertyBookingEngine['property']['id'] . ' : ' . $propertyBookingEngine['property']['name'] . ' - Today: ' . $today . ' - OK');

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


        }


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


    }
}
