<?php

namespace App\Http\Controllers\BookingEngine\V1;

use App\Core\Service\CurrencyService;
use App\Core\Service\FindCountryCodeService;
use App\Core\Service\GeneralTimezoneService;
use App\Core\Service\LanguageService;
use App\Core\Service\PropertyBookingEngineService;
use App\Core\Service\PropertyChannelMappingService;
use App\Core\Service\PropertyGroupService;
use App\Exceptions\ApiErrorException;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;


class PropertyBookingEngineController extends Controller
{

    private $propertyBookingEngineService;
    private $propertyChannelMappingService;
    private $languageService;

    public function __construct(
        PropertyBookingEngineService  $propertyBookingEngineService,
        LanguageService               $languageService,
        PropertyChannelMappingService $propertyChannelMappingService,
        CurrencyService               $currencyService,
        PropertyGroupService          $propertyGroupService,
        FindCountryCodeService        $findCountryCodeService,
        GeneralTimezoneService        $generalTimezoneService
    )
    {
        $this->propertyBookingEngineService = $propertyBookingEngineService;
        $this->languageService = $languageService;
        $this->propertyChannelMappingService = $propertyChannelMappingService;
        $this->currencyService = $currencyService;
        $this->propertyGroupService = $propertyGroupService;
        $this->findCountryCodeService = $findCountryCodeService;
        $this->generalTimezoneService = $generalTimezoneService;
    }

    public function checkProperty(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            if (is_null($request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }
            $params = $request->params;
            $propertyRequest = [
                'criteria' => [
                    ['field' => 'token', 'condition' => '=', 'value' => $params['token']],
                ],
                'with' => ['channel',
                    'property.propertyBookingEngineGroupMapping.propertyGroup.propertyGroupMapping.property.propertyBookingEngineToken',
                    'property.propertyBookingEngineGroupMapping.propertyGroup.propertyGroupMapping.property.propertyWeb',
                    'propertyWeb', 'propertyChannelMapping.channelTax', 'propertyWebComponent',
                    'property.propertyAdditionalInfos'
                ],
                'firstRow' => 1
            ];

            $propertyBookingEngine = $this->propertyBookingEngineService->select($propertyRequest, ['id', 'property_id', 'channel_id', 'token', 'parameters']);

            if ($propertyBookingEngine['status'] != 'success') {
                throw new ApiErrorException($propertyBookingEngine['message']);
            }
            if (!$propertyBookingEngine['data']) {
                throw new ApiErrorException('General error ...');
            }

            $propertyBookingEngine = $propertyBookingEngine['data'];

            $availableLanguageRequest = [
                'criteria' => [
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ['field' => 'is_application', 'condition' => '=', 'value' => 1],
                    ['field' => 'is_published', 'condition' => '=', 'value' => 1]
                ]
            ];

            $availableLanguages = $this->languageService->select($availableLanguageRequest, ['code', 'name', 'language_key']);
            $languageCodes = [];
            foreach ($availableLanguages['data'] as $language) {
                $languageCodes[$language['code']] = $language;
            }


            $properBookingEngineMapping = [];
            if (isset($propertyBookingEngine['parametersArray']['property_group_id'])) {

                $propertyGroupRequest = [
                    'criteria' => [
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ['field' => 'type', 'condition' => '=', 'value' => 'BEN'],
                        ['field' => 'id', 'condition' => '=', 'value' => $propertyBookingEngine['parametersArray']['property_group_id']]
                    ],
                    'with' => ['propertyGroupMapping'],
                    'firstRow' => true,
                ];

                $propertyGroup = $this->propertyGroupService->select($propertyGroupRequest);
                $propertyGroup = $propertyGroup['status'] == 'success' && !empty($propertyGroup['data']) ? $propertyGroup['data']['property_group_mapping'] : [];
                $propertyGroupPropertyIds = collect($propertyGroup)->pluck('property_id')->toArray();

                $propertyGroupBookingEngineRequest = [
                    'criteria' => [
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ['field' => 'channel_id', 'condition' => '=', 'value' => $propertyBookingEngine['channel_id']],
                    ],
                    'with' => ['property.propertyBookingEngineGroupMapping.propertyGroup.propertyGroupMapping.property.propertyBookingEngineToken'],
                    'whereIn' => [
                        ['field' => 'property_id', 'value' => $propertyGroupPropertyIds]
                    ]
                ];

                $propertyGroupBookingEngine = $this->propertyBookingEngineService->select($propertyGroupBookingEngineRequest);
                if ($propertyGroupBookingEngine['status'] == 'success') {

                    foreach ($propertyGroupBookingEngine['data'] as $bookingEngine) {
                        $properBookingEngineMapping[] = [
                            'property_id' => $bookingEngine['property_id'],
                            'name' => $bookingEngine['property']['name'],
                            'token' => $bookingEngine['token'],
                            'order_number' => count($properBookingEngineMapping)
                        ];
                    }
                }

            }

            if ($propertyBookingEngine['channel_id'] == 1) {

                $propertyBookingEngineGroupMapping = $propertyBookingEngine['property']['property_booking_engine_group_mapping'];
                foreach ($propertyBookingEngineGroupMapping as $beGroupMapping) {
                    $group = $beGroupMapping['property_group'];
                    if ($group['type'] == 'MYW') {
                        $groupProperties = $group['property_group_mapping'];
                        foreach ($groupProperties as $groupProperty) {
                            if (isset($groupProperty['property']['property_booking_engine_token'])) {

                                $arrayItem = [
                                    'property_id' => $groupProperty['property_id'],
                                    'name' => $groupProperty['property']['name'],
                                    'token' => $groupProperty['property']['property_booking_engine_token']['token'],
                                    'order_number' => $groupProperty['order_number']
                                ];

                                $arrayItem['web'] = null;
                                if (!empty($groupProperty['property']['property_web'])) {
                                    if ($groupProperty['property']['property_web']['status'] && $groupProperty['property']['property_web']['is_published']) {
                                        $arrayItem['web'] = $groupProperty['property']['property_web']['webProtocolUrl'];
                                    }
                                }

                                $properBookingEngineMapping[] = $arrayItem;

                            }
                        }

                    }
                }
            }

            if (count($properBookingEngineMapping) > 1) {
                array_multisort(array_column($properBookingEngineMapping, 'order_number'), SORT_ASC, $properBookingEngineMapping);
            }

            $channelMappingRequest = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $propertyBookingEngine['property_id']],
                    ['field' => 'channel_id', 'condition' => '=', 'value' => $propertyBookingEngine['channel_id']],
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                ],
                'firstRow' => 1
            ];

            $channelMapping = $this->propertyChannelMappingService->select($channelMappingRequest, ['id', 'contract_file', 'currency_code']);
            if ($channelMapping['status'] != 'success') {
                throw new ApiErrorException($channelMapping['message']);
            }


            $channelDefaultCurrencyCode = $channelMapping['data']['currency_code'];
            //IP Bases Pricing Channel Manipulation
            if (isset($params['ipAddress']) && !empty($params['ipAddress']) && fillOnUndefined($params, 'referrer') != 'google') {

                // Find Country Code with IP
                $ipResponse = $this->findCountryCodeService->findCountryWithIpAddress($params['ipAddress']);

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

                    $propertyChannelMappingParam = [
                        'criteria' => [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyBookingEngine['property_id']],
                            ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ],
                        'with' => ['channel'],
                    ];

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

                    $ipCountryCode = isset($ipResponse['data']['code']) ? $ipResponse['data']['code'] : 'tr';

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

                        $propertyChannelMappingCollect = collect($propertyChannelMapping['data']);
                        $countryChannel = $propertyChannelMappingCollect
                            ->where('channel.channel_category_id', 3)
                            ->where('channel.country_code', $ipCountryCode)
                            ->where('channel.parent_id', 1)
                            ->first();

                        if (!empty($countryChannel)) {
                            $channelDefaultCurrencyCode = $countryChannel['currency_code'];
                        }

                        //countryCodeGroup
                        if (empty($countryChannel)) {
                            $countryChannelGroup = $propertyChannelMappingCollect
                                ->where('channel.channel_category_id', 3)
                                ->where('channel.country_code', 'group')
                                ->where('channel.parent_id', 1)
                                ->toArray();

                            if (!empty($countryChannelGroup)) {
                                foreach ($countryChannelGroup as $country) {
                                    if (!empty($country['channel']['country_code_group'])) {
                                        if (in_array($ipCountryCode, $country['channel']['countryCodeGroupArray'])) {
                                            $channelDefaultCurrencyCode = $country['currency_code'];
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        //countryCodeGroup

                    }

                }
                //channelToken Manipulation


            }

            $exchangeCurrencyRates = $this->currencyService->exchangeCurrencyRates($channelDefaultCurrencyCode);

            $exchangeCurrencyRateList = [];
            $exchangeCurrencyAvailable = ['EUR', 'USD', 'TRY', 'GBP', 'GEL', 'MAD', 'AZN'];
            if ($exchangeCurrencyRates['status'] == 'success') {
                foreach ($exchangeCurrencyRates['data'] as $currencyRate) {
                    if (!in_array($currencyRate['exc_currency_code'], $exchangeCurrencyAvailable)) {
                        continue;
                    }
                    $currencyKey = $currencyRate['currency_code'] . '-' . $currencyRate['exc_currency_code'];
                    $exchangeCurrencyRateList[$currencyKey] = [
                        'currency_code' => $currencyRate['currency_code'],
                        'exc_currency_code' => $currencyRate['exc_currency_code'],
                        'rate' => moneyFourFormatDecimal($currencyRate['rate']),
                    ];
                }
            }

            $contractFileUrl = NULL;
            if (!empty($channelMapping['data']['contract_file'])) {
                $contractFileUrl = Config::get('app.propertyFilesUrl') . $channelMapping['data']['contract_file'];
            }

            $channelTax = null;
            $taxOptions = Config::get('app.taxOptions');
            if (!empty($propertyBookingEngine['property_channel_mapping']['channel_tax_id'])) {
                $channelTax = [
                    'id' => $propertyBookingEngine['property_channel_mapping']['channel_tax']['id'],
                    'code' => $propertyBookingEngine['property_channel_mapping']['channel_tax']['code'],
                    'name' => $propertyBookingEngine['property_channel_mapping']['channel_tax']['name'],
                    'language_key' => $propertyBookingEngine['property_channel_mapping']['channel_tax']['language_key'],
                    'tax' => isset($taxOptions[$propertyBookingEngine['property']['country']]) ? $taxOptions[$propertyBookingEngine['property']['country']] : null
                ];
            }

            //PropertyWebComponent
            $propertyWebComponent = null;
            if ($propertyBookingEngine['property_web_component']) {

                $propertyWebComponentSojernBookingEngine = collect($propertyBookingEngine['property_web_component'])
                    ->where('component_id', 10)
                    ->first();

                if ($propertyWebComponentSojernBookingEngine) {
                    $propertyWebComponent['sojernbookingengine'] = $propertyWebComponentSojernBookingEngine['parameterArray'];
                }

                $propertyWebComponentClarityBookingEngine = collect($propertyBookingEngine['property_web_component'])
                    ->where('component_id', 14)
                    ->first();

                if ($propertyWebComponentClarityBookingEngine) {
                    $propertyWebComponent['claritybookingengine'] = $propertyWebComponentClarityBookingEngine['parameterArray'];
                }

            }


            $propertyTimeZoneDetail = null;
            $timeZoneValue = collect($propertyBookingEngine['property']['property_additional_infos'])->where('additional_info_key_id', '13')->first();
            if ($timeZoneValue) {
                $generalTimezoneRepositoryCriteria = ['criteria' => [['field' => 'id', 'condition' => '=', 'value' => $timeZoneValue['value']],], 'firstRow' => true];
                $propertyTimeZoneDetail = $this->generalTimezoneService->select($generalTimezoneRepositoryCriteria, ['location', 'action_type', 'hour', 'minute']);
                if ($propertyTimeZoneDetail['status'] == 'success') {
                    $propertyTimeZoneDetail = $propertyTimeZoneDetail['data'];
                }

            }

            $responseData = [
                'property_id' => $propertyBookingEngine['property_id'],
                'property_name' => $propertyBookingEngine['property']['name'],
                'channel_id' => $propertyBookingEngine['channel_id'],
                'channel_name' => $propertyBookingEngine['channel']['name'],
                'channel_category_id' => $propertyBookingEngine['channel']['channel_category_id'],
                'booking_engine_token' => $propertyBookingEngine['token'],
                'channel_token' => $propertyBookingEngine['channel']['token'],
                'channel_contact' => $propertyBookingEngine['channel']['contact'],
                'default_language' => isset($propertyBookingEngine['property_web']['default_language']) ? $propertyBookingEngine['property_web']['default_language'] : null,
                'default_currency' => $channelDefaultCurrencyCode,
                'available_language_codes' => $languageCodes,
                'property_booking_engine_mapping' => count($properBookingEngineMapping) > 0 ? $properBookingEngineMapping : null,
                'contract_file_url' => $contractFileUrl,
                'exchange_currency_rate' => $exchangeCurrencyRateList,
                'booking_engine_parameters' => $propertyBookingEngine['parametersArray'],
                'channel_tax' => $channelTax,
                'property_web_component' => $propertyWebComponent,
                'property_timezone' => $propertyTimeZoneDetail
            ];

            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $responseData];

        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }
}
