"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";
import { CartLine, Product } from "./types";

const STORAGE_KEY = "sg_cart_v1";

export type CatalogEntry = Pick<
  Product,
  | "id"
  | "slug"
  | "name"
  | "brand"
  | "category"
  | "price"
  | "compareAtPrice"
  | "images"
  | "stock"
>;

type CartContextValue = {
  lines: CartLine[];
  catalog: CatalogEntry[];
  isOpen: boolean;
  openCart: () => void;
  closeCart: () => void;
  addItem: (productId: string, quantity?: number) => void;
  removeItem: (productId: string) => void;
  setQuantity: (productId: string, quantity: number) => void;
  clear: () => void;
  itemCount: number;
  subtotal: number;
};

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

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

  // Load from localStorage on mount
  useEffect(() => {
    try {
      const raw = window.localStorage.getItem(STORAGE_KEY);
      if (raw) setLines(JSON.parse(raw));
    } catch {
      // ignore corrupted storage
    }
    setHydrated(true);
  }, []);

  // Persist on change
  useEffect(() => {
    if (!hydrated) return;
    try {
      window.localStorage.setItem(STORAGE_KEY, JSON.stringify(lines));
    } catch {
      // storage unavailable, cart just won't persist across reloads
    }
  }, [lines, hydrated]);

  const findStock = useCallback(
    (productId: string) => catalog.find((p) => p.id === productId)?.stock ?? 0,
    [catalog]
  );

  const addItem = useCallback(
    (productId: string, quantity = 1) => {
      setLines((prev) => {
        const stock = findStock(productId);
        const existing = prev.find((l) => l.productId === productId);
        if (existing) {
          const nextQty = Math.min(existing.quantity + quantity, stock || 99);
          return prev.map((l) =>
            l.productId === productId ? { ...l, quantity: nextQty } : l
          );
        }
        return [...prev, { productId, quantity: Math.min(quantity, stock || 99) }];
      });
      setIsOpen(true);
    },
    [findStock]
  );

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

  const setQuantity = useCallback(
    (productId: string, quantity: number) => {
      if (quantity <= 0) {
        removeItem(productId);
        return;
      }
      const stock = findStock(productId);
      setLines((prev) =>
        prev.map((l) =>
          l.productId === productId
            ? { ...l, quantity: Math.min(quantity, stock || 99) }
            : l
        )
      );
    },
    [findStock, removeItem]
  );

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

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

  const subtotal = useMemo(
    () =>
      lines.reduce((sum, l) => {
        const product = catalog.find((p) => p.id === l.productId);
        return sum + (product?.price ?? 0) * l.quantity;
      }, 0),
    [lines, catalog]
  );

  const value: CartContextValue = {
    lines,
    catalog,
    isOpen,
    openCart: () => setIsOpen(true),
    closeCart: () => setIsOpen(false),
    addItem,
    removeItem,
    setQuantity,
    clear,
    itemCount,
    subtotal,
  };

  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;
}
