<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Coupon;
use App\Models\Order;
use App\Models\Product;
use App\Models\ProductCategory;
use App\Models\Setting;
use App\Models\ShippingMethod;
use App\Services\UploadedImageOptimizer;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class EcommerceController extends Controller
{
    public function __construct(
        protected UploadedImageOptimizer $imageOptimizer
    ) {}

    public function index()
    {
        $ordersCount = Order::count();
        $productsCount = Product::count();
        $recentOrders = Order::latest()->take(5)->get();

        $paidOrders = Order::whereIn('status', ['paid', 'shipped']);
        $totalRevenue = (float) $paidOrders->sum('total');
        $revenueThisMonth = (float) Order::whereIn('status', ['paid', 'shipped'])
            ->whereMonth('created_at', Carbon::now()->month)
            ->whereYear('created_at', Carbon::now()->year)
            ->sum('total');
        $ordersThisMonth = Order::whereIn('status', ['paid', 'shipped'])
            ->whereMonth('created_at', Carbon::now()->month)
            ->whereYear('created_at', Carbon::now()->year)
            ->count();
        $paidOrdersCount = Order::whereIn('status', ['paid', 'shipped'])->count();
        $avgOrderValue = $paidOrdersCount > 0 ? round($totalRevenue / $paidOrdersCount, 2) : 0;

        $ordersByStatus = Order::select('status', DB::raw('count(*) as count'))
            ->groupBy('status')
            ->pluck('count', 'status')
            ->toArray();

        $salesLast7Days = $this->buildDailySalesData(7);
        $salesLast30Days = $this->buildDailySalesData(30);

        $currency = Setting::get('ecommerce_currency', 'EUR');
        $currencySymbol = match ($currency) {
            'USD' => '$',
            'CHF' => 'CHF',
            default => '€',
        };

        return view('admin.ecommerce.index', compact(
            'ordersCount', 'productsCount', 'recentOrders',
            'totalRevenue', 'revenueThisMonth', 'ordersThisMonth', 'avgOrderValue',
            'ordersByStatus', 'salesLast7Days', 'salesLast30Days',
            'currencySymbol'
        ));
    }

    public function categories()
    {
        $categories = ProductCategory::with('parent', 'children')->withCount('products')->orderBy('order')->orderBy('name')->get();

        return view('admin.ecommerce.categories', compact('categories'));
    }

    public function storeCategory(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'parent_id' => 'nullable|exists:product_categories,id',
            'order' => 'nullable|integer|min:0',
        ]);
        ProductCategory::create([
            'name' => $request->name,
            'slug' => Str::slug($request->name).'-'.Str::random(4),
            'parent_id' => $request->parent_id,
            'order' => $request->order ?? 0,
        ]);

        return back()->with('success', 'Catégorie créée.');
    }

    public function updateCategory(Request $request, ProductCategory $productCategory)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'parent_id' => 'nullable|exists:product_categories,id',
            'order' => 'nullable|integer|min:0',
        ]);
        $productCategory->update([
            'name' => $request->name,
            'parent_id' => $request->parent_id,
            'order' => $request->order ?? 0,
        ]);

        return back()->with('success', 'Catégorie mise à jour.');
    }

    public function destroyCategory(ProductCategory $productCategory)
    {
        $productCategory->products()->update(['product_category_id' => null]);
        $productCategory->children()->update(['parent_id' => null]);
        $productCategory->delete();

        return back()->with('success', 'Catégorie supprimée.');
    }

    public function shippingMethods()
    {
        $methods = ShippingMethod::orderBy('order')->get();
        $apiStatus = $this->getCarrierApiStatus();

        return view('admin.ecommerce.shipping-methods', compact('methods', 'apiStatus'));
    }

    public function createShippingMethod()
    {
        return view('admin.ecommerce.shipping-method-form', ['method' => null]);
    }

    public function editShippingMethod(ShippingMethod $shippingMethod)
    {
        return view('admin.ecommerce.shipping-method-form', ['method' => $shippingMethod]);
    }

    protected function buildDailySalesData(int $days): array
    {
        $dateExpr = DB::getDriverName() === 'sqlite' ? 'date(created_at)' : 'DATE(created_at)';
        $raw = Order::whereIn('status', ['paid', 'shipped'])
            ->where('created_at', '>=', Carbon::now()->subDays($days)->startOfDay())
            ->select(DB::raw("{$dateExpr} as date"), DB::raw('SUM(total) as total'), DB::raw('COUNT(*) as count'))
            ->groupBy('date')
            ->orderBy('date')
            ->get()
            ->keyBy('date');

        $result = [];
        for ($i = $days - 1; $i >= 0; $i--) {
            $date = Carbon::now()->subDays($i)->format('Y-m-d');
            $row = $raw->get($date);
            $result[] = [
                'date' => $date,
                'label' => Carbon::parse($date)->locale('fr')->isoFormat('D MMM'),
                'total' => (float) ($row->total ?? 0),
                'count' => (int) ($row->count ?? 0),
            ];
        }

        return $result;
    }

    protected function getCarrierApiStatus(): array
    {
        $s = Setting::getGroup('ecommerce');

        return [
            'colissimo' => ! empty($s['colissimo_contract_number'] ?? '') && ! empty($s['colissimo_password'] ?? ''),
            'chronopost' => ! empty($s['chronopost_account_number'] ?? '') && ! empty($s['chronopost_password'] ?? ''),
            'mondial_relay' => ! empty($s['mondial_relay_enseigne'] ?? '') && ! empty($s['mondial_relay_private_key'] ?? ''),
            'laposte' => ! empty($s['laposte_okapi_key'] ?? ''),
        ];
    }

    public function storeShippingMethod(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'carrier' => 'required|in:colissimo,chronopost,mondial_relay,laposte,custom',
            'price' => 'required|numeric|min:0',
            'free_from' => 'nullable|numeric|min:0',
            'price_per_kg' => 'nullable|numeric|min:0',
            'order' => 'nullable|integer|min:0',
        ]);
        ShippingMethod::create([
            'name' => $request->name,
            'carrier' => $request->carrier,
            'price' => $request->price,
            'free_from' => $request->free_from,
            'price_per_kg' => $request->price_per_kg,
            'order' => (int) ($request->order ?? 0),
            'is_active' => $request->boolean('is_active', true),
        ]);

        return redirect()->route('admin.ecommerce.shipping-methods')->with('success', 'Méthode de livraison créée.');
    }

    public function updateShippingMethod(Request $request, ShippingMethod $shippingMethod)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'price' => 'required|numeric|min:0',
            'free_from' => 'nullable|numeric|min:0',
            'price_per_kg' => 'nullable|numeric|min:0',
            'order' => 'nullable|integer|min:0',
            'is_active' => 'boolean',
        ]);
        $shippingMethod->update([
            'name' => $request->name,
            'price' => $request->price,
            'free_from' => $request->free_from,
            'price_per_kg' => $request->price_per_kg,
            'order' => $request->order ?? 0,
            'is_active' => $request->boolean('is_active', true),
        ]);

        return redirect()->route('admin.ecommerce.shipping-methods')->with('success', 'Méthode de livraison mise à jour.');
    }

    public function destroyShippingMethod(ShippingMethod $shippingMethod)
    {
        $shippingMethod->delete();

        return back()->with('success', 'Méthode de livraison supprimée.');
    }

    public function products()
    {
        $products = Product::with('category')->orderBy('order')->orderBy('name')->paginate(20);

        return view('admin.ecommerce.products', compact('products'));
    }

    public function createProduct()
    {
        $categories = ProductCategory::with('children')->whereNull('parent_id')->orderBy('order')->orderBy('name')->get();

        return view('admin.ecommerce.product-form', ['product' => null, 'categories' => $categories]);
    }

    public function storeProduct(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'description' => 'nullable|string',
            'price' => 'required|numeric|min:0',
            'product_category_id' => 'nullable|exists:product_categories,id',
            'stock' => 'nullable|integer|min:0',
            'weight_kg' => 'nullable|numeric|min:0',
            'image_file' => 'nullable|image|max:20480',
            'gallery_files' => 'nullable|array',
            'gallery_files.*' => 'image|max:20480',
            'is_active' => 'boolean',
            'order' => 'nullable|integer|min:0',
        ]);

        $imagePath = null;
        if ($request->hasFile('image_file')) {
            $imagePath = $request->file('image_file')->store('products', 'public');
            $this->imageOptimizer->optimizeStoredFile($imagePath);
        }

        $gallery = [];
        foreach ($request->file('gallery_files', []) as $file) {
            if ($file && $file->isValid()) {
                $p = $file->store('products', 'public');
                $this->imageOptimizer->optimizeStoredFile($p);
                $gallery[] = $p;
            }
        }

        Product::create([
            'name' => $request->name,
            'slug' => Str::slug($request->name).'-'.Str::random(6),
            'description' => $request->description,
            'price' => $request->price,
            'product_category_id' => $request->product_category_id ?: null,
            'stock' => $request->filled('stock') ? $request->stock : null,
            'weight_kg' => $request->weight_kg,
            'image' => $imagePath,
            'gallery' => ! empty($gallery) ? $gallery : null,
            'is_active' => $request->boolean('is_active', true),
            'order' => $request->order ?? 0,
        ]);

        return redirect()->route('admin.ecommerce.products')->with('success', 'Produit créé.');
    }

    public function editProduct(Product $product)
    {
        $categories = ProductCategory::with('children')->whereNull('parent_id')->orderBy('order')->orderBy('name')->get();

        return view('admin.ecommerce.product-form', ['product' => $product, 'categories' => $categories]);
    }

    public function updateProduct(Request $request, Product $product)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'description' => 'nullable|string',
            'price' => 'required|numeric|min:0',
            'product_category_id' => 'nullable|exists:product_categories,id',
            'stock' => 'nullable|integer|min:0',
            'weight_kg' => 'nullable|numeric|min:0',
            'image_file' => 'nullable|image|max:20480',
            'gallery_files' => 'nullable|array',
            'gallery_files.*' => 'image|max:20480',
            'remove_gallery' => 'nullable|array',
            'remove_gallery.*' => 'string',
            'is_active' => 'boolean',
            'order' => 'nullable|integer|min:0',
        ]);

        $imagePath = $product->image;
        if ($request->hasFile('image_file')) {
            if ($product->image) {
                Storage::disk('public')->delete($product->image);
            }
            $imagePath = $request->file('image_file')->store('products', 'public');
            $this->imageOptimizer->optimizeStoredFile($imagePath);
        }

        $gallery = $product->galleryPaths();
        foreach ($request->input('remove_gallery', []) as $rm) {
            if (! is_string($rm) || $rm === '' || str_contains($rm, '..')) {
                continue;
            }
            if (in_array($rm, $gallery, true)) {
                Storage::disk('public')->delete($rm);
                $gallery = array_values(array_filter($gallery, fn ($p) => $p !== $rm));
            }
        }

        foreach ($request->file('gallery_files', []) as $file) {
            if ($file && $file->isValid()) {
                $p = $file->store('products', 'public');
                $this->imageOptimizer->optimizeStoredFile($p);
                $gallery[] = $p;
            }
        }

        $product->update([
            'name' => $request->name,
            'description' => $request->description,
            'price' => $request->price,
            'product_category_id' => $request->product_category_id ?: null,
            'stock' => $request->filled('stock') ? $request->stock : null,
            'weight_kg' => $request->weight_kg,
            'image' => $imagePath,
            'gallery' => ! empty($gallery) ? $gallery : null,
            'is_active' => $request->boolean('is_active', true),
            'order' => $request->order ?? 0,
        ]);

        return redirect()->route('admin.ecommerce.products')->with('success', 'Produit mis à jour.');
    }

    public function destroyProduct(Product $product)
    {
        $product->delete();

        return back()->with('success', 'Produit supprimé.');
    }

    public function orders()
    {
        $orders = Order::latest()->paginate(20);

        return view('admin.ecommerce.orders', compact('orders'));
    }

    public function showOrder(Order $order)
    {
        return view('admin.ecommerce.order', compact('order'));
    }

    public function updateOrderStatus(Request $request, Order $order)
    {
        $request->validate([
            'status' => 'required|in:pending,paid,shipped,cancelled',
        ]);
        $order->update(['status' => $request->status]);

        return back()->with('success', 'Statut mis à jour.');
    }

    public function coupons()
    {
        $coupons = Coupon::orderByDesc('created_at')->paginate(20);

        return view('admin.ecommerce.coupons', compact('coupons'));
    }

    public function createCoupon()
    {
        $products = Product::orderBy('name')->get();
        $categories = ProductCategory::with('children')->whereNull('parent_id')->orderBy('order')->orderBy('name')->get();

        return view('admin.ecommerce.coupon-form', ['coupon' => null, 'products' => $products, 'categories' => $categories]);
    }

    public function storeCoupon(Request $request)
    {
        $request->validate([
            'code' => 'required|string|max:50|unique:coupons,code',
            'type' => 'required|in:percent,fixed',
            'value' => 'required|numeric|min:0',
            'min_amount' => 'nullable|numeric|min:0',
            'max_uses' => 'nullable|integer|min:1',
            'valid_from' => 'nullable|date',
            'valid_until' => 'nullable|date|after_or_equal:valid_from',
            'is_active' => 'boolean',
            'description' => 'nullable|string|max:255',
            'scope_type' => 'required|in:all,products,categories',
            'scope_product_ids' => 'nullable|array',
            'scope_product_ids.*' => 'exists:products,id',
            'scope_category_ids' => 'nullable|array',
            'scope_category_ids.*' => 'exists:product_categories,id',
        ]);

        $data = $request->only(['code', 'type', 'value', 'min_amount', 'max_uses', 'valid_from', 'valid_until', 'description']);
        $data['code'] = strtoupper(trim($data['code']));
        $data['is_active'] = $request->boolean('is_active', true);
        $data['scope_type'] = $request->scope_type;
        $data['scope_ids'] = $request->scope_type === 'products'
            ? array_values(array_map('intval', $request->scope_product_ids ?? []))
            : ($request->scope_type === 'categories'
                ? array_values(array_map('intval', $request->scope_category_ids ?? []))
                : null);

        Coupon::create($data);

        return redirect()->route('admin.ecommerce.coupons')->with('success', 'Code promo créé.');
    }

    public function editCoupon(Coupon $coupon)
    {
        $products = Product::orderBy('name')->get();
        $categories = ProductCategory::with('children')->whereNull('parent_id')->orderBy('order')->orderBy('name')->get();

        return view('admin.ecommerce.coupon-form', ['coupon' => $coupon, 'products' => $products, 'categories' => $categories]);
    }

    public function updateCoupon(Request $request, Coupon $coupon)
    {
        $request->validate([
            'code' => 'required|string|max:50|unique:coupons,code,'.$coupon->id,
            'type' => 'required|in:percent,fixed',
            'value' => 'required|numeric|min:0',
            'min_amount' => 'nullable|numeric|min:0',
            'max_uses' => 'nullable|integer|min:1',
            'valid_from' => 'nullable|date',
            'valid_until' => 'nullable|date',
            'is_active' => 'boolean',
            'description' => 'nullable|string|max:255',
            'scope_type' => 'required|in:all,products,categories',
            'scope_product_ids' => 'nullable|array',
            'scope_product_ids.*' => 'exists:products,id',
            'scope_category_ids' => 'nullable|array',
            'scope_category_ids.*' => 'exists:product_categories,id',
        ]);

        $data = $request->only(['code', 'type', 'value', 'min_amount', 'max_uses', 'valid_from', 'valid_until', 'description']);
        $data['code'] = strtoupper(trim($data['code']));
        $data['is_active'] = $request->boolean('is_active', true);
        $data['scope_type'] = $request->scope_type;
        $data['scope_ids'] = $request->scope_type === 'products'
            ? array_values(array_map('intval', $request->scope_product_ids ?? []))
            : ($request->scope_type === 'categories'
                ? array_values(array_map('intval', $request->scope_category_ids ?? []))
                : null);

        $coupon->update($data);

        return redirect()->route('admin.ecommerce.coupons')->with('success', 'Code promo mis à jour.');
    }

    public function destroyCoupon(Coupon $coupon)
    {
        $coupon->delete();

        return back()->with('success', 'Code promo supprimé.');
    }

    public function settings()
    {
        $settings = array_merge([
            'stripe_key' => '',
            'stripe_secret' => '',
            'stripe_webhook_secret' => '',
            'laposte_okapi_key' => '',
            'colissimo_contract_number' => '',
            'colissimo_password' => '',
            'chronopost_account_number' => '',
            'chronopost_password' => '',
            'mondial_relay_enseigne' => '',
            'mondial_relay_private_key' => '',
            'mondial_relay_test_mode' => false,
            'ecommerce_currency' => 'EUR',
            'ecommerce_navbar_submenu' => true,
        ], Setting::getGroup('ecommerce'));
        $settings['mondial_relay_test_mode'] = ($settings['mondial_relay_test_mode'] ?? '0') === '1';
        $settings['ecommerce_navbar_submenu'] = ($settings['ecommerce_navbar_submenu'] ?? '1') !== '0';

        return view('admin.ecommerce.settings', compact('settings'));
    }

    public function storeSettings(Request $request)
    {
        $sensitive = ['stripe_secret', 'stripe_webhook_secret', 'laposte_okapi_key', 'colissimo_password', 'chronopost_password', 'mondial_relay_private_key'];
        $keys = [
            'stripe_key', 'stripe_secret', 'stripe_webhook_secret',
            'laposte_okapi_key',
            'colissimo_contract_number', 'colissimo_password',
            'chronopost_account_number', 'chronopost_password',
            'mondial_relay_enseigne', 'mondial_relay_private_key', 'mondial_relay_test_mode',
            'ecommerce_currency', 'ecommerce_navbar_submenu',
        ];
        foreach ($keys as $key) {
            $value = $request->input($key);
            if ($key === 'mondial_relay_test_mode' || $key === 'ecommerce_navbar_submenu') {
                $value = $request->boolean($key) ? '1' : '0';
            } elseif (in_array($key, $sensitive) && $value === '') {
                $existing = Setting::get($key);
                if ($existing) {
                    continue;
                }
            }
            Setting::set($key, $value ?? '', 'ecommerce');
        }

        return redirect()->route('admin.ecommerce.settings')->with('success', 'Paramètres enregistrés.');
    }
}
