<?php

namespace App\Http\Middleware;

use App\Models\Article;
use App\Models\ArticleComment;
use App\Models\FormAnswer;
use App\Models\Inventory;
use App\Models\Menu;
use App\Models\Order;
use App\Models\OrderGroup;
use App\Models\PaymentMeta;
use App\Models\PendingPayment;
use App\Models\Product;
use App\Models\ProductCategory;
use App\Models\ProductComment;
use App\Models\ProductTag;
use App\Models\Question;
use App\Models\QuestionAnswer;
use App\Models\Search;
use App\Models\Setting;
use App\Models\Statistic;
use App\Models\Store;
use App\Models\Template;
use App\Models\Ticket;
use App\Models\User;
use App\Models\Withdrawal;
use Carbon\Carbon;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\View;
use Inertia\Middleware;
use Morilog\Jalali\Jalalian;
use Tighten\Ziggy\Ziggy;

class HandleInertiaRequests extends Middleware
{
    /**
     * The root template that is loaded on the first page visit.
     * @var string
     */
    protected $rootView = 'app';

    /**
     * main settings
     * @var Array
     */
    protected $settings;

    /**
     * Determine the current asset version.
     */
    public function version(Request $request): string|null
    {
        // do parent
        if (parent::version($request) == null) {
            dd("ERROR - Please contact with system manager"); // die application
        }

        $version = '1';
        if (file_exists(storage_path('version'))) {
            $version = file_get_contents(storage_path('version'));
        }

        // versioning
        if (str_starts_with(request()->getPathInfo(), '/admin')) {
            return 'admin-' . $version;
        } else if (str_starts_with(request()->getPathInfo(), '/seller')) {
            return 'seller-' . $version;
        } else if (str_starts_with(request()->getPathInfo(), '/user')) {
            return 'user-' . $version;
        } else {
            return 'main-' . $version;
        }

        return parent::version($request);
    }

    /**
     * Define the props that are shared by default.
     *
     * @return array<string, mixed>
     */
    public function share(Request $request): array
    {
        // settings
        $this->settings = Cache::remember('settings', now()->addMonth(), function () {
            return Setting::select(['key', 'value'])->get()->toArray();
        });

        /** auth user
         * @var App\Models\User $user
         */
        $user = auth()->user();
        $user = $user != null ? User::where('id', $user->id)->with('wallet')->first() : null;

        /** dark mode */
        $dark = $request->session()->get('dark', $this->getSetting('theme_mode', 'value', 'light') == 'light' ? false : true);

        /** neshan map */
        $neshan = [
            'map_key' => null,
            'service_key' => null,
        ];
        if ($this->getSetting('neshan') != null) {
            $neshanArray = unserialize($this->getSetting('neshan'));
            $neshan['map_key'] = $neshanArray['map_key'];
            $neshan['service_key'] = $neshanArray['service_key'];
        }

        /** payment meta */
        $paymentMeta = Cache::remember('payment_metas', now()->addDay(), function () {
            return PaymentMeta::where('store_id', null)->first();
        });
        if ($paymentMeta != null) {
            $paymentMeta = [
                'id' => $paymentMeta->id,
                'post_period' => $paymentMeta->post_period,
                'free_post_min_price' => $paymentMeta->free_post_min_price,
                'get_formatted_free_post_min_price' => $paymentMeta->get_formatted_free_post_min_price,
                'get_post_ways' => $paymentMeta->get_post_ways,
            ];
        }

        /** gate */
        $gate = [];
        if (auth()->check()) {
            if ($user->type == "owner" || $user->type == "admin") {
                $gate = [
                    'owner' => $request->user()->type == "owner",
                    'manage-users' => $request->user()->can('manage-users'),
                    'change-settings' => $request->user()->can('change-settings'),
                    'show-reports' => $request->user()->can('show-reports'),
                    'manage-menus' => $request->user()->can('manage-menus'),
                    'manage-products' => $request->user()->can('manage-products'),
                    'manage-storages' => $request->user()->can('manage-storages'),
                    'manage-brands' => $request->user()->can('manage-brands'),
                    'manage-product-categories' => $request->user()->can('manage-product-categories'),
                    'manage-tickets' => $request->user()->can('manage-tickets'),
                    'manage-transactions' => $request->user()->can('manage-transactions'),
                    'manage-template' => $request->user()->can('manage-template'),
                    'manage-stores' => $request->user()->can('manage-stores'),
                    'manage-discounts' => $request->user()->can('manage-discounts'),
                    'manage-pages' => $request->user()->can('manage-pages'),
                    'manage-forms' => $request->user()->can('manage-forms'),
                    'manage-product-comments' => $request->user()->can('manage-product-comments'),
                    'manage-product-questions' => $request->user()->can('manage-product-questions'),
                    'manage-articles' => $request->user()->can('manage-articles'),
                    'manage-article-categories' => $request->user()->can('manage-article-categories'),
                    'manage-article-comments' => $request->user()->can('manage-article-comments'),
                    'manage-affiliate' => $request->user()->can('manage-affiliate'),
                    'show-statistics' => $request->user()->can('show-statistics'),
                    'manage-orders' => $request->user()->can('manage-orders'),
                    'manage-stories' => $request->user()->can('manage-stories'),
                    'manage-faq' => $request->user()->can('manage-faq'),
                    'manage-newsletters' => $request->user()->can('manage-newsletters'),
                    'manage-prefactors' => $request->user()->can('manage-prefactors'),
                ];
            }
        }

        /** admin badges */
        $adminBadges = [];
        try {
            if (auth()->check()) {
                if ($user->type == "owner" || $user->type == "admin") {
                    if (str_starts_with($request->route()->getName(), 'admin')) {
                        $ordersStatus = OrderGroup::selectRaw("
                                    CASE
                                        WHEN EXISTS (
                                            SELECT 1 FROM orders
                                            WHERE orders.order_group_id = order_groups.id
                                            AND orders.status = 'registered'
                                        )
                                        THEN 'processing'
                                        ELSE 'completed'
                                    END as status, COUNT(*) as total
                                ")
                            ->groupBy('status')
                            ->pluck('total', 'status')->toArray();

                        $adminBadges = [
                            'waiting-tickets' => Ticket::where('status', 'waiting_admin')->count(),
                            'waiting-stores' => Store::where('status', 'awaiting')->count(),
                            'waiting-products' => Product::where('status', 'awaiting')->count(),
                            'waiting-inventories' => Inventory::where('status', 'awaiting')->count(),
                            'unread-form-answers' => FormAnswer::where('flag', 'unread')->count(),
                            'waiting-product-comments' => ProductComment::where('status', 'awaiting')->count(),
                            'waiting-product-comments-reports' => ProductComment::where('reported', true)->count(),
                            'waiting-questions' => Question::where('status', 'awaiting')->count(),
                            'waiting-question-answers' => QuestionAnswer::where('status', 'awaiting')->count(),
                            'waiting-articles' => Article::where('status', 'awaiting')->count(),
                            'waiting-article-comments' => ArticleComment::where('status', 'awaiting')->count(),
                            'waiting-withdrawals' => Withdrawal::where('status', 'awaiting')->count(),
                            'waiting-orders' => array_key_exists('processing', $ordersStatus) ? $ordersStatus['processing'] : 0,
                            'waiting-pending-payments' => PendingPayment::where('status', 'awaiting')->whereHas('order', function ($query) {
                                $query->where('status', 'delivered');
                            })->count(),
                        ];
                    }
                }
            }
        } catch (\Exception $e) {
        }

        /** seller badges */
        $sellerBadges = [];
        if (auth()->check()) {
            if ($user->seller) {
                if (str_starts_with($request->route()->getName(), 'seller')) {
                    $store = $user->store;
                    $sellerBadges = [
                        'waiting-tickets' => $user->tickets()->where('status', 'waiting_user')->count(),
                        'waiting-questions' => Question::whereHas('product', function ($query) use ($store) {
                            $query->whereHas('stores', function ($query) use ($store) {
                                $query->where('id', $store->id);
                            });
                        })->where('status', 'awaiting')->count(),
                        'waiting-question-answers' => QuestionAnswer::whereHas('question', function ($query) use ($store) {
                            $query->whereHas('product', function ($query) use ($store) {
                                $query->whereHas('stores', function ($query) use ($store) {
                                    $query->where('id', $store->id);
                                });
                            });
                        })->where('status', 'awaiting')->count(),
                        'waiting-orders' => $user->store->consignments()->whereHas('consignmentItems', function ($query) {
                            $query->where('status', 'awaiting_seller')->orWhere('status', 'awaiting_seller_send');
                        })->count(),
                        'waiting-product' => $user->store->products()->where('status', 'awaiting')->count(),
                        'waiting-inventory' => $user->store->inventories()->where('status', 'awaiting')->count(),
                    ];
                }
            }
        }

        /** user badges */
        $userBadge = [];
        if (auth()->check()) {
            if (str_starts_with($request->route()->getName(), 'user')) {
                $userBadge = [
                    'waiting-orders' => $user->orders()->where('status', 'registered')->count(),
                    'waiting-tickets' => $user->tickets()->where('status', 'waiting_admin')->count(),
                    'waiting-comments' => $user->productComments()->where('status', 'awaiting')->count(),
                    'waiting-questions' => $user->questions()->where('status', 'awaiting')->count(),
                    'waiting-prefactors' => $user->prefactors()->where('status', 'waiting_payment')->where(function ($query) {
                        $query->whereNull('expired_at')
                            ->orWhere('expired_at', '>', now());
                    })->count(),
                ];
            }
        }

        /** cart item summary details */
        $consignmentItems = [];
        if (auth()->check()) {
            /** @var \App\Models\Order $order */
            $order = $user->orders()->where('status', 'awaiting')->first();

            // get order consignment
            $consignments = [];
            if ($order != null) {
                $consignments = $order->consignments()->with('consignmentItems')->get();
            }

            // add consignment items
            $consignmentItems = new Collection();
            foreach ($consignments as $consignment) {
                $consignmentItems = $consignmentItems->merge($consignment->consignmentItems()->get()->map(fn($item) => [
                    'id' => $item->id,
                    'count' => $item->count,
                    'price' => $item->price,
                    'inventory_id' => $item->inventory_id,
                    'get_full_count_price' => $item->get_full_count_price,
                    'product' => [
                        'id' => $item->product->id,
                        'title' => $item->product->title,
                        'slug' => $item->product->slug,
                        'get_images' => $item->product->get_images,
                        'id' => $item->product->id,
                    ],
                ]));
            }
        }

        /** user media library files */
        $files = null;
        if (auth()->check()) {
            if ($user->type == "owner" || $user->type == "admin" || $user->seller) {
                if (str_starts_with($request->route()->getName(), 'admin') || str_starts_with($request->route()->getName(), 'seller')) {
                    /**
                     * get files
                     * @var LengthAwarePaginator
                     * @var App\Models\User $user
                     */
                    $files = $user->files()->where('visibility', 'public')->when($request->input('search'), function ($query, $search) {
                        $query->where('id', 'like', "%{$search}%");
                    })->where('type', 'image');
                    if ($request->exists('newest') && $request->newest) {
                        $files = $files->orderBy('created_at', 'desc')->paginate(12, ['*'], 'mpage');
                    } else if ($request->exists('oldest') && $request->oldest) {
                        $files = $files->orderBy('created_at', 'asc')->paginate(12, ['*'], 'mpage');
                    } else {
                        $files = $files->orderBy('created_at', 'desc')->paginate(12, ['*'], 'mpage');
                    }
                    $files->withQueryString();
                }
            }
        }

        /** active template */
        $template = Cache::remember('template', now()->addDay(), function () {
            return Template::where('status', 'active')->first();
        });
        $template = $template != null ? [
            'id' => $template->id,
            'header' => $template->header,
            'footer' => $template->footer,
            'get_top_banner' => $template->get_top_banner,
            'get_options' => $template->get_options,
            'get_data' => [
                'product' => $request->route()->getName() == "main.products.show" ? $template->get_data['product'] : null
            ],
            'get_blog_data' => [
                'article' => $request->route()->getName() == "blog.articles.show" ? $template->get_blog_data['article'] : null
            ],
            'status' => $template->status,
        ] : null;

        /** shop categories */
        $categories = null;
        if (!str_starts_with($request->route()->getName(), 'admin') && !str_starts_with($request->route()->getName(), 'seller')) {
            $categories = Cache::remember('main_categories', now()->addMonth(), function () {
                return ProductCategory::where('status', 'publish')->where('parent_id', 0)->get()->map(fn($catLevel1) => [
                    'id' => $catLevel1->id,
                    'title' => $catLevel1->title,
                    'slug' => $catLevel1->slug,
                    'childs' => ProductCategory::where('status', 'publish')->where('parent_id', $catLevel1->id)->get()->map(fn($catLevel2) => [
                        'id' => $catLevel2['id'],
                        'title' => $catLevel2['title'],
                        'slug' => $catLevel2['slug'],
                        'childs' => ProductCategory::where('status', 'publish')->where('parent_id', $catLevel2->id)->get()->map(fn($catLevel3) => [
                            'id' => $catLevel3['id'],
                            'title' => $catLevel3['title'],
                            'slug' => $catLevel3['slug'],
                            'childs' => null
                        ])
                    ])
                ]);
            });
        }

        /** header main search widget informations */
        $mostViewedProductsOfWeek = [];
        $lastSearchList = [];
        $mostRepeatedSearch = [];
        if (!str_starts_with($request->route()->getName(), 'admin') && !str_starts_with($request->route()->getName(), 'seller')) {
            // header most viewed products of week data
            $mostViewedProductsOfWeek = Cache::remember('search_container_most_viewed_products', now()->addMinutes(10), function () {
                $productStatistics = Statistic::select('url', DB::raw('count(*) as total'))
                    ->where('service', 'product')
                    ->whereDate('created_at', '>=', Carbon::now()->subDays(10))->groupBy('url')->orderBy('total', 'desc')->limit(6)->get();

                $mostViewedProductsOfWeek = [];
                foreach ($productStatistics as $statistic) {
                    $product = Product::where('status', 'publish')->where('slug', urldecode(str_replace('/product/', '', $statistic->url)))->first();
                    if ($product != null) {
                        $mostViewedProductsOfWeek[] = [
                            'id' => $product->id,
                            'title' => $product->title,
                            'slug' => $product->slug,
                            'get_images' => $product->get_images,
                            'in_stock_status' => $product->in_stock_status,
                            'inventory' => $product->inventory,
                            'best_price' => $product->best_price,
                        ];
                    }
                }

                return $mostViewedProductsOfWeek;
            });

            // header last_search_list data
            $lastSearchList = $request->session()->get('last_search_list');
            if ($lastSearchList != null && is_array($lastSearchList)) {
                $lastSearchList = array_reverse($lastSearchList);
            }

            // header most repeated search
            $mostRepeatedSearch = Cache::remember('most_repeated_search', now()->addMinutes(30), function () {
                return Search::select('keyword', DB::raw('COUNT(keyword) AS magnitude'))
                    ->groupBy('keyword')
                    ->orderBy('magnitude', 'DESC')
                    ->limit(6)->get()->map(fn($s) => ['keyword' => $s->keyword])->toArray();
            });
        }

        /** blade share */
        $bladeShares = [
            'favicon' => $this->getSetting('favicon', 'get_image'),
            'header_codes' => $this->getSetting('header_meta'),
            'footer_codes' => $this->getSetting('footer_meta'),
        ];
        try {
            $bladeShares['custom_css'] = $template != null ? $template['get_options']['style']['custom_css'] : null;
            $bladeShares['custom_js'] = $template != null ? $template['get_options']['style']['custom_js'] : null;
        } catch (Exception $e) {
        }
        View::share($bladeShares);

        // version
        $version = [];
        if (auth()->check()) {
            if ($user->type == "owner") {
                if (str_starts_with($request->route()->getName(), 'admin')) {
                    // check host file
                    $isHost = false;
                    if (file_exists(storage_path('host'))) $isHost = true;
                    $currentVersion = (float)file_get_contents(storage_path('version'));
                    $latestVersion = Cache::remember('check_latest_version', now()->addHour(), function () {
                        try {
                            $latestVersion = Http::timeout(6)->get('https://manage.vimascript.ir/version/number');
                            return (float)$latestVersion->body();
                        } catch (Exception $e) {
                            return 0.0;
                        }
                    });
                    $hasUpdate = $latestVersion > $currentVersion;

                    $version = [
                        'version' => $currentVersion,
                        'latest_version' => $latestVersion,
                        'has_update' => $hasUpdate,
                        'is_host' => $isHost,
                    ];
                }
            }
        }

        // return shared data
        return [
            ...parent::share($request),

            // platform settings
            'appUrl' => !app()->environment(['local', 'testing']) && request()->secure() ? str_replace('http://', 'https://', rtrim(asset(''), '/')) : rtrim(asset(''), '/'),
            'csrfToken' => csrf_token(),
            'dark' => $dark,
            'ziggy' => [
                ...(new Ziggy)->toArray(),
                'location' => !app()->environment(['local', 'testing']) && request()->secure() ? str_replace('http://', 'https://', $request->url()) :  $request->url(),
            ],
            'panelDetails' => [
                'name' => $this->getSetting('shop_title') != null && $this->getSetting('shop_title') != '' ? $this->getSetting('shop_title') : 'ویما',
                ...$version,
            ],
            "copyright" => file_exists(storage_path('copyright'))
                ? file_get_contents(storage_path('copyright'))
                : 'vima',
            'flash' => [
                'message' => fn() => $request->session()->get('message'),
                'add_to_cart' => fn() => $request->session()->get('add_to_cart'),
                'cart_error' => fn() => $request->session()->get('cart_error'),
                'wallet_charge_status' => fn() => $request->session()->get('wallet_charge_status'),
            ],
            'currentTimestamp' => Jalalian::forge(Carbon::now())->getTimestamp(),
            'currentRouteName' => $request->route()->getName(),
            'currentRouteParams' => collect($request->route()->parameters())->map(function ($value) {
                return $value instanceof \Illuminate\Database\Eloquent\Model
                    ? $value->getAttribute($value->getRouteKeyName())
                    : $value;
            })->toArray(),
            'currentUrl' => asset($request->getRequestUri()),
            'locale' => App::getLocale(),
            'keyword' => $request->exists('s') ? ['search' => $request->s] : $request->only(['search']),
            'neshan' => $neshan,
            'payment_meta' => $paymentMeta,
            'prefetch' => [
                'status' => false, // 'mount'
                'delay' => "10s",
            ],
            'appEnv' => env('APP_ENV'),

            // db main information and settings
            'appName' => $this->getSetting('shop_title'),
            'appFullName' => $this->getSetting('shop_full_title'),
            'appH1' => $this->getSetting('shop_h1'),
            'appDescription' => $this->getSetting('shop_description'),

            'blogName' => $this->getSetting('blog_title'),
            'blogDescription' => $this->getSetting('blog_description'),

            'appFavicon' => $this->getSetting('favicon', 'get_image'),
            'appLogo' => $this->getSetting('logo', 'get_image'),
            'appLogoDark' => $this->getSetting('logo_dark', 'get_image') != null ? $this->getSetting('logo_dark', 'get_image') : $this->getSetting('logo', 'get_image'),

            'responseTime' => $this->getSetting('response_time', 'value', __('messages.sentence.not_set')),
            'supportPhone' => $this->getSetting('support_phone'),
            'supportEmail' => $this->getSetting('support_email'),
            'shopAddress' => $this->getSetting('shop_address'),
            'shopAddressTown' => $this->getSetting('shop_address_town'),
            'shopAddressCity' => $this->getSetting('shop_address_city'),
            'shopAddressPostalCode' => $this->getSetting('shop_address_postal_code'),
            'shopMapLocation' => unserialize($this->getSetting('shop_map_location', 'value', serialize(["longitude" => 54.36281969540723, "latitude" => 32.69672648316882, "zoom" => 5.2]))),
            'socials' => [
                'instagram' => $this->getSetting('social_instagram'),
                'telegram' => $this->getSetting('social_telegram'),
                'twitter' => $this->getSetting('social_twitter'),
                'facebook' => $this->getSetting('social_facebook'),
                'whatsapp' => $this->getSetting('social_whatsapp'),
                'eita' => $this->getSetting('social_eita'),
                'rubika' => $this->getSetting('social_rubika'),
            ],
            'supportFloatingButton' => (bool)(int)$this->getSetting('support_floating_button'),
            'instagramSupport' => $this->getSetting('instagram_support'),
            'telegramPhone' => $this->getSetting('telegram_phone'),
            'whatsappPhone' => $this->getSetting('whatsapp_phone'),
            'staticPhone' => $this->getSetting('static_phone'),
            'mobilePhone' => $this->getSetting('mobile_phone'),

            'storeRegisterStatus' => $this->getSetting('store_register_status', 'value', false),
            'withdrawalLimit' => $this->getSetting('withdrawal_limit', 'value', 10000),

            'scriptPermissions' => [
                'samandehi' => $this->getSetting('script_samandehi'),
                'union' => $this->getSetting('script_union'),
                'enamad' => $this->getSetting('script_enamad'),
            ],

            // products settings
            'productStatisticsStatus' => $this->getSetting('product_statistics_status', 'value', '1'),

            // auth and panels data
            'auth' => [
                'user' => auth()->check() ? $user : null,
                'store' => auth()->check() && $user->seller ? $user->store : null,
                'wallet' => auth()->check() ? [
                    'amount' => $user->wallet->amount,
                    'get_formatted_amount' => $user->wallet->get_formatted_amount,
                ] : null,

                'can' => $gate,
                'sellerAccess' => auth()->check() ? $request->user()->can('seller-access') : false,

                'adminBadges' => $adminBadges,
                'sellerBadge' => $sellerBadges,
                'userBadge' => $userBadge,
            ],
            'notificationCount' => auth()->check() ? $user->notifications()->where('read_at', null)->count() : 0,

            // cart summary data
            'cart' => [
                'total_price' => count($consignmentItems) > 0 ? $consignmentItems->sum('get_full_count_price') : 0,
                'items' => $consignmentItems,
            ],

            // user media library
            'mediaLibrary' => [
                'maxUploadSize' => 50,
                'files' => $files
            ],

            // active template information
            'template' => $template,

            // categories
            'categories' => $categories,
            'categories_count' => ProductCategory::count(),

            // site menus
            'menu' => [
                'header_main' => $this->getMenu('header_main'),
                'footer_main' => $this->getMenu('footer_main'),
                'footer_menu_1' => $this->getMenu('footer_menu_1'),
                'footer_menu_2' => $this->getMenu('footer_menu_2'),
                //'footer_menu_3' => $this->getMenu('footer_menu_3'),
            ],

            // header main search widget informations
            'ui' => [
                'header' => [
                    'most_viewed_products_of_week' => $mostViewedProductsOfWeek,
                    'last_search_list' => $lastSearchList,
                    'most_repeated_search' => $mostRepeatedSearch,
                ],
            ],

            // last four product
            'random_four_products' => Product::where('status', 'publish')->inRandomOrder()->take(4)->get()->map(fn($product) => [
                'id' => $product->id,
                'title' => $product->title,
                'slug' => $product->slug,
                'get_images' => $product->get_images,
            ]),

            'product_most_viewed_hashtags' => ProductTag::where('status', 'publish')->orderBy('view_count', 'desc')->limit(5)->get()
        ];
    }

    /** override rootView */
    public function rootView(Request $request): string
    {
        if ($request->routeIs(['admin', 'admin.*', 'seller', 'seller.*'])) {
            return 'admin';
        } else if ($request->routeIs(['user', 'user.*'])) {
            return 'user';
        }

        return $this->rootView;
    }

    /**
     * get main settings from db
     */
    protected function getSetting($key, $value = 'value', $default = null)
    {
        return array_values(array_filter($this->settings, fn($i) => $i['key'] == $key))[0][$value] ?? $default;
    }

    /**
     * get main settings from db
     */
    protected function getMenu($key)
    {
        $menu = Cache::remember('menus-' . $key, now()->addMonth(), function () use ($key) {
            return Menu::where('place', $key)->first();
        });

        return $menu != null ? [
            'name' => $menu->name,
            'get_items' => $menu->get_items,
        ] : [];
    }
}
