<?php

namespace App\Core\Service;


use App\Core\Repository\PropertyWeb\PropertyWebRepository;
use App\Exceptions\ApiErrorException;
use App\Models\Booking;
use App\Models\BookingRoom;
use App\Models\BookingRoomPax;
use App\Models\Country;
use App\Models\PropertyBookingEngine;
use App\Models\PropertyChannel;
use App\Models\PropertyChannelMapping;
use App\Models\PropertyWebLog;
use App\Models\vwBookingSummaryAll;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class DashboardPlusService
{
    private $countryRepository;

    public function __construct(
        CurrencyService $currencyService,
        PropertyWebRepository $propertyWebRepository
    )
    {
        $this->currencyService = $currencyService;
        $this->propertyWebRepository = $propertyWebRepository;
    }


    public function webVisitor(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

            $criteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                ],
                'firstRow' => true
            ];

            $propertyWeb = $this->propertyWebRepository->findByCriteria($criteria, $columns);
            if (empty($propertyWeb)) {
                throw new ApiErrorException('No record found.');
            }

            $startDate = Carbon::parse($params['start_date'])->startOfDay()->timestamp;
            $finishDate = Carbon::parse($params['finish_date'])->endOfDay()->timestamp;
            $propertyWebLogRaw = PropertyWebLog::whereBetween('created_at', [$startDate, $finishDate])
                ->where('web_id', $propertyWeb)
                ->groupBy('country_code')
                ->select('country_code', DB::raw('count(id) count'))
                ->get()->toArray();

            $propertyWebLogCountryIds = pickItemFromArray('country_code', $propertyWebLogRaw);
            $propertyWebLogCountry = Country::whereIn('country_code', $propertyWebLogCountryIds)->get()->toArray();
            $propertyWebLogCountry = collect($propertyWebLogCountry);

            $propertyWebLog = [];
            $propertyWebLogTotal = 0;
            foreach ($propertyWebLogRaw as $propertyWebLogKey => $propertyWebLogValue) {

                $countryCodeDetail = $propertyWebLogCountry->where('country_code', mb_strtoupper($propertyWebLogValue['country_code']))->first();
                if (empty($countryCodeDetail)) {
                    continue;
                }

                $propertyWebLog[] = [
                    'country' => $countryCodeDetail['name'],
                    'language_key' => $countryCodeDetail['language_key'],
                    'country_code' => $propertyWebLogValue['country_code'],
                    'count' => $propertyWebLogValue['count'],
                    'formatted' =>  [
                        'value' => $propertyWebLogValue['count'],
                        'country' => $propertyWebLogValue['country_code'],
                        'country_name' => $countryCodeDetail['name'],
                    ]
                ];

            }

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

            $propertyWebLogTotal = collect($propertyWebLog)->sum('count');

            $response = [
                'status' => true,
                'data' => [
                    'total' => $propertyWebLogTotal,
                    'country' => $propertyWebLog
                ],
            ];

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

        return $response;
    }

    public function guestDemographic(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

            $propertyChannel = PropertyChannel::whereIn('channel_category_id', [2, 3])->get(['id'])->sortBy('id')->toArray();
            $propertyChannelIds = pickItemFromArray('id', $propertyChannel);

            $startDate = Carbon::parse($params['start_date'])->startOfDay()->timestamp;
            $finishDate = Carbon::parse($params['finish_date'])->endOfDay()->timestamp;
            $propertyBooking = Booking::whereBetween('created_at', [$startDate, $finishDate])
                ->where('status', 1)
                ->whereIn('channel_id', $propertyChannelIds)
                ->where('property_id', $params['property_id'])
                ->get(['id'])->sortBy('id')->toArray();
            $propertyBookingIds = pickItemFromArray('id', $propertyBooking);


            $bookingRoomPax = BookingRoomPax::
            whereIn('booking_id', $propertyBookingIds)
                ->get()->toArray();
            $bookingRoomPax = collect($bookingRoomPax);

            $guestDemographic = [];


            $totalPax = $bookingRoomPax->count();

            $guestDemographic['all'] = $totalPax;

            //Gender
            $guestDemographic['gender'] = [];
            if (!empty($totalPax)) {
                $guestDemographic['gender'] = [
                    'male' => [
                        'title' => 'Male',
                        'count' => $bookingRoomPax->where('gender', 'M')->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPax->where('gender', 'M')->count() / $totalPax * 100),
                    ],
                    'female' => [
                        'title' => 'Female',
                        'count' => $bookingRoomPax->where('gender', 'F')->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPax->where('gender', 'F')->count() / $totalPax * 100),
                    ]
                ];
            }


            //Type
            $guestDemographic['type'] = [];
            if (!empty($totalPax)) {
                $guestDemographic['type'] = [
                    'adult' => [
                        'title' => 'Adult',
                        'count' => $bookingRoomPax->where('type', 'ADT')->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPax->where('type', 'ADT')->count() / $totalPax * 100),
                    ],
                    'child' => [
                        'title' => 'Child',
                        'count' => $bookingRoomPax->where('type', 'CHD')->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPax->where('type', 'CHD')->count() / $totalPax * 100),
                    ]
                ];
            }


            //Citizen
            $guestDemographic['citizen'] = [];
            if (!empty($totalPax)) {
                $bookingRoomPaxGroupedCitizen = $bookingRoomPax->groupBy('citizen')->map->count()->toArray();
                arsort($bookingRoomPaxGroupedCitizen);

                $paxGroupedCitizenCountry = Country::whereIn('country_code', array_keys($bookingRoomPaxGroupedCitizen))->get()->toArray();
                $paxGroupedCitizenCountry = collect($paxGroupedCitizenCountry);

                foreach ($bookingRoomPaxGroupedCitizen as $bookingRoomPaxGroupedCitizenCode => $bookingRoomPaxGroupedCitizenCount) {

                    $countryCodeDetail = $paxGroupedCitizenCountry->where('country_code', mb_strtoupper($bookingRoomPaxGroupedCitizenCode))->first();

                    $guestDemographic['citizen'][mb_strtolower($bookingRoomPaxGroupedCitizenCode)] = [
                        'country' => fillOnUndefined($countryCodeDetail, 'name', $bookingRoomPaxGroupedCitizenCode),
                        'language_key' => fillOnUndefined($countryCodeDetail, 'language_key', $bookingRoomPaxGroupedCitizenCode),
                        'country_code' => mb_strtolower($bookingRoomPaxGroupedCitizenCode),
                        'count' => $bookingRoomPaxGroupedCitizenCount,
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPaxGroupedCitizenCount / $totalPax * 100),
                    ];
                }
            }

            //Age
            $guestDemographic['age'] = [];
            if (!empty($totalPax)) {
                $bookingRoomPaxAges = $bookingRoomPax->map(function ($value, $key) {
                    $value['age'] = Carbon::parse($value['birth_date'])->diffInYears(Carbon::createFromTimestamp($value['created_at']));
                    return $value;
                });


                $guestDemographic['age'] = [
                    '0-12' => [
                        'title' => '0-12 Age',
                        'count' => $bookingRoomPaxAges->where('age', '>=', 0)->where('age', '<', 12)->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPaxAges->where('age', '>=', 0)->where('age', '<', 12)->count() / $totalPax * 100),
                    ],
                    '12-18' => [
                        'title' => '12-18 Age',
                        'count' => $bookingRoomPaxAges->where('age', '>=', 12)->where('age', '<', 18)->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPaxAges->where('age', '>=', 12)->where('age', '<', 18)->count() / $totalPax * 100),
                    ],
                    '18-36' => [
                        'title' => '18-36 Age',
                        'count' => $bookingRoomPaxAges->where('age', '>=', 18)->where('age', '<', 36)->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPaxAges->where('age', '>=', 18)->where('age', '<', 36)->count() / $totalPax * 100),
                    ],
                    '36-60' => [
                        'title' => '36-60 Age',
                        'count' => $bookingRoomPaxAges->where('age', '>=', 36)->where('age', '<', 60)->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPaxAges->where('age', '>=', 36)->where('age', '<', 60)->count() / $totalPax * 100),
                    ],
                    '60+' => [
                        'title' => '60+ Age',
                        'count' => $bookingRoomPaxAges->where('age', '>=', 60)->count(),
                        'percentage' => moneyDoubleFormatDecimal($bookingRoomPaxAges->where('age', '>=', 60)->count() / $totalPax * 100),
                    ],
                ];
            }

            $response = [
                'status' => true,
                'data' => $guestDemographic
            ];

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

        return $response;
    }

    public function topChannel(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

            $defaultCurrency = 'TRY';
            $bookingEngineBaseCurrency = PropertyChannelMapping::where('status', 1)
                ->where('channel_id', 1)
                ->where('property_id', $params['property_id'])
                ->first()->toArray();

            if (!empty($bookingEngineBaseCurrency)) {
                $defaultCurrency = $bookingEngineBaseCurrency['currency_code'];
            }

            $startDate = Carbon::parse($params['start_date'])->startOfDay()->timestamp;
            $finishDate = Carbon::parse($params['finish_date'])->endOfDay()->timestamp;
            /*$propertyBooking = Booking::whereBetween('created_at', [$startDate, $finishDate])
                ->where('property_id', $params['property_id'])
                ->get(['id', 'property_id', 'channel_id', 'total', 'currency_code', 'status'])
                ->sortByDesc('id')->toArray();*/

            $propertyBooking = Booking::whereBetween('created_at', [$startDate, $finishDate])
                ->where('property_id', $params['property_id'])
                ->where('status', 1)
                ->groupBy('channel_id')
                ->groupBy('currency_code')
                ->select('channel_id', 'currency_code', DB::raw('count(id) count, sum(total) total'))
                ->get()->toArray();

            //Channel Id List
            $channelIds = pickItemFromArray('channel_id', $propertyBooking);
            $channelIds = !empty($channelIds) ? array_values(array_unique($channelIds)) : [];
            $propertyChannel = PropertyChannel::whereIn('id', $channelIds)->get(['id', 'name'])->toArray();
            $propertyChannelCollect = collect($propertyChannel);

            //Currency Code List
            $currencyCodes = pickItemFromArray('currency_code', $propertyBooking);
            $currencyCodes = !empty($currencyCodes) ? array_values(array_unique($currencyCodes)) : [];


            $topChannel = [];
            foreach ($propertyBooking as $booking) {

                if ($booking['total'] <= 0) {
                    continue;
                }

                $commonCurrencyCodeRate = $this->currencyService->lastExchangeRate($booking['currency_code'], $defaultCurrency);

                $channelName = $propertyChannelCollect->where('id', $booking['channel_id'])->first();
                if (!empty($channelName)) {
                    $channelName = $channelName['name'];
                }

                $topChannel[$booking['channel_id']] = [
                    'name' => $channelName,
                    'count' => $booking['count'],
                    'total' => $booking['total'],
                    'currency_code' => $booking['currency_code'],
                    'commonCurrencyTotal' => ($booking['total'] * $commonCurrencyCodeRate['data']),
                    'commonCurrencyCode' => $defaultCurrency
                ];

            }

            $totalChannelOverall = collect($topChannel)->sum('commonCurrencyTotal');
            foreach ($topChannel as $channelId => $channel) {
                $topChannel[$channelId]['total'] = moneyDoubleFormatDecimal($channel['total']);
                $topChannel[$channelId]['commonCurrencyTotal'] = moneyDoubleFormatDecimal($channel['commonCurrencyTotal']);
                $topChannel[$channelId]['percentage'] = moneyDoubleFormatDecimal($channel['commonCurrencyTotal'] / $totalChannelOverall * 100);
            }


            $topChannel = collect($topChannel)->sortByDesc('commonCurrencyTotal')->toArray();
            $topChannel = array_values($topChannel);

            $response = [
                'status' => true,
                'data' => $topChannel
            ];

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

        return $response;
    }

    public function todayCheckin(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

            $todayCheckin = 0;
            $today = Carbon::now()->startOfDay()->toDateString();
            $todayCheckin = Booking::where('checkin_date', $today)->where('property_id', $params['property_id'])->count();

            $response = [
                'status' => true,
                'data' => $todayCheckin
            ];

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

        return $response;
    }

    public function todayCheckout(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

            $todayCheckOut = 0;
            $today = Carbon::now()->startOfDay()->toDateString();
            $todayCheckOut = Booking::where('checkout_date', $today)->where('property_id', $params['property_id'])->count();

            $response = [
                'status' => true,
                'data' => $todayCheckOut
            ];

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

        return $response;
    }

    public function lengthOfStay(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

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

            $lengthOfStay = 0;
            $lengthOfStay = vwBookingSummaryAll::whereBetween('time', [$startDate, $finishDate])
                ->where('property_id', $params['property_id'])
                ->pluck('length_of_stay')->avg();

            $lengthOfStay = moneyDoubleFormatDecimal($lengthOfStay);

            $response = [
                'status' => true,
                'data' => $lengthOfStay
            ];

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

        return $response;
    }

    public function lengthOfBooking(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

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

            $lengthOfBooking = 0;
            $lengthOfBooking = vwBookingSummaryAll::whereBetween('time', [$startDate, $finishDate])
                ->where('property_id', $params['property_id'])
                ->pluck('length_of_booking')->avg();

            $lengthOfBooking = moneyDoubleFormatDecimal($lengthOfBooking);

            $response = [
                'status' => true,
                'data' => $lengthOfBooking
            ];

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

        return $response;
    }

    public function totalBooking(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

            $defaultCurrency = 'TRY';
            $bookingEngineBaseCurrency = PropertyChannelMapping::where('status', 1)
                ->where('channel_id', 1)
                ->where('property_id', $params['property_id'])
                ->first()->toArray();

            if (!empty($bookingEngineBaseCurrency)) {
                $defaultCurrency = $bookingEngineBaseCurrency['currency_code'];
            }

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

            $propertyBooking = 0;
            $propertyBooking = vwBookingSummaryAll::whereBetween('time', [$startDate, $finishDate])
                ->where('property_id', $params['property_id'])
                ->groupBy('currency_code')
                ->select('currency_code', DB::raw('count(id) count, sum(total) total'))
                ->get()->toArray();


            $totalBooking = [
                'totalCount' => 0,
                'totalRevenue' => 0,
                'currencyCode' => $defaultCurrency
            ];

            foreach ($propertyBooking as $booking) {

                if ($booking['total'] <= 0) {
                    continue;
                }

                $commonCurrencyCodeRate = $this->currencyService->lastExchangeRate($booking['currency_code'], $defaultCurrency);
                $totalBooking['totalRevenue'] += ($booking['total'] * $commonCurrencyCodeRate['data']);
                $totalBooking['totalCount'] += $booking['count'];

            }

            $totalBooking['totalRevenue'] = moneyDoubleFormatDecimal($totalBooking['totalRevenue']);


            $response = [
                'status' => true,
                'data' => $totalBooking
            ];

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

        return $response;
    }

    public function averageDailyRate(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

            $defaultCurrency = 'TRY';
            $bookingEngineBaseCurrency = PropertyChannelMapping::where('status', 1)
                ->where('channel_id', 1)
                ->where('property_id', $params['property_id'])
                ->first()->toArray();

            if (!empty($bookingEngineBaseCurrency)) {
                $defaultCurrency = $bookingEngineBaseCurrency['currency_code'];
            }

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

            $averageDailyRate = [
                'averageDailyRate' => 0,
                'currencyCode' => $defaultCurrency
            ];

            $propertyBooking = vwBookingSummaryAll::whereBetween('time', [$startDate, $finishDate])
                ->where('property_id', $params['property_id'])
                ->select('id')
                ->get()->toArray();
            $propertyBookingIds = pickItemFromArray('id', $propertyBooking);

            $bookingRoom = BookingRoom::whereIn('booking_id', $propertyBookingIds)
                ->select('id', 'booking_id', 'checkin_date', 'checkout_date', 'total', 'currency_code')
                ->get()->toArray();

            $exchangeCurrencyList = collect($bookingRoom)->unique('currency_code')->pluck('currency_code')->toArray();

            foreach ($exchangeCurrencyList as $currencyCode) {
                if ($currencyCode == $defaultCurrency) {
                    $commonCurrencyCodeRate[$currencyCode] = 1;
                } else {
                    $lastExchangeRate = $this->currencyService->lastExchangeRate($currencyCode, $defaultCurrency);
                    $commonCurrencyCodeRate[$currencyCode] = $lastExchangeRate['data'];
                }
            }

            $averageDailyRateList = [];
            foreach ($bookingRoom as $perRoom) {
                $diffInDays = Carbon::parse($perRoom['checkout_date'])->diffInDays(Carbon::parse($perRoom['checkin_date']));
                $totalExchangeAmount = ($perRoom['total'] * $commonCurrencyCodeRate[$perRoom['currency_code']]);
                $averageDailyRateList[] = $totalExchangeAmount / $diffInDays;
            }


            $averageDailyRate['averageDailyRate'] = moneyDoubleFormatDecimal(collect($averageDailyRateList)->average());

            $response = [
                'status' => true,
                'data' => $averageDailyRate
            ];

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

        return $response;
    }

    public function totalPax(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

            $defaultCurrency = 'TRY';
            $bookingEngineBaseCurrency = PropertyChannelMapping::where('status', 1)
                ->where('channel_id', 1)
                ->where('property_id', $params['property_id'])
                ->first()->toArray();

            if (!empty($bookingEngineBaseCurrency)) {
                $defaultCurrency = $bookingEngineBaseCurrency['currency_code'];
            }

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

            $propertyBooking = 0;
            $propertyBooking = vwBookingSummaryAll::whereBetween('time', [$startDate, $finishDate])
                ->where('property_id', $params['property_id'])
                ->groupBy('currency_code')
                ->select('currency_code', DB::raw('count(id) count, sum(total) total'))
                ->get()->toArray();


            $totalPax = [
                'totalPaxCount' => 0,
                'totalPaxRevenue' => 0,
                'averageRevenuePerPax' => 0,
                'currencyCode' => $defaultCurrency
            ];

            foreach ($propertyBooking as $booking) {

                if ($booking['total'] <= 0) {
                    continue;
                }

                $commonCurrencyCodeRate = $this->currencyService->lastExchangeRate($booking['currency_code'], $defaultCurrency);
                $totalPax['totalPaxRevenue'] += ($booking['total'] * $commonCurrencyCodeRate['data']);

            }

            $totalPax['totalPaxRevenue'] = moneyDoubleFormatDecimal($totalPax['totalPaxRevenue']);

            $bookingIds = vwBookingSummaryAll::whereBetween('time', [$startDate, $finishDate])
                ->where('property_id', $params['property_id'])
                ->pluck('id')->toArray();

            $bookingRoom = BookingRoom::whereIn('booking_id', $bookingIds)
                ->groupBy('occupancy_code')
                ->select('occupancy_code', DB::raw('count(id) count'))
                ->get()->toArray();

            foreach ($bookingRoom as $bookingRoomPax) {

                $adultCount = substr_count($bookingRoomPax['occupancy_code'], 'A');
                $childCount = substr_count($bookingRoomPax['occupancy_code'], 'C');

                $totalPax['totalPaxCount'] += (($adultCount + $childCount) * $bookingRoomPax['count']);

            }

            if($totalPax['totalPaxCount'] > 0) {
                $totalPax['averageRevenuePerPax'] = moneyDoubleFormatDecimal($totalPax['totalPaxRevenue'] / $totalPax['totalPaxCount']);
            }


            $response = [
                'status' => true,
                'data' => $totalPax
            ];

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

        return $response;
    }

    public function channelForecast(array $params = [], $columns = ["*"])
    {
        $response = ['status' => false, 'message' => '', 'data' => null];

        try {

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

            //Burada mutlaka 2 kontrol eklenecke,
            // 1. bitiş, başlangıçtan büyük olamazi
            // 2. max 6 aylık yani 180 günlük veri çekilebilir


            $relatingDates = [];
            $dateDiff = Carbon::parse($startDate)->diffInDays(Carbon::parse($finishDate));
            for ($i = 0; $i < ($dateDiff + 1); $i++) {
                $currentDate = Carbon::parse($startDate)->addDays($i)->toDateString();
                $relatingDates[] = $currentDate;
            }

            $period = [];
            $periodModel = 'daily';
            if (Carbon::parse($startDate)->month != Carbon::parse($finishDate)->month) {
                $periodModel = 'monthly';
            } elseif (Carbon::parse($startDate)->diffInDays(Carbon::parse($finishDate)) > 30) {
                $periodModel = 'monthly';
            }

            $propertyBooking = Booking::where('status', 1)
                ->where('checkin_date', '<=', $finishDate)
                ->where('checkout_date', '>=', $startDate)
                ->where('property_id', $params['property_id'])
                //->where('id',11825)
                ->with('bookingRoomSummary')
                ->select('id', 'channel_id', 'checkin_date', 'checkout_date', 'total', 'status')
                ->get()->toArray();

            //dd($propertyBooking);

            //Channel Id List
            $channelIds = pickItemFromArray('channel_id', $propertyBooking);
            $channelIds = !empty($channelIds) ? array_values(array_unique($channelIds)) : [];
            $propertyChannel = PropertyChannel::whereIn('id', $channelIds)->get(['id', 'name'])->toArray();
            $propertyChannelCollect = collect($propertyChannel);

            $bookingChannelForecast = [];
            $bookingChannelForecastTotal = [];
            foreach ($propertyBooking as $booking) {

                if ($booking['total'] <= 0) {
                    continue;
                }

                $channelName = $propertyChannelCollect->where('id', $booking['channel_id'])->first();
                if (!empty($channelName)) {
                    $channelName = $channelName['name'];
                }

                foreach ($booking['booking_room_summary'] as $bookingRoom) {

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

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

                        if(!in_array($date,$relatingDates)) {
                            continue;
                        }


                        if (!isset($bookingChannelForecast[$booking['channel_id']]['total'])) {
                            $bookingChannelForecast[$booking['channel_id']]['id'] = $booking['channel_id'];
                            $bookingChannelForecast[$booking['channel_id']]['title'] = $channelName;
                            $bookingChannelForecast[$booking['channel_id']]['total'] = 0;
                            $bookingChannelForecast[$booking['channel_id']]['percentage'] = 0;
                        }

                        if (!isset($bookingChannelForecast[$booking['channel_id']]['data'][$date])) {
                            $bookingChannelForecast[$booking['channel_id']]['data'][$date] = 0;
                        }

                        if (!isset($bookingChannelForecastTotal[$date])) {
                            $bookingChannelForecastTotal[$date] = 0;
                        }


                        $bookingChannelForecast[$booking['channel_id']]['data'][$date]++;
                        $bookingChannelForecast[$booking['channel_id']]['total']++;
                        $bookingChannelForecastTotal[$date]++;

                    }
                }

            }


            $totalRoom = collect($bookingChannelForecast)->sum('total');

            $dateDiff = Carbon::parse($startDate)->diffInDays(Carbon::parse($finishDate));
            for ($i = 0; $i < ($dateDiff + 1); $i++) {
                $currentDate = Carbon::parse($startDate)->addDays($i)->toDateString();
                foreach ($bookingChannelForecast as $channelId => $channel) {
                    foreach ($channel['data'] as $date => $count) {

                        if (!isset($bookingChannelForecast[$channelId]['data'][$currentDate])) {
                            $bookingChannelForecast[$channelId]['data'][$currentDate] = 0;
                        }

                        if (!isset($bookingChannelForecastTotal[$currentDate])) {
                            $bookingChannelForecastTotal[$currentDate] = 0;
                        }


                        $period[$currentDate] = $currentDate;
                        $bookingChannelForecast[$channelId]['percentage'] = moneyDoubleFormatDecimal($bookingChannelForecast[$channelId]['total'] / $totalRoom * 100);

                        ksort($bookingChannelForecast[$channelId]['data']);
                        ksort($period);

                    }
                }
            }


            if ($periodModel == 'monthly') {

                $period = [];
                foreach ($bookingChannelForecast as $channelId => $channel) {
                    foreach ($channel['data'] as $date => $count) {

                        $currentMonth = Carbon::parse($date)->format('Y-m');
                        $period[$currentMonth] = $currentMonth;

                        if (!isset($bookingChannelForecast[$channelId]['data'][$currentMonth])) {
                            $bookingChannelForecast[$channelId]['data'][$currentMonth] = 0;
                        }


                        if (!isset($bookingChannelForecastTotal[$currentMonth])) {
                            $bookingChannelForecastTotal[$currentMonth] = 0;
                        }


                        $bookingChannelForecast[$channelId]['data'][$currentMonth] += $bookingChannelForecast[$channelId]['data'][$date];
                        $bookingChannelForecastTotal[$currentMonth] += $bookingChannelForecast[$channelId]['data'][$date];

                        unset($bookingChannelForecast[$channelId]['data'][$date]);
                        unset($bookingChannelForecastTotal[$date]);
                        ksort($bookingChannelForecast[$channelId]['data']);
                        ksort($bookingChannelForecast);
                        ksort($period);
                    }
                }

            }

            $bookingChannelForecast = collect($bookingChannelForecast)->sortBy('title')->toArray();
            $bookingChannelForecast = array_values($bookingChannelForecast);

            $propertyChannel = collect($propertyChannel)->sortBy('name')->pluck('name')->toArray();

            $period = is_array($period) ? array_values($period) : [];

            ksort($bookingChannelForecastTotal);

            $response = [
                'status' => true,
                'data' => [
                    'title' => 'Forecast - '.$startDate . ' / ' . $finishDate . ' (' . ucfirst($periodModel) . ')',
                    'period' => $period,
                    'channel' => $propertyChannel,
                    'forecast' => $bookingChannelForecast,
                    'forecastTotal' => $bookingChannelForecastTotal
                ]
            ];

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

        return $response;
    }


}
