"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from "react";
import type { MedusaCart } from "@/lib/medusa";

const CART_ID_KEY = "trptk_cart_id";

async function apiJson<T>(url: string, init?: RequestInit): Promise<T> {
  const res = await fetch(url, {
    ...init,
    headers: { "Content-Type": "application/json", ...init?.headers },
  });
  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    const msg = body?.error ?? `Cart API error: ${res.status}`;
    console.error("[cart]", msg);
    throw new Error(msg);
  }
  return res.json();
}

type CartState = {
  cart: MedusaCart | null;
  isLoading: boolean;
  isAdding: boolean;
  itemCount: number;
  drawerOpen: boolean;
  setDrawerOpen: (open: boolean) => void;
  addItem: (variantId: string, quantity?: number) => Promise<void>;
  removeItem: (lineItemId: string) => Promise<void>;
  updateItem: (lineItemId: string, quantity: number) => Promise<void>;
  applyPromo: (code: string) => Promise<void>;
  removePromo: (code: string) => Promise<void>;
  resetCart: () => void;
};

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

export function CartProvider({ children }: { children: ReactNode }) {
  const [cart, setCart] = useState<MedusaCart | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isAdding, setIsAdding] = useState(false);
  const [drawerOpen, setDrawerOpen] = useState(false);

  // Restore cart from localStorage on mount
  useEffect(() => {
    async function restore() {
      const cartId = localStorage.getItem(CART_ID_KEY);
      if (cartId) {
        try {
          const existing = await apiJson<MedusaCart>(`/api/cart?id=${cartId}`);
          setCart(existing);
        } catch {
          localStorage.removeItem(CART_ID_KEY);
        }
      }
      setIsLoading(false);
    }
    restore();
  }, []);

  const ensureCart = useCallback(async (): Promise<string> => {
    if (cart?.id) return cart.id;
    const newCart = await apiJson<MedusaCart>("/api/cart", { method: "POST" });
    localStorage.setItem(CART_ID_KEY, newCart.id);
    setCart(newCart);
    return newCart.id;
  }, [cart?.id]);

  const addItem = useCallback(
    async (variantId: string, quantity = 1) => {
      setIsAdding(true);
      try {
        const cartId = await ensureCart();
        const updated = await apiJson<MedusaCart>(`/api/cart/${cartId}/items`, {
          method: "POST",
          body: JSON.stringify({ variant_id: variantId, quantity }),
        });
        setCart(updated);
        setDrawerOpen(true);
      } finally {
        setIsAdding(false);
      }
    },
    [ensureCart],
  );

  const removeItem = useCallback(
    async (lineItemId: string) => {
      if (!cart?.id) return;
      const updated = await apiJson<MedusaCart>(`/api/cart/${cart.id}/items/${lineItemId}`, {
        method: "DELETE",
      });
      setCart(updated);
    },
    [cart?.id],
  );

  const updateItem = useCallback(
    async (lineItemId: string, quantity: number) => {
      if (!cart?.id) return;
      if (quantity <= 0) {
        await removeItem(lineItemId);
        return;
      }
      const updated = await apiJson<MedusaCart>(`/api/cart/${cart.id}/items/${lineItemId}`, {
        method: "POST",
        body: JSON.stringify({ quantity }),
      });
      setCart(updated);
    },
    [cart?.id, removeItem],
  );

  const applyPromo = useCallback(
    async (code: string) => {
      if (!cart?.id) return;
      const updated = await apiJson<MedusaCart>(`/api/cart/${cart.id}/promotions`, {
        method: "POST",
        body: JSON.stringify({ code }),
      });
      setCart(updated);
    },
    [cart?.id],
  );

  const removePromo = useCallback(
    async (code: string) => {
      if (!cart?.id) return;
      const updated = await apiJson<MedusaCart>(`/api/cart/${cart.id}/promotions`, {
        method: "DELETE",
        body: JSON.stringify({ code }),
      });
      setCart(updated);
    },
    [cart?.id],
  );

  const resetCart = useCallback(() => {
    setCart(null);
    localStorage.removeItem(CART_ID_KEY);
  }, []);

  const itemCount = useMemo(
    () => cart?.items?.reduce((sum, item) => sum + item.quantity, 0) ?? 0,
    [cart?.items],
  );

  const value = useMemo<CartState>(
    () => ({
      cart,
      isLoading,
      isAdding,
      itemCount,
      drawerOpen,
      setDrawerOpen,
      addItem,
      removeItem,
      updateItem,
      applyPromo,
      removePromo,
      resetCart,
    }),
    [
      cart,
      isLoading,
      isAdding,
      itemCount,
      drawerOpen,
      setDrawerOpen,
      addItem,
      removeItem,
      updateItem,
      applyPromo,
      removePromo,
      resetCart,
    ],
  );

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