<?php

namespace App\Http\Controllers\V1;

use App\Http\Controllers\Controller;
use App\Core\Service\PropertyService;
use App\Models\Country;
use App\Models\Language;
use App\Models\vwBookingEngineSearch;
use App\Models\vwBookingSummaryAll;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Core\Service\PropertyTypeService;
use App\Core\Service\PropertyChainService;
use App\Core\Service\UserPropertyMappingService;
use App\Core\Service\PermissionService;
use App\Core\Service\PropertyConfigService;
use App\Core\Service\SiteConfigService;
use App\Core\Service\CountryService;
use App\Core\Service\GeneralTimezoneService;
use App\Core\Service\PropertyNetworkService;
use App\Core\Service\ProductService;
use App\Core\Service\DashboardPlusService;

use App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Config;
use Exception;
use App\Exceptions\ApiErrorException;
use Illuminate\Support\Facades\Validator;

class PropertyController extends Controller
{


    private $request;
    private $propertyService;
    private $propertyTypeService;
    private $propertyChainService;
    private $userPropertyMappingService;
    private $permissionService;
    private $propertyConfigService;
    private $siteConfigService;
    private $countryService;
    private $generalTimezoneService;
    private $propertyNetworkService;
    private $productService;


    public function __construct(
        Request $request,
        UserPropertyMappingService $userPropertyMappingService,
        PermissionService $permissionService,
        PropertyChainService $propertyChainService,
        PropertyTypeService $propertyTypeService,
        PropertyConfigService $propertyConfigService,
        SiteConfigService $siteConfigService,
        PropertyService $propertyService,
        GeneralTimezoneService $generalTimezoneService,
        CountryService $countryService,
        PropertyNetworkService $propertyNetworkService,
        ProductService $productService,
        DashboardPlusService $dashboardPlusService
    )
    {
        $this->request = $request;
        $this->propertyService = $propertyService;
        $this->propertyTypeService = $propertyTypeService;
        $this->propertyChainService = $propertyChainService;
        $this->userPropertyMappingService = $userPropertyMappingService;
        $this->permissionService = $permissionService;
        $this->propertyConfigService = $propertyConfigService;
        $this->siteConfigService = $siteConfigService;
        $this->countryService = $countryService;
        $this->generalTimezoneService = $generalTimezoneService;
        $this->propertyNetworkService = $propertyNetworkService;
        $this->productService = $productService;
        $this->dashboardPlusService = $dashboardPlusService;
    }

    public function listProperty(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;

            $requestParams = [
                'locale' => fillOnUndefined($params, 'locale'),
                'user_id' => $request->credentials->user_id,

            ];

            $property = $this->propertyService->getPropertyList($requestParams);

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

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

        } 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']);


    }

    public function getProperty(Request $request)
    {

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

            $return = [];
            if (is_null($request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $request->params;

            $requestParams = [

                'locale' => fillOnUndefined($params, 'locale'),
                'property_id' => fillOnUndefined($params, 'property_id'),

            ];

            $property = $this->propertyService->getProperty($requestParams);

            if ($property['status'] != 'success') {
                throw new Exception($property['message']);
            }
            $return['get_property'] = $property['data']['get_property'];
            $return['minimum_age_policies'] = $property['data']['minimum_age_policies'];


            $propertyType = $this->propertyTypeService->getPropertyTypes($requestParams);
            if ($propertyType['status'] != 'success') {
                throw new ApiErrorException($propertyType['message']);
            }
            $return['property_type'] = $propertyType['data']['property_type'];


            $propertyChains = $this->propertyChainService->getPropertyChains($requestParams);
            if ($propertyChains['status'] != 'success') {
                throw new ApiErrorException($propertyChains['message']);
            }
            $return['property_chains'] = $propertyChains['data']['property_chains'];

            $criteria = [
                'criteria' => [
                    ['field' => 'status', 'condition' => '=', 'value' => 1],

                ],
                "orderBy" => [
                    ["field" => "name", "value" => "ASC"]
                ]
            ];
            $countries = $this->countryService->getCountryList($criteria);
            if ($countries['status'] != 'success') {
                throw new ApiErrorException($countries['message']);
            }
            $return['countries'] = $countries['data'];

            $generalTimeZones = $this->generalTimezoneService->getAllaGeneralTimezone($params);
            if ($generalTimeZones['status'] != 'success') {
                throw new ApiErrorException($generalTimeZones['message']);
            }
            $return['general_timezone'] = $generalTimeZones['data'];

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

        } 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']);


    }

    public function updateProperty(Request $request)
    {

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

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $requestParams = [
                'locale' => fillOnUndefined($params, 'locale'),
                'property_info' => fillOnUndefined($params, 'property_info'),
                'additional_info' => fillOnUndefined($params, 'additional_info'),
                'property_language_spoken' => fillOnUndefined($params, 'property_language_spoken'),
                'has_locale_name' => fillOnUndefined($params, 'has_locale_name', false),
                'property_id' => fillOnUndefined($params, 'property_id'),
                'user_id' => $request->credentials->user_id,
            ];


            $property = $this->propertyService->propertyUpdate($requestParams);

            if ($property['status'] != 'success') {

                throw new ApiErrorException($property['message']);
            }


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

        } 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']);


    }

    public function updatePropertyContentCode(Request $request)
    {

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

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $requestParams = [
                'content_code' => fillOnUndefined($params, 'content_code')
            ];

            $validator = Validator::make($requestParams, ['content_code' => 'nullable|min:5|max:10']);
            if (!empty($validator->errors()->messages())) {
                throw new ApiErrorException('The verification code must be a minimum of 5 and a maximum of 10 digits.');
            }

            $property = $this->propertyService->update($params['property_id'], $requestParams);

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


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

        } 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']);


    }

    public function userPropertyMenu(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 400];
        try {
            $userId = $request->credentials->user_id;
            $params = $request->params;

            $mappingPropertiesCriteria = [
                'criteria' => [
                    ['field' => 'user_id', 'condition' => '=', 'value' => $userId],
                ],
                'with' => ['property'],
            ];
            if (isset($params['property_id'])) {
                $mappingPropertiesCriteria['criteria'][] = ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']];
            }

            $mappingProperties = $this->userPropertyMappingService->select($mappingPropertiesCriteria);
            if (!$mappingProperties['data']) {
                throw new ApiErrorException(lang('User Property mapping not found'));
            }

            $propertyList = collect($mappingProperties['data'])->map(function ($value) use ($userId, $params) {

                $menuParams = [
                    'user_id' => $userId,
                    'property_id' => $value['property']['id'],
                    'locale' => fillOnUndefined($params, 'locale')
                ];
                if (is_array($value['property'])) {
                    return $value['property'] = [
                        'id' => $value['property']['id'],
                        'name' => $value['property']['name'],
                        'property_menu' => $this->permissionService->getMenuTreeForUser($menuParams)
                    ];
                }
            })->toArray();
            $return['property_list'] = $propertyList;

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

        } 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'] = 400;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }

    public function propertyDashBoard(Request $request)
    {
        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 400];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $propertyDashBoardparams = [
                'property_id' => fillOnUndefined($params, 'property_id'),
                'user_id' => $request->credentials->user_id,
                'locale' => array_shift($request->header()['language'])
            ];

            $propertyRequest = [
                'criteria' => [
                    ['field' => 'id', 'condition' => '=', 'value' => $params['property_id']],
                ],
                'firstRow' => true
            ];
            $property = $this->propertyService->select($propertyRequest);
            if ($property['status'] != 'success' || !isset($property['data'])) {
                throw new ApiErrorException($property['message']);
            }
            $property = isset($property['data']) ? $property['data'] : [];

            $siteConfig = $this->propertyConfigService->propertyDashBoard($propertyDashBoardparams);
            if ($siteConfig['status'] != 'success') {
                throw new ApiErrorException($siteConfig['message']);
            }
            $return = $siteConfig['data'];
            $return['hotel_name'] = $property['name'];

            $siteHints = $this->siteConfigService->siteHints($propertyDashBoardparams);
            if ($siteHints['status'] != 'success') {
                throw new ApiErrorException($siteConfig['message']);
            }
            $return['site_hints'] = $siteHints['data'];

            $return['content_code'] = $property['content_code'];

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

        } 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'] = 400;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }

    public function propertyPabDashBoard(Request $request)
    {
        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 400];
        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;

            $requestData = [
                'property_id' => fillOnUndefined($params, 'property_id')
            ];

            $property = $this->propertyNetworkService->getAllDashboardData($requestData);

            if ($property['status'] != 'success' || !isset($property['data'])) {
                throw new ApiErrorException($property['message']);
            }

            $property = isset($property['data']) ? $property['data'] : [];


            /*$return = [
                'hotel_name' => $property['name'],

                'room_and_rate' => [
                    'room_count' => 16,
                    'rate_count' => 8

                ],
                'channels' => [
                    'channel_percent' => 25,
                    'avail_channels' => 48,
                    'saved_channel' => 12
                ],
                'reservation' => [
                    [
                        'day' => 'Mon',
                        'reservation_count' => 16,
                        'reservation_percent' => 50
                    ],
                    [
                        'day' => 'Tue',
                        'reservation_count' => 5,
                        'reservation_percent' => 15
                    ],
                    [
                        'day' => 'Wed',
                        'reservation_count' => 12,
                        'reservation_percent' => 30
                    ],
                    [
                        'day' => 'Thu',
                        'reservation_count' => 15,
                        'reservation_percent' => 50
                    ],
                    [
                        'day' => 'Fri',
                        'reservation_count' => 45,
                        'reservation_percent' => 95
                    ],
                    [
                        'day' => 'Sat',
                        'reservation_count' => 47,
                        'reservation_percent' => 97
                    ],
                    [
                        'day' => 'Mon',
                        'reservation_count' => 49,
                        'reservation_percent' => 100
                    ],

                ],
                'for_cast' => [
                    'total' => 40,
                    'popular_channels' => [

                        [
                            'name' => 'Booking.Com',
                            'cast' => 12,
                        ],
                        [
                            'name' => 'Agoda',
                            'cast' => 13,
                        ], [
                            'name' => 'Trivago',
                            'cast' => 15,
                        ],
                    ]

                ]


            ];*/

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

        } 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'] = 400;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }

    public function createProperty(Request $request)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {
            DB::beginTransaction();

            $return = [];
            if (is_null($request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $userId = $request->credentials->user_id;
            $propertyInsertData = [
                'name' => __('enw-your_property_name'),
                'property_chain' => 1,
                'status' => 2,
                'created_by' => $userId,
                'updated_by' => $userId,
                'created_at' => time(),
                'updated_at' => time(),
            ];
            $propertyCreate = $this->propertyService->create($propertyInsertData);
            if ($propertyCreate['status'] != 'success') {
                throw new ApiErrorException($propertyCreate['message']);
            }

            $return = $propertyCreate['data'];
            $userPropertyMappingData = [
                'user_id' => $userId,
                'status' => 1,
                'property_id' => $propertyCreate['data']['id'],
                'created_by' => $userId,
                'updated_by' => $userId,
                'created_at' => time(),
                'updated_at' => time(),
            ];
            $userPropertyMappingCreate = $this->userPropertyMappingService->create($userPropertyMappingData);
            if ($userPropertyMappingCreate['status'] != 'success') {
                throw new ApiErrorException($userPropertyMappingCreate['message']);
            }

            $propertyProducts = $this->productService->setDefaultPropertyProducts($userPropertyMappingData);
            if ($propertyProducts['status'] != 'success') {
                throw new ApiErrorException($propertyProducts['message']);
            }

            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $return];
            DB::commit();
        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
            DB::rollBack();

        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
            DB::rollBack();

        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);


    }


    /*
     * Dashboard Plus
     */

    public function propertyDashBoardPlus(Request $request)
    {

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

        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $params['user_id'] = $request->credentials->user_id;

            //Date Check
            $diffInDays = Carbon::parse($params['start_date'])->diffInDays(Carbon::parse($params['finish_date']));
            if ($diffInDays > 180) {
                throw new ApiErrorException('A maximum of 180 days of data can be retrieved.');
            }
            if (Carbon::parse($params['finish_date'])->isBefore(Carbon::parse($params['start_date']))) {
                throw new ApiErrorException('The finish date cannot be earlier than the start date.');
            }


            $propertyCriteria = [
                'criteria' => [
                    ['field' => 'id', 'condition' => '=', 'value' => $params['property_id']],
                ],
                'firstRow' => true
            ];
            $property = $this->propertyService->select($propertyCriteria);

            if ($property['status'] != 'success' || !isset($property['data'])) {
                throw new ApiErrorException($property['message']);
            }

            $property = isset($property['data']) ? $property['data'] : [];


            $dashBoardParam = [
                'property_id' => $params['property_id'],
                'start_date' => fillOnUndefined($params, 'start_date', Carbon::now()->subYear()->toDateString()),
                'finish_date' => fillOnUndefined($params, 'finish_date', Carbon::now()->subDay()->toDateString()),
            ];


            $todayCheckin = $this->dashboardPlusService->todayCheckin($dashBoardParam);
            $todayCheckin = $todayCheckin['status'] ? $todayCheckin['data'] : 0;

            $todayCheckout = $this->dashboardPlusService->todayCheckout($dashBoardParam);
            $todayCheckout = $todayCheckout['status'] ? $todayCheckout['data'] : 0;

            $lengthOfStay = $this->dashboardPlusService->lengthOfStay($dashBoardParam);
            $lengthOfStay = $lengthOfStay['status'] ? $lengthOfStay['data'] : 0;

            $lengthOfBooking = $this->dashboardPlusService->lengthOfBooking($dashBoardParam);
            $lengthOfBooking = $lengthOfBooking['status'] ? $lengthOfBooking['data'] : 0;

            $totalBooking = $this->dashboardPlusService->totalBooking($dashBoardParam);
            $totalBooking = $totalBooking['status'] ? $totalBooking['data'] : [];

            $averageDailyRate = $this->dashboardPlusService->averageDailyRate($dashBoardParam);
            $averageDailyRate = $averageDailyRate['status'] ? $averageDailyRate['data'] : [];

            $totalPax = $this->dashboardPlusService->totalPax($dashBoardParam);
            $totalPax = $totalPax['status'] ? $totalPax['data'] : [];

            $responseData = [
                'propertyId' => $property['id'],
                'propertyName' => $property['name'],
                'todayCheckin' => $todayCheckin,
                'todayCheckout' => $todayCheckout,
                'lengthOfStay' => $lengthOfStay,
                'lengthOfBooking' => $lengthOfBooking,
                'totalBooking' => $totalBooking,
                'totalPax' => $totalPax,
                'averageDailyRate' => $averageDailyRate,
            ];


            $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'] = 400;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }

    public function propertyDashBoardPlusWebVisitor(Request $request)
    {

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

        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $params['user_id'] = $request->credentials->user_id;

            //Date Check
            $diffInDays = Carbon::parse($params['start_date'])->diffInDays(Carbon::parse($params['finish_date']));
            if ($diffInDays > 180) {
                throw new ApiErrorException('A maximum of 180 days of data can be retrieved.');
            }
            if (Carbon::parse($params['finish_date'])->isBefore(Carbon::parse($params['start_date']))) {
                throw new ApiErrorException('The finish date cannot be earlier than the start date.');
            }

            $webVisitorParam = [
                'property_id' => $params['property_id'],
                'start_date' => fillOnUndefined($params, 'start_date', Carbon::now()->subYear()->toDateString()),
                'finish_date' => fillOnUndefined($params, 'finish_date', Carbon::now()->subDay()->toDateString()),
            ];

            $webVisitor = $this->dashboardPlusService->webVisitor($webVisitorParam);
            if (!$webVisitor['status']) {
                throw new ApiErrorException($webVisitor['message']);
            }

            $responseData = $webVisitor['data'];


            $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'] = 400;
        }

        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }

    public function propertyDashBoardPlusGuestDemographic(Request $request)
    {

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

        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $params['user_id'] = $request->credentials->user_id;

            //Date Check
            $diffInDays = Carbon::parse($params['start_date'])->diffInDays(Carbon::parse($params['finish_date']));
            if ($diffInDays > 180) {
                throw new ApiErrorException('A maximum of 180 days of data can be retrieved.');
            }
            if (Carbon::parse($params['finish_date'])->isBefore(Carbon::parse($params['start_date']))) {
                throw new ApiErrorException('The finish date cannot be earlier than the start date.');
            }

            $webVisitorParam = [
                'property_id' => $params['property_id'],
                'start_date' => fillOnUndefined($params, 'start_date', Carbon::now()->subYear()->toDateString()),
                'finish_date' => fillOnUndefined($params, 'finish_date', Carbon::now()->subDay()->toDateString()),
            ];

            $webVisitor = $this->dashboardPlusService->guestDemographic($webVisitorParam);
            if (!$webVisitor['status']) {
                throw new ApiErrorException($webVisitor['message']);
            }

            $responseData = $webVisitor['data'];


            $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'] = 400;
        }

        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }

    public function propertyDashBoardPlusTopChannel(Request $request)
    {

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

        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $params['user_id'] = $request->credentials->user_id;

            //Date Check
            $diffInDays = Carbon::parse($params['start_date'])->diffInDays(Carbon::parse($params['finish_date']));
            if ($diffInDays > 180) {
                throw new ApiErrorException('A maximum of 180 days of data can be retrieved.');
            }
            if (Carbon::parse($params['finish_date'])->isBefore(Carbon::parse($params['start_date']))) {
                throw new ApiErrorException('The finish date cannot be earlier than the start date.');
            }

            $topChannelParam = [
                'property_id' => $params['property_id'],
                'start_date' => fillOnUndefined($params, 'start_date', Carbon::now()->subYear()->toDateString()),
                'finish_date' => fillOnUndefined($params, 'finish_date', Carbon::now()->subDay()->toDateString()),
            ];

            $webVisitor = $this->dashboardPlusService->topChannel($topChannelParam);
            if (!$webVisitor['status']) {
                throw new ApiErrorException($webVisitor['message']);
            }

            $responseData = $webVisitor['data'];


            $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'] = 400;
        }

        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }

    public function propertyDashBoardPlusChannelForecast(Request $request)
    {

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

        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $params['user_id'] = $request->credentials->user_id;

            //Date Check
            $diffInDays = Carbon::parse($params['start_date'])->diffInDays(Carbon::parse($params['finish_date']));
            if ($diffInDays > 180) {
                throw new ApiErrorException('A maximum of 180 days of data can be retrieved.');
            }
            if (Carbon::parse($params['finish_date'])->isBefore(Carbon::parse($params['start_date']))) {
                throw new ApiErrorException('The finish date cannot be earlier than the start date.');
            }

            $topChannelParam = [
                'property_id' => $params['property_id'],
                'start_date' => fillOnUndefined($params, 'start_date', Carbon::now()->subYear()->toDateString()),
                'finish_date' => fillOnUndefined($params, 'finish_date', Carbon::now()->subDay()->toDateString()),
            ];

            $webVisitor = $this->dashboardPlusService->channelForecast($topChannelParam);
            if (!$webVisitor['status']) {
                throw new ApiErrorException($webVisitor['message']);
            }

            $responseData = $webVisitor['data'];


            $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'] = 400;
        }

        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }


    public function bookingEngineReport(Request $request)
    {

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

        try {

            $reportTypes = [
                'TRS' => 'Transaction Report',
                'GTR' => 'Guest Transaction Report',
                'DSR' => 'Date Search Report',
                'DSS' => 'Date Search Stay Report',
                'UCR' => 'User Country Report',
                'ULR' => 'User Language Report',
            ];

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $params['user_id'] = $request->credentials->user_id;

            //Date Check
            $diffInDays = Carbon::parse($params['start_date'])->diffInDays(Carbon::parse($params['finish_date']));
            if ($diffInDays > 180) {
                throw new ApiErrorException('A maximum of 180 days of data can be retrieved.');
            }
            if (Carbon::parse($params['finish_date'])->isBefore(Carbon::parse($params['start_date']))) {
                throw new ApiErrorException('The finish date cannot be earlier than the start date.');
            }

            if (!in_array(fillOnUndefined($params, 'type'), array_keys($reportTypes))) {
                throw new ApiErrorException('Undefined report type.');

            }

            $propertyCriteria = [
                'criteria' => [
                    ['field' => 'id', 'condition' => '=', 'value' => $params['property_id']],
                ],
                'firstRow' => true
            ];
            $property = $this->propertyService->select($propertyCriteria);

            if ($property['status'] != 'success' || !isset($property['data'])) {
                throw new ApiErrorException($property['message']);
            }

            $property = isset($property['data']) ? $property['data'] : [];

            $reportType = $params['type'];

            if($reportType != 'DSS') {
                $searchData = vwBookingEngineSearch::where('property_id', $property['id'])
                    ->whereBetween('date', [$params['start_date'], $params['finish_date']])
                    ->get()->toArray();
            }

            $responseData = [];

            switch ($reportType) {
                case 'TRS':

                    $responseData['search'] = collect($searchData)->count();
                    $responseData['roomFound'] = collect($searchData)->where('status', 1)->count();
                    $responseData['roomNotFound'] = collect($searchData)->where('status', 0)->count();
                    $responseData['preBooking'] = collect($searchData)->where('status', 2)->count();
                    $responseData['booking'] = collect($searchData)->where('status', 3)->count();

                    break;
                case 'GTR':

                    $occupancyCodes = collect($searchData)->groupBy('pax')->keys()->toArray();
                    foreach ($occupancyCodes as $occupancyCode) {
                        $responseData[$occupancyCode]['text'] = occupancyCodeFormatted($occupancyCode);
                        $responseData[$occupancyCode]['count'] = collect($searchData)->where('pax', $occupancyCode)->count();
                    }

                    $responseData = collect($responseData)->sortByDesc('count')->toArray();

                    break;
                case 'DSR':

                    //Daily Intensity
                    $dailyIntensity = [];
                    foreach ($searchData as $data) {
                        $checkInDate = $data['checkin_date'];
                        $checkOutDate = $data['checkout_date'];
                        $dateDiff = Carbon::parse($data['checkout_date'])->diffInDays(Carbon::parse($data['checkin_date']));

                        for ($i = 0; $i < $dateDiff; $i++) {
                            $date = Carbon::parse($checkInDate)->addDays($i)->toDateString();

                            if (!isset($dailyIntensity[$date])) {
                                $dailyIntensity[$date]['text'] = Carbon::parse($date)->format('d.m.Y');
                                $dailyIntensity[$date]['search'] = 0;
                                $dailyIntensity[$date]['roomFound'] = 0;
                                $dailyIntensity[$date]['roomNotFound'] = 0;
                                $dailyIntensity[$date]['preBooking'] = 0;
                                $dailyIntensity[$date]['booking'] = 0;
                            }

                            $dailyIntensity[$date]['search']++;
                            $dailyIntensity[$date]['roomFound'] += $data['status'] == 1 ? 1 : 0;
                            $dailyIntensity[$date]['roomNotFound'] += $data['status'] == 0 ? 1 : 0;
                            $dailyIntensity[$date]['preBooking'] += $data['status'] == 2 ? 1 : 0;
                            $dailyIntensity[$date]['booking'] += $data['status'] == 3 ? 1 : 0;

                        }
                    }
                    ksort($dailyIntensity);
                    $responseData = $dailyIntensity;
                    //Daily Intensity
                    break;
                case 'DSS':

                    //Daily Intensity


                    $searchData = vwBookingEngineSearch::where('property_id', $property['id'])
                        ->where('channel_id', $params['channel_id'])
                        ->whereBetween('checkin_date', [$params['start_date'], $params['finish_date']])
                        ->orderByDesc('id')
                        ->get()->toArray();


                    $dailyIntensity = [];
                    foreach ($searchData as $data) {

                        $checkInDate = $data['checkin_date'];
                        $checkOutDate = $data['checkout_date'];
                        $dateDiff = Carbon::parse($data['checkout_date'])->diffInDays(Carbon::parse($data['checkin_date']));

                        for ($i = 0; $i < $dateDiff; $i++) {
                            $date = Carbon::parse($checkInDate)->addDays($i)->toDateString();

                            if(!Carbon::parse($date)->betweenIncluded($params['start_date'], $params['finish_date'])) {
                                continue;
                            }

                            if (!isset($dailyIntensity[$date])) {
                                $dailyIntensity[$date]['text'] = Carbon::parse($date)->format('d.m.Y');
                                $dailyIntensity[$date]['search'] = 0;
                                $dailyIntensity[$date]['roomFound'] = 0;
                                $dailyIntensity[$date]['roomNotFound'] = 0;
                                $dailyIntensity[$date]['preBooking'] = 0;
                                $dailyIntensity[$date]['booking'] = 0;
                                $dailyIntensity[$date]['bookingCode'] = [];
                            }

                            $dailyIntensity[$date]['search']++;
                            $dailyIntensity[$date]['roomFound'] += $data['status'] == 1 ? 1 : 0;
                            $dailyIntensity[$date]['roomNotFound'] += $data['status'] == 0 ? 1 : 0;
                            $dailyIntensity[$date]['preBooking'] += $data['status'] == 2 ? 1 : 0;
                            $dailyIntensity[$date]['booking'] += $data['status'] == 3 ? 1 : 0;

                            if(!empty($data['booking_code'])) {
                                $dailyIntensity[$date]['bookingCode'][] = $data['booking_code'];
                            }

                        }
                    }
                    ksort($dailyIntensity);
                    $responseData = $dailyIntensity;
                    //Daily Intensity
                    break;
                case 'UCR':

                    $countryList = Country::all()->toArray();
                    $countryCodes = collect($searchData)->where('country_code', '!=', null)->groupBy('country_code')->keys()->toArray();

                    foreach ($countryCodes as $countryCode) {
                        $countryText = $countryCode;
                        $countryTextCheck = collect($countryList)->where('country_code', mb_strtoupper($countryCode))->first();
                        if (!empty($countryTextCheck)) {
                            $countryText = $countryTextCheck['name'];
                        }
                        $responseData[$countryCode]['text'] = $countryText;
                        $responseData[$countryCode]['search'] = collect($searchData)->where('country_code', $countryCode)->count();
                        $responseData[$countryCode]['roomFound'] = collect($searchData)->where('country_code', $countryCode)->where('status', 1)->count();
                        $responseData[$countryCode]['roomNotFound'] = collect($searchData)->where('country_code', $countryCode)->where('status', 0)->count();
                        $responseData[$countryCode]['preBooking'] = collect($searchData)->where('country_code', $countryCode)->where('status', 2)->count();
                        $responseData[$countryCode]['booking'] = collect($searchData)->where('country_code', $countryCode)->where('status', 3)->count();
                    }

                    break;
                case 'ULR':

                    $languageList = Language::all()->toArray();
                    $languageCodes = collect($searchData)->groupBy('language_code')->keys()->toArray();
                    foreach ($languageCodes as $languageCode) {
                        $languageText = $languageCode;
                        $languageTextCheck = collect($languageList)->where('code', $languageCode)->first();
                        if (!empty($languageTextCheck)) {
                            $languageText = $languageTextCheck['name'];
                        }
                        $responseData[$languageCode]['text'] = $languageText;
                        $responseData[$languageCode]['search'] = collect($searchData)->where('language_code', $languageCode)->count();
                        $responseData[$languageCode]['roomFound'] = collect($searchData)->where('language_code', $languageCode)->where('status', 1)->count();
                        $responseData[$languageCode]['roomNotFound'] = collect($searchData)->where('language_code', $languageCode)->where('status', 0)->count();
                        $responseData[$languageCode]['preBooking'] = collect($searchData)->where('language_code', $languageCode)->where('status', 2)->count();
                        $responseData[$languageCode]['booking'] = collect($searchData)->where('language_code', $languageCode)->where('status', 3)->count();
                    }

                    $responseData = collect($responseData)->sortByDesc('search')->toArray();

                    break;
                case 'default':
                    break;

            }

            $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'] = 400;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }


    public function couponCodeReport(Request $request)
    {

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

        try {

            if (is_null($this->request->getContent())) {
                throw new ApiErrorException(lang('Parameter Error.'));
            }

            $params = $this->request->params;
            $params['user_id'] = $request->credentials->user_id;

            //Date Check
            $diffInDays = Carbon::parse($params['start_date'])->diffInDays(Carbon::parse($params['finish_date']));
            if ($diffInDays > 180) {
                throw new ApiErrorException('A maximum of 180 days of data can be retrieved.');
            }
            if (Carbon::parse($params['finish_date'])->isBefore(Carbon::parse($params['start_date']))) {
                throw new ApiErrorException('The finish date cannot be earlier than the start date.');
            }

            $propertyCriteria = [
                'criteria' => [
                    ['field' => 'id', 'condition' => '=', 'value' => $params['property_id']],
                ],
                'firstRow' => true
            ];
            $property = $this->propertyService->select($propertyCriteria);

            if ($property['status'] != 'success' || !isset($property['data'])) {
                throw new ApiErrorException($property['message']);
            }

            $property = isset($property['data']) ? $property['data'] : [];


            $startDate = Carbon::parse($params['start_date'])->startOfDay()->toDateTimeString();
            $finishDate = Carbon::parse($params['finish_date'])->endOfDay()->toDateTimeString();

            $status = fillOnUndefined($params,'status', 1);

            if (empty(fillOnUndefined($params, 'code'))) {
                $searchData = vwBookingSummaryAll::where('property_id', $property['id'])
                    ->where('coupon_code', '!=', null)
                    ->where('status', '=', $status)
                    ->whereBetween('time', [$startDate, $finishDate])
                    ->with('bookingStatus')
                    ->get()->toArray();
            } else {
                $searchData = vwBookingSummaryAll::where('property_id', $property['id'])
                    ->where('coupon_code', $params['code'])
                    ->where('status', '=', $status)
                    ->whereBetween('time', [$startDate, $finishDate])
                    ->with('bookingStatus')
                    ->get()->toArray();
            }

            $responseData = [];

            foreach ($searchData as $data) {

                $responseData[] = [
                    'id' => $data['id'],
                    'transaction_period' => $data['transaction_period'],
                    'checkout_period' => $data['checkout_period'],
                    'code' => $data['coupon_code'],
                    'booking_code' => $data['booking_code'],
                    'name_surname' => $data['name_surname'],
                    'checkin_date' => $data['checkin_date'],
                    'checkout_date' => $data['checkout_date'],
                    'length_of_stay' => $data['length_of_stay'],
                    'length_of_booking' => $data['length_of_booking'],
                    'total' => $data['total'],
                    'total_formatted' => $data['total_formatted'],
                    'currency_code' => $data['currency_code'],
                    'status' => $data['status'],
                    'status_name' => $data['booking_status']['name'],
                    'status_language_key' => $data['booking_status']['language_key'],
                    'time' => $data['time'],
                    'time_formatted' => Carbon::parse($data['time'])->format('d.m.Y H:i:s')
                ];

            }


            $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'] = 400;
        }
        return apiResponse($response['status'], $response['message'], $response['data'], $response['statusCode']);
    }


}
