<?php


namespace App\Http\Controllers;

use App\Models\Rating;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Yajny\Controller\BrandCtrl;
use Yajny\Controller\CategoryCtrl;
use Yajny\Controller\CouponCtrl;
use Yajny\Controller\StoreCtrl;
use Yajny\Member\Models\Click;
use Yajny\Member\Models\Member;
use Yajny\Models\Ad;
use Yajny\Models\Brand;
use Yajny\Models\Category;
use Yajny\Models\Competition;
use Yajny\Models\Coupon;
use Yajny\Models\FeaturedStores;
use Yajny\Models\PageWidget;
use Yajny\Models\Position;
use Yajny\Models\Store;
use Yajny\Models\StoreCategories;
use Yajny\Models\StripBanner;
use Yajny\Models\Tag;
use Yajny\Models\TopHomeSlide;

class HomeController extends Controller
{
    // TODO: Refactor
    public function desktop()
    {
        $CouponCtrl = new CouponCtrl;

        $hot_deal = $CouponCtrl->getHomepageCoupons();

        $featured_deal = $CouponCtrl->getFeaturedDeals();

        return ['hotDeals' => $hot_deal, 'featuredDeals' => $featured_deal];
    }

    // TODO: Refactor
    public function mobile()
    {
        $CouponCtrl = new CouponCtrl;

        $categories = Category::isParent()->selectRaw(Category::colSelect())->get();

        $hot_deal = $CouponCtrl->getHomepageCoupons();

        $hpbrands = explode(',', Brand::getHpBrands());
        if (count($hpbrands) > 1)
            $brands = BrandCtrl::getBrandsByIdApi(($hpbrands));
        else
            $brands = [];

        return ['hotDeals' => $hot_deal, 'categories' => $categories, 'topBrands' => $brands];
    }

    /**
     * @return array
     */
    public function getDiscoveryHomeData()
    {

        $regionCode = request('region');
        $user_id = request('user_id');

        $member = null;
        if ($user_id)
            $member = Member::find($user_id);

        $positions = Position::getByLabel('homepage', $regionCode)->map(function ($position) {
            return Position::mapItemsForApp($position);
        });

        $topStores = StoreCtrl::getTopStores($user_id);

        // todo remove after force update app
        $sliders = null;
        if (isset($positions['homepage_0'])) {
            $sliders = $positions['homepage_0']['ads']->toArray();

            foreach ($sliders as $index => $ad) {
                $sliders[$index] = Ad::fixSliderAppLinKForOldVersion($ad);
            }
        }

        $homeReturn = [
            'slider' => $sliders ?? null, // todo remove after force update app
            'popular_stores' => $this->getPopularStores(),          //TODO to be removed after force update
            'featured_stores' => $topStores->take(5)->map(function ($item) {
                return Store::mapItems($item);
            }),
            'store_offers' => $this->getStoreOffers(),              //TODO to be removed after force update
            'categories' => $this->getCategories()["all_categories"] ?? null,              //TODO to be removed after force update

        ];

        if ($member) {
            $memberCurrency = $member->getUserCurrency();
            $balance = $member->is_merchant ? 0 : ($member->pending_balance + $member->confirmed_balance);
            $homeReturn['balance'] = [
                'value' => round($balance * $memberCurrency->conversion_rate, 2),
                'value_formatted' => $this->currencyValueFormatted($balance * $memberCurrency->conversion_rate, $memberCurrency)
            ];
        }

        return $homeReturn;
    }


    public function getAppHomeData()
    {
        $StoreCtrl = new StoreCtrl;

        $regionCode = request('region');
        $user_id = request('user_id');

        $member = null;
        if ($user_id)
            $member = Member::find($user_id);

        $positions = Position::getByLabel('homepage', $regionCode)->map(function ($position) {
            return Position::mapItemsForApp($position);
        });

        $adsPositions = $positions->filter(function ($position) {
            return $position['type'] == 'ads';
        });

        $top_cashback_stores = $StoreCtrl->getStoresById(config('settingConfig.hp_new_top_stores_top_row')[$regionCode ?? 'global'] ?? [])->map(function ($item) {
            return Store::mapItems($item);
        });

        $topStores = StoreCtrl::getTopStores($user_id);

        $stripBanner = StripBanner::getForApp($regionCode ?? 'global');

        // todo remove after force update app
        $sliders = null;
        if (isset($positions['homepage_0'])) {
            $sliders = $positions['homepage_0']['ads']->toArray();

            foreach ($sliders as $index => $ad) {
                $sliders[$index] = Ad::fixSliderAppLinKForOldVersion($ad);
            }
        }

        $homeReturn = [
            'positions' => $positions,
            'slider' => $sliders ?? null, // todo remove after force update app
            'top_cashback_stores' => $top_cashback_stores,          //TODO to be removed after force update
            'popular_stores' => $this->getPopularStores(),          //TODO to be removed after force update
            'coupons' => $this->getStoreCoupons($topStores),
            'store_offers' => $this->getStoreOffers(),              //TODO to be removed after force update
            'recommended_deals' => $this->getRecommendedDeals($topStores),
            'most_visited' => $user_id ? $this->getMostVisitedStores() : null,        //TODO to be removed after force update
            'ads_positions' => $adsPositions,
            'hot_deals' => $this->getHotDeals(),
            'top_stores' => $topStores->take(5)->map(function ($item) {
                return Store::mapItems($item);
            }),
            'cashback_stores' => $top_cashback_stores->splice(0, 5),
            'strip' => $stripBanner ? StripBanner::mapItemsForApp($stripBanner) : null,
            'countdown_event' => Competition::getCompetitionDataForApp()
        ];

        if ($member) {
            $memberCurrency = $member->getUserCurrency();
            $balance = $member->is_merchant ? 0 : ($member->pending_balance + $member->confirmed_balance);
            $homeReturn['balance'] = [
                'value' => round($balance * $memberCurrency->conversion_rate, 2),
                'value_formatted' => $this->currencyValueFormatted($balance * $memberCurrency->conversion_rate, $memberCurrency)
            ];
        }

        return $homeReturn;
    }


    public function getHotDeals()
    {
        return CouponCtrl::getHomepageCoupons()->map(function ($item) {
            return Coupon::mapItems($item);
        });
    }

    public function getDealsPageData()
    {
        $topStores = StoreCtrl::getTopStores(request('user_id'));
        return [
            'coupons' => $this->getStoreCoupons($topStores),
            'store_offers' => $this->getStoreOffers(),
            'recommended_deals' => $this->getRecommendedDeals($topStores),
            'all_offers' => $this->getRegularOffers()
        ];
    }

    public function getAllStores()
    {
        $stores_data=[];
        if(\request('region')=="global"){
            $Stores=StoreCtrl::getStoreswithoutRegion()->map(function ($item) {
                return Store::mapItems($item);
            });
        }else{
            $Stores=StoreCtrl::getStores()->map(function ($item) {
                return Store::mapItems($item);
            });
        }

        foreach ($Stores as $store){
            $clicks=Click::where('store_id',$store['id'])->count();
            $coupons=Coupon::where('store_id',$store['id'])->count();
            $store_data=["store"=>$store,"store_clicks"=>$clicks,"store_coupons"=>$coupons];
            array_push($stores_data,$store_data);
        }
        return [
            'stores' =>$stores_data,
        ];
    }

    public function getCategories()
    {
        $top_store_categories = CategoryCtrl::getTopParentCategories(true);
        $top_store_categories_ids = $top_store_categories->pluck('id')->toArray();

        return [
            'top_categories' => $top_store_categories->map(function ($item) {
                return StoreCategories::mapItems($item);
            }),
            'all_categories' => CategoryCtrl::getParentCategoriesExceptIds($top_store_categories_ids, true)
                ->map(function ($item) {
                    return StoreCategories::mapItems($item);
                })
        ];
    }

    public function getCategoryStores($category_id)
    {
        $category = CategoryCtrl::getInfo($category_id);
        if (empty($category))
            throw ValidationException::withMessages(['category_id' => ['not_found']]);

        return [
            'category' => StoreCategories::mapItems($category),
            'stores' => StoreCtrl::getStoresByCategory($category->id)->map(function ($item) {
                return Store::mapItems($item);
            }),
        ];
    }

    private function currencyValueFormatted($value, $currency_record): string
    {
        $value = round($value, 2);
        $formattedValue = "{$value} {$currency_record->symbol}";
        if ($currency_record->display_as == 'prefix')
            $formattedValue = "{$currency_record->symbol} {$value}";
        return $formattedValue;
    }

    private function getStoreCoupons($topStores)
    {
        return CouponCtrl::getUserRecommendedCouponsByType('coupon', request('region'), 5, $topStores->pluck('id'), null, true)->map(function ($item) {
            return Coupon::mapItems($item);
        });
    }

    private function getStoreOffers()
    {
        return CouponCtrl::getHomeFeaturedCouponsByType('offer')->map(function ($item) {
            return Coupon::mapItems($item);
        });
    }

    private function getRecommendedDeals($topStores)
    {
        return CouponCtrl::getUserRecommendedCouponsByType('offer', request('region'), 5, $topStores->pluck('id'), null, true)->map(function ($item) {
            return Coupon::mapItems($item);
        });
    }

    private function getPopularStores()
    {
        return StoreCtrl::getStoresById(
            explode(',',
                PageWidget::where('for_page', 'homepage')
                    ->where('widget_type', 'StoresGrid')
                    ->first('widget_content')->widget_content))->map(function ($item) {
            return [
                'id' => $item->id,
                'logo' => $item->logo
            ];
        });
    }

    private function getRegularOffers()
    {
        $offerQuery = Coupon::with(['couponStore' => function ($q) {
            $q->selectRaw(Store::colSelect());
        }])
            ->where('type', 'offer')
            ->where('is_featured', 0)
            ->where('is_recommended', 0)
            ->selectRaw(Coupon::colSelect())
            ->orderBy('clicks', 'DESC');
        CouponCtrl::applyRegions($offerQuery);
        return $offerQuery->get()->map(function ($item) {
            return Coupon::mapItems($item);
        });
    }

    private function getMostVisitedStores()
    {
        $user = Member::find(request('user_id'));
        $topClickedStoresIDs = $user->clicks()
            ->selectRaw("count('id') as store_count, store_id")
            ->groupBy(['store_id'])
            ->orderByDesc('store_count')
            ->limit(20)
            ->get()
            ->pluck('store_id')
            ->toArray();
        return StoreCtrl::getStoresById($topClickedStoresIDs)->map(function ($item) {
            return Store::mapItems($item);
        });
    }

    public function getBlackFridayPageData()
    {
        $StoreCtrl = new StoreCtrl;
        $regionCode = request('region');

        $topStores = StoreCtrl::getTopStores(request('user_id'));
        $top_cashback_stores = $StoreCtrl->getStoresById(config('settingConfig.hp_new_top_stores_top_row')[$regionCode ?? 'global'] ?? [])->map(function ($item) {
            return Store::mapItems($item);
        });

        $positions = Position::getByLabel('black_friday', $regionCode)->map(function ($position) {
            return Position::mapItemsForApp($position);
        });

        $adsPositions = $positions->filter(function ($position) {
            return $position['type'] == 'ads';
        });

        $novemberDays = range(1, 30);
        $singleDays = [11, 12];
        $flashSaleDays = [3, 5, 9, 15, 19, 23, 26];
        $luckyHourDays = array_diff($novemberDays, array_merge($flashSaleDays, $singleDays));

        $flashSaleOffers = [];
        if (Carbon::today()->month == 11 && in_array(Carbon::today()->day, $flashSaleDays)) {
            $flashSaleTag = Tag::where('slug', 'flash-sale')->first();
            $flashSaleOffers = CouponCtrl::getCouponsByTag('offer', $flashSaleTag->id)->map(function ($item) {
                return Coupon::mapItems($item);
            });
        }

        $now = Carbon::now();
        $start = Carbon::createFromTimeString('11:00am');
        $end = Carbon::createFromTimeString('2:00pm');

        $luckyHourStores = [];
        if (Carbon::today()->month == 11 && in_array(Carbon::today()->day, $luckyHourDays) && $now->between($start, $end)) {
            $luckyHourTag = Tag::where('slug', 'lucky-hour')->first();
            $luckyHourStores = StoreCtrl::getStoresById($luckyHourTag->recom_store ?? [])->map(function ($item) {
                return Store::mapItems($item);
            });
        }

        $storeCategories = Category::selectRaw(Category::colSelect())->orderBy('is_recommended')->orderBy('visits', 'DESC')->get()
            ->map(function ($item) {
                return Category::mapItems($item);
            });

        $luckyHourTimeLeft = null;
        if ($now->between($start, $end)) {
            $interval = $now->diffAsCarbonInterval($end);
            $luckyHourTimeLeft = ['hours' => $interval->h, 'minutes' => $interval->i, 'seconds' => $interval->s];
        }

        // todo remove after force update app
        $sliders = null;
        if (isset($positions['black_friday_0'])) {
            $sliders = $positions['black_friday_0']['ads']->toArray();

            foreach ($sliders as $index => $ad) {
                $sliders[$index] = Ad::fixSliderAppLinKForOldVersion($ad);
            }
        }

        return [
            'positions' => $positions,
            'slider' => $sliders ?? null, // todo remove after force update app
            'category_hot_deals' => $storeCategories,
            'flash_sale_offers' => $flashSaleOffers,
            'lucky_hour_stores' => $luckyHourStores,
            'cashback_stores' => $top_cashback_stores->splice(0, 5),
            'hot_coupons' => $this->getStoreCoupons($topStores),
            'ads_positions' => $adsPositions,
            'lucky_hour_time_left' => $luckyHourTimeLeft,
            'countdown_event' => Competition::getCompetitionDataForApp()
        ];
    }

    public function getTopHomeSlide(Request $request)
    {

        $regionCode = $request->region;
        $query = TopHomeSlide::selectRaw(TopHomeSlide::colSelect())->where('status', 'active');

        if ($regionCode) {
            $query->whereJsonContains('region_code', $regionCode);
        }
        $res = $query->get();
        return $res;
    }

    public function getFeaturedStores(Request $request)
    {

        $regionCode = $request->region;
        $query = FeaturedStores::selectRaw(FeaturedStores::colSelect())
            ->with(['Store' => function ($q) {
                $q->selectRaw(Store::colSelect())
                    ->withCount('store_coupons')
                    ->with('store_coupons');
            }])
            ->where('status', 'active');

        if ($regionCode!="global") {
            $query->whereJsonContains('region_code', $regionCode);
        }
        $res = $query->get();
        return $res;
    }


    public function getCyberMondayPageData()
    {
        $StoreCtrl = new StoreCtrl;
        $regionCode = request('region');
        $now = Carbon::now();

        $topStores = StoreCtrl::getTopStores(request('user_id'));
        $top_cashback_stores = $StoreCtrl->getStoresById(config('settingConfig.hp_new_top_stores_top_row')[$regionCode ?? 'global'] ?? [])->map(function ($item) {
            return Store::mapItems($item);
        });

        $positions = Position::getByLabel('cyber_monday', $regionCode)->map(function ($position) {
            return Position::mapItemsForApp($position);
        });

        $adsPositions = $positions->filter(function ($position) {
            return $position['type'] == 'ads';
        });


        $flashSaleOffers = [];
        $flashSaleDays = ["2021-11-29", "2021-12-03"];
        if (in_array($now->tz('Africa/Cairo')->toDateString(), $flashSaleDays)) {
            $flashSaleTag = Tag::where('slug', 'flash-sale')->first();
            $flashSaleOffers = CouponCtrl::getCouponsByTag('offer', $flashSaleTag->id)->map(function ($item) {
                return Coupon::mapItems($item);
            });
        }

        $luckyHourTag = Tag::where('slug', 'lucky-hour')->first();
        $luckyHourStores = StoreCtrl::getStoresById($luckyHourTag->recom_store ?? [])->map(function ($item) {
            return Store::mapItems($item);
        });

        $storeCategories = Category::selectRaw(Category::colSelect())->orderBy('is_recommended')->orderBy('visits', 'DESC')->get()
            ->map(function ($item) {
                return Category::mapItems($item);
            });

        $luckyHourStart = Carbon::createFromTimeString('11:00am');
        $luckyHourEnd = Carbon::createFromTimeString('2:00pm');

        $luckyHourTimeLeft = null;
        if ($now->between($luckyHourStart, $luckyHourEnd)) {
            $interval = $now->diffAsCarbonInterval($luckyHourEnd);
            $luckyHourTimeLeft = ['hours' => $interval->h, 'minutes' => $interval->i, 'seconds' => $interval->s];
        }

        // todo remove after force update app
        $sliders = null;
        if (isset($positions['cyber_monday_0'])) {
            $sliders = $positions['cyber_monday_0']['ads']->toArray();

            foreach ($sliders as $index => $ad) {
                $sliders[$index] = Ad::fixSliderAppLinKForOldVersion($ad);
            }
        }

        return [
            'positions' => $positions,
            'slider' => $sliders ?? null, // todo remove after force update app
            'category_hot_deals' => $storeCategories,
            'flash_sale_offers' => $flashSaleOffers,
            'lucky_hour_stores' => $luckyHourStores,
            'cashback_stores' => $top_cashback_stores->splice(0, 5),
            'hot_coupons' => $this->getStoreCoupons($topStores),
            'ads_positions' => $adsPositions,
            'lucky_hour_time_left' => $luckyHourTimeLeft,
            'countdown_event' => Competition::getCompetitionDataForApp()
        ];
    }

    public function getChristmasPageData()
    {
        $StoreCtrl = new StoreCtrl;
        $regionCode = request('region');
        $now = Carbon::now();

        $topStores = StoreCtrl::getTopStores(request('user_id'));
        $top_cashback_stores = $StoreCtrl->getStoresById(config('settingConfig.hp_new_top_stores_top_row')[$regionCode ?? 'global'] ?? [])->map(function ($item) {
            return Store::mapItems($item);
        });

        $positions = Position::getByLabel('event_christmas', $regionCode)->map(function ($position) {
            return Position::mapItemsForApp($position);
        });

        $adsPositions = $positions->filter(function ($position) {
            return $position['type'] == 'ads';
        });

        $flashSaleOffers = [];
        $flashSaleDays = ["2021-12-07", "2021-12-11", "2021-12-15", "2021-12-21", "2021-12-25", "2021-12-28", "2021-12-31", "2022-01-03", "2022-01-07"];
        if (in_array($now->tz('Africa/Cairo')->toDateString(), $flashSaleDays)) {
            $flashSaleTag = Tag::where('slug', 'flash-sale')->first();
            $flashSaleOffers = CouponCtrl::getCouponsByTag('offer', $flashSaleTag->id)->map(function ($item) {
                return Coupon::mapItems($item);
            });
        }

        $luckyHourTag = Tag::where('slug', 'lucky-hour')->first();
        $luckyHourStores = StoreCtrl::getStoresById($luckyHourTag->recom_store ?? [])->map(function ($item) {
            return Store::mapItems($item);
        });

        $storeCategories = Category::selectRaw(Category::colSelect())->orderBy('is_recommended')->orderBy('visits', 'DESC')->get()
            ->map(function ($item) {
                return Category::mapItems($item);
            });

        $luckyHourStart = Carbon::createFromTimeString('11:00am');
        $luckyHourEnd = Carbon::createFromTimeString('2:00pm');

        $luckyHourTimeLeft = null;
        if ($now->between($luckyHourStart, $luckyHourEnd)) {
            $interval = $now->diffAsCarbonInterval($luckyHourEnd);
            $luckyHourTimeLeft = ['hours' => $interval->h, 'minutes' => $interval->i, 'seconds' => $interval->s];
        }

        // todo remove after force update app
        $sliders = null;
        if (isset($positions['event_christmas_0'])) {
            $sliders = $positions['event_christmas_0']['ads']->toArray();

            foreach ($sliders as $index => $ad) {
                $sliders[$index] = Ad::fixSliderAppLinKForOldVersion($ad);
            }
        }

        return [
            'positions' => $positions,
            'slider' => $sliders ?? null, // todo remove after force update app
            'category_hot_deals' => $storeCategories,
            'flash_sale_offers' => $flashSaleOffers,
            'lucky_hour_stores' => $luckyHourStores,
            'cashback_stores' => $top_cashback_stores->splice(0, 5),
            'hot_coupons' => $this->getStoreCoupons($topStores),
            'ads_positions' => $adsPositions,
            'lucky_hour_time_left' => $luckyHourTimeLeft,
            'countdown_event' => Competition::getCompetitionDataForApp()
        ];
    }

    public function addRating(Request $request)
    {

        Validator::make($request->all(), [
            'rate' => 'required|integer|between:0,5',
            'message' => 'sometimes'
        ])->validate();
        $rate = new Rating();
        $rate->user_id = request('user_id');
        $rate->message = request('message');
        $rate->rate = $request->rate;
        $rate->save();
        return $rate;
    }

    public function getRating(Request $request)
    {
        return Rating::where('user_id', request('user_id'))->get();
    }
}
