<?php

namespace App\Http\Controllers;

use App\Mail\NewOrderNotification;
use App\Mail\OrderConfirmation;
use App\Models\Order;
use App\Models\Product;
use App\Models\ProductCategory;
use App\Models\ShippingMethod;
use App\Services\CaptchaService;
use App\Services\CouponService;
use App\Services\FinalizeOrderPaymentService;
use App\Services\MailService;
use App\Services\StripeService;
use App\Services\ThemeService;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

class EcommerceController extends Controller
{
    public function __construct(
        protected ThemeService $themeService,
        protected StripeService $stripeService,
        protected CouponService $couponService,
        protected FinalizeOrderPaymentService $finalizeOrderPayment
    ) {}

    public function index(Request $request)
    {
        $categories = ProductCategory::with('children')->whereNull('parent_id')->orderBy('order')->orderBy('name')->get();
        $query = Product::where('is_active', true)->with('category');

        if ($request->filled('q')) {
            $q = $request->q;
            $query->where(function ($qry) use ($q) {
                $qry->where('name', 'like', "%{$q}%")
                    ->orWhere('description', 'like', "%{$q}%");
            });
        }

        $query = $this->applySort($query, $request->get('sort'));
        $products = $query->paginate(12)->withQueryString();

        return $this->themeService->render('ecommerce.index', [
            'categories' => $categories,
            'products' => $products,
        ]);
    }

    public function category(Request $request, string $slug)
    {
        $category = ProductCategory::where('slug', $slug)->with('children')->firstOrFail();
        $query = $category->children->isNotEmpty()
            ? $category->allProducts()
            : $category->products();
        $query = $query->where('is_active', true);

        if ($request->filled('q')) {
            $q = $request->q;
            $query->where(function ($qry) use ($q) {
                $qry->where('name', 'like', "%{$q}%")
                    ->orWhere('description', 'like', "%{$q}%");
            });
        }

        $query = $this->applySort($query, $request->get('sort'));
        $products = $query->paginate(12)->withQueryString();

        return $this->themeService->render('ecommerce.category', [
            'category' => $category,
            'products' => $products,
        ]);
    }

    protected function applySort($query, ?string $sort)
    {
        return match ($sort) {
            'price_asc' => $query->orderBy('price', 'asc')->orderBy('name', 'asc'),
            'price_desc' => $query->orderBy('price', 'desc')->orderBy('name', 'asc'),
            'name_asc' => $query->orderBy('name', 'asc'),
            'name_desc' => $query->orderBy('name', 'desc'),
            'newest' => $query->orderBy('created_at', 'desc')->orderBy('name', 'asc'),
            default => $query->orderBy('order')->orderBy('name', 'asc'),
        };
    }

    public function product(string $slug)
    {
        $product = Product::where('slug', $slug)->where('is_active', true)->with('category')->firstOrFail();
        return $this->themeService->render('ecommerce.product', [
            'product' => $product,
        ]);
    }

    public function cart()
    {
        $cart = session('cart', []);
        $productIds = array_keys($cart);
        $products = Product::whereIn('id', $productIds)->get()->keyBy('id');
        $items = [];
        $subtotal = 0;
        foreach ($cart as $id => $qty) {
            $product = $products->get($id);
            if ($product && $product->inStock()) {
                $items[] = ['product' => $product, 'qty' => $qty];
                $subtotal += $product->price * $qty;
            }
        }

        $discount = $this->couponService->getDiscountForCart($items);
        $total = max(0, $subtotal - $discount);
        $appliedCoupon = $this->couponService->getApplied();

        return $this->themeService->render('ecommerce.cart', [
            'items' => $items,
            'subtotal' => $subtotal,
            'discount' => $discount,
            'total' => $total,
            'appliedCoupon' => $appliedCoupon,
        ]);
    }

    public function applyCoupon(Request $request)
    {
        $request->validate(['code' => 'required|string|max:50']);

        $cart = session('cart', []);
        $productIds = array_keys($cart);
        $products = Product::whereIn('id', $productIds)->get()->keyBy('id');
        $items = [];
        foreach ($cart as $id => $qty) {
            $product = $products->get($id);
            if ($product && $product->inStock()) {
                $items[] = ['product' => $product, 'qty' => $qty];
            }
        }

        $result = $this->couponService->apply($request->code, $items);
        if ($result['valid']) {
            return redirect()->route('ecommerce.cart')->with('success', $result['message']);
        }
        return redirect()->route('ecommerce.cart')->withErrors(['coupon' => $result['message']]);
    }

    public function removeCoupon()
    {
        $this->couponService->remove();
        return redirect()->route('ecommerce.cart')->with('success', 'Code promo retiré.');
    }

    public function addToCart(Request $request)
    {
        $request->validate([
            'product_id' => 'required|exists:products,id',
            'qty' => 'nullable|integer|min:1|max:99',
        ]);

        $product = Product::findOrFail($request->product_id);
        if (! $product->is_active || ! $product->inStock()) {
            return back()->withErrors(['product' => 'Produit indisponible.']);
        }

        $cart = session('cart', []);
        $qty = $request->qty ?? 1;
        $cart[$product->id] = ($cart[$product->id] ?? 0) + $qty;

        if ($product->stock !== null) {
            $cart[$product->id] = min($cart[$product->id], $product->stock);
        }

        session(['cart' => $cart]);

        return redirect()->route('ecommerce.cart')->with('success', 'Produit ajouté au panier.');
    }

    public function updateCart(Request $request)
    {
        $request->validate([
            'items' => 'required|array',
            'items.*.id' => 'required|exists:products,id',
            'items.*.qty' => 'required|integer|min:0|max:99',
        ]);

        $cart = [];
        foreach ($request->items as $item) {
            if ($item['qty'] > 0) {
                $cart[$item['id']] = $item['qty'];
            }
        }
        session(['cart' => $cart]);

        return redirect()->route('ecommerce.cart')->with('success', 'Panier mis à jour.');
    }

    public function checkout()
    {
        $cart = session('cart', []);
        if (empty($cart)) {
            return redirect()->route('ecommerce.index')->with('info', 'Votre panier est vide.');
        }

        $productIds = array_keys($cart);
        $products = Product::whereIn('id', $productIds)->get()->keyBy('id');
        $items = [];
        $subtotal = 0;
        $totalWeight = 0;
        foreach ($cart as $id => $qty) {
            $product = $products->get($id);
            if ($product && $product->inStock()) {
                $items[] = ['product' => $product, 'qty' => $qty];
                $subtotal += $product->price * $qty;
                $totalWeight += ($product->weight_kg ?? 0.5) * $qty;
            }
        }

        if (empty($items)) {
            session()->forget('cart');
            return redirect()->route('ecommerce.index')->with('info', 'Votre panier est vide.');
        }

        $discount = $this->couponService->getDiscountForCart($items);
        $subtotalAfterDiscount = max(0, $subtotal - $discount);
        $appliedCoupon = $this->couponService->getApplied();

        $shippingMethods = ShippingMethod::where('is_active', true)->orderBy('order')->get();
        $mondialRelayEnseigne = \App\Models\Setting::get('mondial_relay_enseigne', 'BDTEST');

        return $this->themeService->render('ecommerce.checkout', [
            'items' => $items,
            'subtotal' => $subtotal,
            'discount' => $discount,
            'subtotalAfterDiscount' => $subtotalAfterDiscount,
            'totalWeight' => $totalWeight,
            'shippingMethods' => $shippingMethods,
            'appliedCoupon' => $appliedCoupon,
            'stripeConfigured' => $this->stripeService->isConfigured(),
            'mondialRelayEnseigne' => trim($mondialRelayEnseigne),
        ]);
    }

    public function createPaymentIntent(Request $request)
    {
        $request->validate(['order_id' => 'required|exists:orders,id']);
        $order = Order::findOrFail($request->order_id);
        $result = $this->stripeService->createPaymentIntent($order);
        return $result ? response()->json($result) : response()->json(['error' => 'Stripe non configuré'], 400);
    }

    public function payment(Order $order)
    {
        if ($order->status === 'paid') {
            return redirect()->route('ecommerce.order-confirmation', $order->id);
        }
        if (! $this->stripeService->isConfigured()) {
            return redirect()->route('ecommerce.order-confirmation', $order->id);
        }
        $intent = $this->stripeService->createPaymentIntent($order);
        if (! $intent) {
            return redirect()->route('ecommerce.order-confirmation', $order->id)->with('error', 'Erreur de paiement.');
        }
        return $this->themeService->render('ecommerce.payment', [
            'order' => $order,
            'clientSecret' => $intent['client_secret'],
            'publishableKey' => $intent['publishable_key'],
        ]);
    }

    public function placeOrder(Request $request)
    {
        $cart = session('cart', []);
        if (empty($cart)) {
            return redirect()->route('ecommerce.index')->with('info', 'Votre panier est vide.');
        }

        $rules = [
            'customer_name' => 'required|string|max:255',
            'customer_email' => 'required|email',
            'customer_phone' => 'nullable|string|max:50',
            'customer_address' => 'nullable|string|max:500',
            'customer_postal_code' => 'nullable|string|max:20',
            'customer_city' => 'nullable|string|max:100',
            'customer_country' => 'nullable|string|size:2',
            'shipping_method_id' => 'required|exists:shipping_methods,id',
            'shipping_relay_id' => 'nullable|string|max:50',
            'shipping_relay_label' => 'nullable|string|max:255',
            'notes' => 'nullable|string|max:1000',
        ];

        $shippingMethod = ShippingMethod::find($request->shipping_method_id);
        if ($shippingMethod && $shippingMethod->isMondialRelay()) {
            $rules['shipping_relay_id'] = 'required|string|max:50';
        }

        $captcha = app(CaptchaService::class);
        if ($captcha->shouldVerify(CaptchaService::CONTEXT_CHECKOUT)) {
            $result = $captcha->verifyRequest($request);
            if (! $result['ok']) {
                return back()->withErrors(['captcha' => $result['error'] ?? 'Captcha invalide.'])->withInput();
            }
        }

        $request->validate($rules);

        $productIds = array_keys($cart);
        $products = Product::whereIn('id', $productIds)->get()->keyBy('id');
        $orderItems = [];
        $subtotal = 0;
        $totalWeight = 0;

        foreach ($cart as $id => $qty) {
            $product = $products->get($id);
            if ($product && $product->inStock() && $qty > 0) {
                $orderItems[] = [
                    'product_id' => $product->id,
                    'name' => $product->name,
                    'price' => (float) $product->price,
                    'qty' => $qty,
                    'total' => (float) $product->price * $qty,
                ];
                $subtotal += $product->price * $qty;
                $totalWeight += ($product->weight_kg ?? 0.5) * $qty;
            }
        }

        if (empty($orderItems)) {
            session()->forget('cart');
            return redirect()->route('ecommerce.index')->with('info', 'Votre panier est vide.');
        }

        $cartItems = [];
        foreach ($cart as $id => $qty) {
            $product = $products->get($id);
            if ($product && $product->inStock() && $qty > 0) {
                $cartItems[] = ['product' => $product, 'qty' => $qty];
            }
        }
        $discount = $this->couponService->getDiscountForCart($cartItems);
        $subtotalAfterDiscount = max(0, $subtotal - $discount);
        $shippingMethod = $shippingMethod ?? ShippingMethod::findOrFail($request->shipping_method_id);
        $shippingCost = $shippingMethod->calculateCost($subtotalAfterDiscount, $totalWeight);
        $total = max(0, $subtotalAfterDiscount + $shippingCost);

        $appliedCoupon = $this->couponService->getApplied();
        $couponId = $appliedCoupon['id'] ?? null;
        $couponCode = $appliedCoupon['code'] ?? null;

        $order = Order::create([
            'number' => Order::generateNumber(),
            'customer_name' => $request->customer_name,
            'customer_email' => $request->customer_email,
            'customer_phone' => $request->customer_phone,
            'customer_address' => $request->customer_address,
            'customer_postal_code' => $request->customer_postal_code,
            'customer_city' => $request->customer_city,
            'customer_country' => $request->customer_country ?? 'FR',
            'shipping_method_id' => $shippingMethod->id,
            'shipping_cost' => $shippingCost,
            'shipping_relay_id' => $request->shipping_relay_id,
            'shipping_relay_label' => $request->shipping_relay_label,
            'subtotal' => $subtotal,
            'total' => $total,
            'status' => 'pending',
            'notes' => $request->notes,
            'items' => $orderItems,
            'coupon_id' => $couponId,
            'coupon_code' => $couponCode,
            'discount_amount' => $discount,
        ]);

        session()->forget('cart');
        session()->forget('coupon');

        if ($couponId) {
            \App\Models\Coupon::where('id', $couponId)->increment('used_count');
        }

        $mailService = app(MailService::class);
        if ($mailService->isConfigured()) {
            foreach ($mailService->getNotificationRecipientEmails() as $recipientEmail) {
                $mailService->send(new NewOrderNotification($order, $recipientEmail));
            }
        }

        if ($this->stripeService->isConfigured() && $total >= 0.50) {
            return redirect()->route('ecommerce.payment', $order);
        }

        foreach ($order->items as $item) {
            $product = Product::find($item['product_id'] ?? null);
            if ($product && $product->stock !== null) {
                $product->decrement('stock', $item['qty'] ?? 0);
            }
        }

        if ($mailService->isConfigured()) {
            $mailService->send(new OrderConfirmation($order));
        }

        return redirect()->route('ecommerce.order-confirmation', $order->id)
            ->with('success', 'Commande enregistrée. Numéro : ' . $order->number);
    }

    public function orderConfirmation(Order $order)
    {
        // Si le webhook Stripe n’a pas encore tourné (ou est injoignable), on finalise au chargement du retour 3DS / paiement.
        $this->finalizeOrderPayment->syncFromStripeIfPending($order);
        $order->refresh()->load('shippingMethod');

        return $this->themeService->render('ecommerce.order-confirmation', [
            'order' => $order,
        ]);
    }
}
