"use client";

import React, {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";

const STORAGE_KEY = "nizamify_shop_cart_v2";

export function makeCartLineKey(productId: string, variantSelections: Record<string, string>) {
  const keys = Object.keys(variantSelections).sort();
  const normalized: Record<string, string> = {};
  for (const k of keys) normalized[k] = String(variantSelections[k] ?? "").trim();
  return `${productId}::${JSON.stringify(normalized)}`;
}

export type CartLine = {
  key: string;
  productId: string;
  slug: string;
  title: string;
  image?: string;
  quantity: number;
  unitPrice: number;
  variantSelections: Record<string, string>;
  shippingPerUnit: number;
  /** Max units for this line (from PDP stock); caps merges and quantity edits. */
  availableStock?: number;
};

type CartContextValue = {
  lines: CartLine[];
  addLine: (line: Omit<CartLine, "key"> & { key?: string }) => void;
  removeLine: (key: string) => void;
  setQuantity: (key: string, qty: number) => void;
  clearCart: () => void;
  totalQuantity: number;
};

const CartContext = createContext<CartContextValue | null>(null);

export function CartProvider({ children }: { children: React.ReactNode }) {
  const [lines, setLines] = useState<CartLine[]>([]);
  const [hydrated, setHydrated] = useState(false);

  useEffect(() => {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      if (raw) {
        const parsed = JSON.parse(raw) as CartLine[];
        if (Array.isArray(parsed)) {
          setLines(
            parsed.filter((l) => l && typeof l.unitPrice === "number" && typeof l.quantity === "number"),
          );
        }
      }
    } catch {
      /* ignore */
    } finally {
      setHydrated(true);
    }
  }, []);

  useEffect(() => {
    if (!hydrated) return;
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(lines));
    } catch {
      /* ignore */
    }
  }, [lines, hydrated]);

  const addLine = useCallback((line: Omit<CartLine, "key"> & { key?: string }) => {
    const key = line.key ?? makeCartLineKey(line.productId, line.variantSelections);
    const incomingCap = line.availableStock ?? Number.MAX_SAFE_INTEGER;
    setLines((prev) => {
      const idx = prev.findIndex((l) => l.key === key);
      if (idx >= 0) {
        const next = [...prev];
        const prevLine = next[idx];
        const prevCap = prevLine.availableStock ?? Number.MAX_SAFE_INTEGER;
        const effectiveCap = Math.min(prevCap, incomingCap);
        const mergedQty = Math.min(prevLine.quantity + line.quantity, effectiveCap);
        next[idx] = {
          ...prevLine,
          quantity: Math.max(1, mergedQty),
          availableStock:
            effectiveCap < Number.MAX_SAFE_INTEGER ? effectiveCap : prevLine.availableStock,
        };
        return next;
      }
      const firstQty = Math.min(line.quantity, incomingCap);
      return [...prev, { ...line, key, quantity: Math.max(1, firstQty) }];
    });
  }, []);

  const removeLine = useCallback((key: string) => {
    setLines((prev) => prev.filter((l) => l.key !== key));
  }, []);

  const setQuantity = useCallback((key: string, qty: number) => {
    setLines((prev) =>
      prev.map((l) => {
        if (l.key !== key) return l;
        const cap = l.availableStock ?? Number.MAX_SAFE_INTEGER;
        const q = Math.max(1, Math.min(Math.floor(qty), cap));
        return { ...l, quantity: q };
      }),
    );
  }, []);

  const clearCart = useCallback(() => setLines([]), []);

  const totalQuantity = useMemo(
    () => lines.reduce((s, l) => s + l.quantity, 0),
    [lines],
  );

  const value = useMemo(
    () => ({
      lines,
      addLine,
      removeLine,
      setQuantity,
      clearCart,
      totalQuantity,
    }),
    [lines, addLine, removeLine, setQuantity, clearCart, totalQuantity],
  );

  return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
}

export function useCart() {
  const ctx = useContext(CartContext);
  if (!ctx) throw new Error("useCart must be used within CartProvider");
  return ctx;
}
