<?php

namespace App\Http\Controllers\Frontend;

use App\Http\Controllers\Controller;
use App\Models\ContactMessage;
use App\Models\FoodCart;
use App\Models\FoodMenuItem;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Product;
use App\Models\Reel;
use App\Models\Shop;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
use Illuminate\View\View;

class StorefrontController extends Controller
{
    public function index(Request $request): View
    {
        $shared = $this->frontendSharedData($request);
        $excludedShopNames = $this->excludedFrontShopNames();

        $shops = Shop::query()
            ->whereNotIn(DB::raw('LOWER(name)'), $excludedShopNames)
            ->whereHas('products', fn($query) => $query->available())
            ->with([
                'products' => fn($query) => $query->with('images')->latest(),
            ])
            ->withCount([
                'products as available_products_count' => fn($query) => $query->available(),
            ])
            ->latest()
            ->get();

        $reels = Schema::hasTable('reels')
            ? Reel::query()
            ->where('is_active', true)
            ->with('shop')
            ->latest()
            ->take(12)
            ->get()
            : collect();

        $facebookLiveShops = Schema::hasTable('reels')
            ? Shop::query()
            ->select(['id', 'name', 'slug', 'logo'])
            ->whereHas('reels', function ($query) {
                $query->where('is_active', true)
                    ->where(function ($videoQuery) {
                        $videoQuery->where('video_url', 'like', '%facebook.com%')
                            ->orWhere('video_url', 'like', '%fb.watch%');
                    });
            })
            ->withMax([
                'reels as live_views_max' => function ($query) {
                    $query->where('is_active', true)
                        ->where(function ($videoQuery) {
                            $videoQuery->where('video_url', 'like', '%facebook.com%')
                                ->orWhere('video_url', 'like', '%fb.watch%');
                        });
                },
            ], 'views')
            ->orderByDesc('live_views_max')
            ->orderBy('name')
            ->get()
            : collect();

        return view('welcome', array_merge($shared, [
            'shops' => $shops,
            'reels' => $reels,
            'facebookLiveShops' => $facebookLiveShops,
        ]));
    }

    public function shop(Request $request, Shop $shop): View
    {
        $shared = $this->frontendSharedData($request);

        $products = $shop->products()
            ->available()
            ->with('images')
            ->latest()
            ->get();

        return view('frontend.shop', array_merge($shared, [
            'shop' => $shop,
            'products' => $products,
        ]));
    }

    public function shopLanding(Request $request, Shop $shop): View
    {
        $shared = $this->frontendSharedData($request);

        $products = $shop->products()
            ->available()
            ->with('images')
            ->latest()
            ->get();

        $cart = $request->session()->get('cart', []);
        $cartTotal = collect($cart)->sum(function (array $item) {
            return ((float) $item['unit_price']) * ((int) $item['quantity']);
        });

        return view('frontend.shop-landing', array_merge($shared, [
            'shop'           => $shop,
            'products'       => $products,
            'cartTotal'      => $cartTotal,
            'cartItemsCount' => count($cart),
            'cartItems'      => $cart,   // ← passed so JS can boot sidebar
        ]));
    }

    public function productDetails(Request $request, Product $product): View
    {
        $shared = $this->frontendSharedData($request);

        if (! $product->isInStock()) {
            abort(404);
        }

        $product->load(['shop', 'images']);

        $relatedProducts = Product::query()
            ->where('shop_id', $product->shop_id)
            ->whereKeyNot($product->id)
            ->available()
            ->with('images')
            ->latest()
            ->take(8)
            ->get();

        return view('frontend.product-details', array_merge($shared, [
            'product'         => $product,
            'relatedProducts' => $relatedProducts,
            'hasOffer'        => $this->hasActiveOffer($product),
            'productImage'    => $this->resolveProductImage($product),
        ]));
    }

    /**
     * Add a product to the cart.
     * Returns JSON when the request expects it (AJAX), otherwise redirects.
     */
    public function addToCart(Request $request, Product $product): JsonResponse|RedirectResponse
    {
        $validated = $request->validate([
            'quantity' => ['nullable', 'integer', 'min:1'],
            'variant_label' => ['nullable', 'string', 'max:120'],
        ]);

        $product->loadMissing('shop', 'images');

        $variant = null;
        if ($product->hasVariantInventory()) {
            $variant = $product->findVariantOption($validated['variant_label'] ?? null);

            if (! $variant) {
                return $this->cartErrorResponse($request, 'Please select an available product variant.', 422);
            }
        }

        $availableStock = $variant['stock'] ?? $product->totalAvailableStock();

        if ($availableStock < 1) {
            return $this->cartErrorResponse($request, 'This product is currently out of stock.', 422);
        }

        $requestedQty  = (int) ($validated['quantity'] ?? 1);
        $quantityToAdd = min($requestedQty, (int) $availableStock);

        $cart = $request->session()->get('cart', []);

        $hasOffer  = $this->hasActiveOffer($product);
        $unitPrice = $hasOffer ? (float) $product->offer_price : (float) $product->price;
        $cartItemKey = $this->cartItemKey($product, $variant['key'] ?? null);

        $existingQty = (int) ($cart[$cartItemKey]['quantity'] ?? 0);
        $newQty      = min($existingQty + $quantityToAdd, (int) $availableStock);

        $cart[$cartItemKey] = [
            'cart_item_key' => $cartItemKey,
            'product_id'    => $product->id,
            'name'          => $product->product_title,
            'shop_name'     => optional($product->shop)->name,
            'variant_key'   => $variant['key'] ?? null,
            'variant_label' => $variant['label'] ?? null,
            'regular_price' => (float) $product->price,
            'offer_price'   => $hasOffer ? (float) $product->offer_price : null,
            'unit_price'    => $unitPrice,
            'quantity'      => $newQty,
            'stock'         => (int) $availableStock,
            'image'         => $this->resolveProductImage($product),
            'has_offer'     => $hasOffer,
        ];

        $request->session()->put('cart', $cart);

        if ($request->expectsJson()) {
            return response()->json([
                'success'  => true,
                'message'  => 'Product added to cart.',
                'cart'     => array_values($cart),
                'cartItem' => $cart[$cartItemKey],
            ]);
        }

        return back()->with('success', 'Product added to cart successfully.');
    }

    public function cart(Request $request): View
    {
        $shared = $this->frontendSharedData($request);

        $cart = $request->session()->get('cart', []);

        $total = collect($cart)->sum(function (array $item) {
            return ((float) $item['unit_price']) * ((int) $item['quantity']);
        });

        return view('frontend.cart', array_merge($shared, [
            'cartItems' => $cart,
            'total'     => $total,
        ]));
    }

    /**
     * Update a cart item quantity.
     * Returns JSON when the request expects it (AJAX), otherwise redirects.
     */
    public function updateCartQuantity(Request $request, Product $product): JsonResponse|RedirectResponse
    {
        $validated = $request->validate([
            'action' => ['required', 'in:increase,decrease'],
            'cart_item_key' => ['required', 'string'],
        ]);

        $cart = $request->session()->get('cart', []);
        $cartItemKey = $validated['cart_item_key'];

        if (! isset($cart[$cartItemKey]) || (int) ($cart[$cartItemKey]['product_id'] ?? 0) !== (int) $product->id) {
            return $this->cartErrorResponse($request, 'Cart item not found.', 404);
        }

        $variant = $product->findVariantOption($cart[$cartItemKey]['variant_label'] ?? null);
        $latestStock = $variant['stock'] ?? $product->totalAvailableStock();
        $stock = max(1, (int) ($latestStock > 0 ? $latestStock : ($cart[$cartItemKey]['stock'] ?? 1)));
        $currentQty = (int) ($cart[$cartItemKey]['quantity'] ?? 1);

        if ($validated['action'] === 'increase') {
            $nextQty = min($currentQty + 1, $stock);
        } else {
            $nextQty = max(1, $currentQty - 1);
        }

        $cart[$cartItemKey]['quantity'] = $nextQty;
        $cart[$cartItemKey]['stock'] = $stock;
        $request->session()->put('cart', $cart);

        if ($request->expectsJson()) {
            return response()->json([
                'success'  => true,
                'quantity' => $nextQty,
                'cart'     => array_values($cart),
            ]);
        }

        return back()->with('success', 'Cart quantity updated.');
    }

    public function reels(Request $request): View
    {
        $shared = $this->frontendSharedData($request);

        $reels = Schema::hasTable('reels')
            ? Reel::query()
            ->where('is_active', true)
            ->with('shop')
            ->latest()
            ->get()
            : collect();

        return view('frontend.reels', array_merge($shared, [
            'reels' => $reels,
        ]));
    }

    public function about(Request $request): View
    {
        $shared = $this->frontendSharedData($request);

        return view('frontend.about', $shared);
    }

    public function contact(Request $request): View
    {
        $shared = $this->frontendSharedData($request);

        return view('frontend.contact', $shared);
    }

    public function storeContactMessage(Request $request): RedirectResponse
    {
        $shared = $this->frontendSharedData($request);

        if (! Schema::hasTable('contact_messages')) {
            return back()->with('error', 'Contact message storage is not ready yet. Please run database migration.');
        }

        $validated = $request->validate([
            'name'    => ['required', 'string', 'max:120'],
            'email'   => ['required', 'email', 'max:255'],
            'phone'   => ['nullable', 'string', 'max:30'],
            'message' => ['required', 'string', 'max:2000'],
        ]);

        ContactMessage::create([
            'shop_id'  => data_get($shared, 'contactShop.id'),
            'name'     => $validated['name'],
            'email'    => $validated['email'],
            'phone'    => $validated['phone'] ?? null,
            'message'  => $validated['message'],
        ]);

        return back()->with('success', 'Thanks for your message. We will get in touch soon.');
    }

    public function incrementReelView(Reel $reel): JsonResponse
    {
        if (! $reel->is_active) {
            abort(404);
        }

        $reel->increment('views');

        return response()->json([
            'views' => (int) $reel->fresh()->views,
        ]);
    }

    private function frontendSharedData(Request $request): array
    {
        $cartCount = $this->cartCount($request);

        $navShops = Shop::query()
            ->select('id', 'name', 'slug')
            ->withCount([
                'products as available_products_count' => fn($query) => $query->available(),
            ])
            ->latest()
            ->take(8)
            ->get();

        $reels = Schema::hasTable('reels')
            ? Reel::query()
            ->where('is_active', true)
            ->with('shop')
            ->latest()
            ->take(12)
            ->get()
            : collect();

        $siteStats = [
            'shops'    => (int) Shop::count(),
            'products' => (int) Product::query()->available()->count(),
            'orders'   => (int) Order::count(),
            'reels'    => (int) $reels->count(),
        ];

        $contactShop = Shop::query()
            ->whereNotNull('contact')
            ->latest()
            ->first();

        $contactPayload = (array) ($contactShop?->contact ?? []);

        $phone = data_get($contactPayload, 'phone') ?: '+880 1XXXXXXXXX';
        $email = data_get($contactPayload, 'email') ?: 'support@shopsphere.com';
        $address = data_get($contactPayload, 'address') ?: 'Bangladesh';
        $workingHours = data_get($contactPayload, 'working_hours') ?: '10:00 AM - 9:00 PM';

        $contactData = [
            'title' => 'Contact Us',
            'subtitle' => 'We would love to hear from you. Get in touch with us anytime.',
            'intro' => data_get($contactPayload, 'intro') ?: 'Feel free to contact us for inquiries, support, or feedback. Our team will get back to you as soon as possible.',
            'shop_name' => $contactShop?->name ?: 'ShopSphere',
            'phone' => $phone,
            'email' => $email,
            'address' => $address,
            'working_hours' => $workingHours,
            'map_embed_url' => data_get($contactPayload, 'map_embed_url') ?: 'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3689.908850458656!2d91.8400065!3d22.357070300000004!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x30ad27656c600855%3A0xa4be32d307a83aee!2sBali%20Arcade!5e0!3m2!1sen!2sbd!4v1776424657140!5m2!1sen!2sbd',
        ];

        $footerData = [
            'about' => data_get($contactPayload, 'footer_about') ?: 'A refined marketplace offering quality goods across fashion, technology, groceries, and beauty.',
            'facebook' => data_get($contactPayload, 'facebook'),
            'instagram' => data_get($contactPayload, 'instagram'),
            'twitter' => data_get($contactPayload, 'twitter'),
            'youtube' => data_get($contactPayload, 'youtube'),
            'pinterest' => data_get($contactPayload, 'pinterest'),
            'support_email' => $email,
            'support_phone' => $phone,
            'support_address' => $address,
        ];

        return [
            'cartCount'   => $cartCount,
            'navShops'    => $navShops,
            'footerShops' => $navShops->take(5),
            'siteStats'   => $siteStats,
            'reels'       => $reels,
            'contactShop' => $contactShop,
            'contactData' => $contactData,
            'footerData'  => $footerData,
        ];
    }

    public function checkoutCod(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'customer_name' => ['required', 'string', 'max:255'],
            'phone'         => ['required', 'string', 'max:30'],
            'address'       => ['required', 'string', 'max:1000'],
            'notes'         => ['nullable', 'string', 'max:1000'],
        ]);

        $cart = $request->session()->get('cart', []);
        if (empty($cart)) {
            return redirect()->route('storefront.cart')->with('error', 'Your cart is empty.');
        }

        $result = DB::transaction(function () use ($cart, $validated, $request) {
            $productIds = array_map('intval', array_keys($cart));

            $products = Product::query()
                ->whereIn('id', $productIds)
                ->with('shop')
                ->lockForUpdate()
                ->get()
                ->keyBy('id');

            $orderItemsPayload = [];
            $total             = 0;

            foreach ($cart as $productId => $item) {
                $product = $products->get((int) ($item['product_id'] ?? $productId));
                if (! $product || $product->totalAvailableStock() < 1) {
                    continue;
                }

                $variant = null;
                $availableStock = $product->totalAvailableStock();
                $variantLabel = null;

                if ($product->hasVariantInventory()) {
                    $variant = $product->findVariantOption($item['variant_label'] ?? null);
                    if (! $variant || $variant['stock'] < 1) {
                        continue;
                    }

                    $availableStock = (int) $variant['stock'];
                    $variantLabel = $variant['label'];
                }

                $requestedQty = (int) ($item['quantity'] ?? 1);
                $quantity     = min($requestedQty, (int) $availableStock);
                if ($quantity < 1) {
                    continue;
                }

                $hasOffer  = $this->hasActiveOffer($product);
                $unitPrice = $hasOffer ? (float) $product->offer_price : (float) $product->price;
                $lineTotal = $unitPrice * $quantity;

                if ($variantLabel !== null) {
                    $product->decrementVariantStock($variantLabel, $quantity);
                } else {
                    $product->decrement('stock', $quantity);
                }

                $orderItemsPayload[] = [
                    'product_id'   => $product->id,
                    'product_name' => $product->product_title,
                    'shop_name'    => optional($product->shop)->name,
                    'variant_label' => $variantLabel,
                    'price'        => $unitPrice,
                    'quantity'     => $quantity,
                    'line_total'   => $lineTotal,
                ];

                $total += $lineTotal;
            }

            if (empty($orderItemsPayload)) {
                return ['order' => null];
            }

            $order = Order::create([
                'user_id'        => $request->user()?->id,
                'order_number'   => 'ORD-' . now()->format('YmdHis') . '-' . Str::upper(Str::random(4)),
                'customer_name'  => $validated['customer_name'],
                'phone'          => $validated['phone'],
                'address'        => $validated['address'],
                'payment_method' => 'cod',
                'status'         => 'pending',
                'total_amount'   => $total,
                'notes'          => $validated['notes'] ?? null,
            ]);

            foreach ($orderItemsPayload as $payload) {
                OrderItem::create([
                    'order_id' => $order->id,
                    ...$payload,
                ]);
            }

            return ['order' => $order];
        });

        if (! data_get($result, 'order')) {
            return redirect()->route('storefront.cart')->with('error', 'No items are currently available in stock.');
        }

        $request->session()->forget('cart');

        return redirect()->route('storefront.home')->with('success', 'COD order placed successfully.');
    }

    public function foodCarts(Request $request): View
    {
        $shared = $this->frontendSharedData($request);

        $foodCarts = FoodCart::query()
            ->where('is_active', true)
            ->withCount([
                'items as available_items_count' => fn($query) => $query->available(),
            ])
            ->latest()
            ->get();

        return view('frontend.food-carts-index', array_merge($shared, [
            'foodCarts' => $foodCarts,
        ]));
    }

    public function foodCartShow(Request $request, FoodCart $foodCart): View
    {
        if (! $foodCart->is_active) {
            abort(404);
        }

        $shared = $this->frontendSharedData($request);

        $items = $foodCart->items()
            ->available()
            ->latest()
            ->get();

        return view('frontend.food-cart-show', array_merge($shared, [
            'foodCart' => $foodCart,
            'items' => $items,
        ]));
    }

    public function searchFoodCartItems(Request $request, FoodCart $foodCart): JsonResponse
    {
        if (! $foodCart->is_active) {
            abort(404);
        }

        $term = trim((string) $request->string('q', ''));

        $items = FoodMenuItem::query()
            ->where('food_cart_id', $foodCart->id)
            ->available()
            ->when($term !== '', function ($query) use ($term) {
                $query->where(function ($innerQuery) use ($term) {
                    $innerQuery->where('title', 'like', "%{$term}%")
                        ->orWhere('description', 'like', "%{$term}%")
                        ->orWhere('search_tags', 'like', "%{$term}%");
                });
            })
            ->latest()
            ->limit(60)
            ->get();

        $payload = $items->map(function (FoodMenuItem $item) {
            return [
                'id' => $item->id,
                'title' => $item->title,
                'description' => $item->description,
                'price' => number_format((float) $item->price, 2),
                'image' => $item->image
                    ? asset('storage/' . ltrim($item->image, '/'))
                    : null,
                'tags' => (array) ($item->search_tags ?? []),
            ];
        })->values();

        return response()->json([
            'items' => $payload,
            'count' => $payload->count(),
        ]);
    }

    private function hasActiveOffer(Product $product): bool
    {
        if (is_null($product->offer_price) || $product->offer_price >= $product->price) {
            return false;
        }

        if (is_null($product->offer_expiry_date)) {
            return true;
        }

        return $product->offer_expiry_date->isFuture();
    }

    private function resolveProductImage(Product $product): string
    {
        if (! empty($product->feature_image)) {
            return Str::startsWith($product->feature_image, ['http://', 'https://'])
                ? $product->feature_image
                : asset('storage/' . $product->feature_image);
        }

        $galleryImage = optional($product->images->first())->image_path;
        if (! empty($galleryImage)) {
            return Str::startsWith($galleryImage, ['http://', 'https://'])
                ? $galleryImage
                : asset('storage/' . $galleryImage);
        }

        return 'https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=1200&q=80';
    }

    private function cartItemKey(Product $product, ?string $variantKey = null): string
    {
        $key = (string) $product->id;

        if ($variantKey === null || trim($variantKey) === '') {
            return $key;
        }

        return $key . ':' . trim($variantKey);
    }

    private function cartErrorResponse(Request $request, string $message, int $status): JsonResponse|RedirectResponse
    {
        if ($request->expectsJson()) {
            return response()->json(['error' => $message], $status);
        }

        return back()->with('error', $message);
    }

    private function cartCount(Request $request): int
    {
        return (int) collect($request->session()->get('cart', []))->sum('quantity');
    }

    private function excludedFrontShopNames(): array
    {
        return [
            'apple gadgets',
            'sayem shop',
        ];
    }

    //* terms and conditions page */
    public function terms(Request $request): View
    {
        return view('frontend.terms', $this->frontendSharedData($request));
    }

    //* return policy page */
    public function returns(Request $request): View
    {
        return view('frontend.returns', $this->frontendSharedData($request));
    }
}
