"use client";

import Link from "next/link";
import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
import { CART_STORAGE_KEY, calculateCart } from "@/lib/cart";
import type { CartItem, Dish } from "@/lib/types";
import { reachGoal } from "@/lib/analytics";

type CartContextValue = {
  ordersEnabled: boolean;
  items: CartItem[];
  count: number;
  orderComment: string;
  hydrated: boolean;
  addItem: (dishId: string) => void;
  updateQuantity: (dishId: string, quantity: number) => void;
  setOrderComment: (comment: string) => void;
  updatePriceSnapshots: (actual: { sbis_id: string; price: number; available?: boolean }[]) => void;
  removeItem: (dishId: string) => void;
  undoRemove: () => void;
  pendingRemoval: { item: CartItem; index: number; expiresAt: number } | null;
  clear: () => void;
  getDish: (dishId: string) => Dish | undefined;
};

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

export function CartProvider({ children, menuItems, ordersEnabled }: { children: React.ReactNode; menuItems: Dish[]; ordersEnabled: boolean }) {
  const [items, setItems] = useState<CartItem[]>([]);
  const [orderComment, setOrderCommentState] = useState("");
  const [hydrated, setHydrated] = useState(false);
  const [toast, setToast] = useState<string | null>(null);
  const [priceOverrides, setPriceOverrides] = useState<Record<string, number>>({});
  const [availabilityOverrides, setAvailabilityOverrides] = useState<Record<string, boolean>>({});
  const [pendingRemoval, setPendingRemoval] = useState<{ item: CartItem; index: number; token: number } | null>(null);
  const removalTimerRef = useRef<number | null>(null);

  useEffect(() => {
    const raw = window.localStorage.getItem(CART_STORAGE_KEY);
    if (raw) setItems(JSON.parse(raw) as CartItem[]);
    setOrderCommentState(window.localStorage.getItem("kiln-cart-comment-v1") || "");
    setHydrated(true);
  }, []);

  useEffect(() => {
    if (!hydrated) return;
    window.localStorage.setItem(CART_STORAGE_KEY, JSON.stringify(items));
  }, [hydrated, items]);

  useEffect(() => {
    if (hydrated) window.localStorage.setItem("kiln-cart-comment-v1", orderComment);
  }, [hydrated, orderComment]);

  useEffect(() => () => {
    if (removalTimerRef.current) window.clearTimeout(removalTimerRef.current);
  }, []);

  const value = useMemo<CartContextValue>(
    () => ({
      ordersEnabled,
      items,
      count: items.filter((item) => menuItems.some((dish) => dish.id === item.dishId)).length,
      orderComment,
      hydrated,
      addItem: (dishId) => {
        setItems((current) => {
          const existing = current.find((item) => item.dishId === dishId);
          const dish = menuItems.find((candidate) => candidate.id === dishId);
          if (!dish || !ordersEnabled || dish.temporarilyUnavailable || dish.alcohol || (dish.stockLeft !== null && dish.stockLeft !== undefined && (existing?.quantity || 0) >= dish.stockLeft)) {
            setToast(dish?.unavailableText || "Позиция сейчас недоступна");
            window.setTimeout(() => setToast(null), 2400);
            return current;
          }
          if (existing) {
            return current.map((item) => (item.dishId === dishId ? { ...item, quantity: item.quantity + 1 } : item));
          }
          return [...current, { dishId, quantity: 1, priceSnapshot: dish?.price }];
        });
        reachGoal("add_to_cart", { dishId });
        setToast("Добавлено в корзину");
        window.setTimeout(() => setToast(null), 2400);
      },
      updateQuantity: (dishId, quantity) => {
        const dish = menuItems.find((candidate) => candidate.id === dishId);
        const cappedQuantity = dish?.stockLeft !== null && dish?.stockLeft !== undefined ? Math.min(quantity, dish.stockLeft) : quantity;
        setItems((current) => current.flatMap((item) => (item.dishId === dishId ? (cappedQuantity > 0 ? [{ ...item, quantity: cappedQuantity }] : []) : [item])));
      },
      setOrderComment: (comment) => setOrderCommentState(comment.slice(0, 160)),
      updatePriceSnapshots: (actual) => {
        const bySbisId = new Map(actual.map((item) => [item.sbis_id, item]));
        const nextOverrides: Record<string, number> = {};
        const nextAvailability: Record<string, boolean> = {};
        menuItems.forEach((dish) => {
          const currentActual = dish.sbisId ? bySbisId.get(dish.sbisId) : undefined;
          if (currentActual) {
            nextOverrides[dish.id] = currentActual.price;
            if (currentActual.available !== undefined) nextAvailability[dish.id] = currentActual.available;
          }
        });
        setItems((current) => current.map((item) => {
          const dish = menuItems.find((candidate) => candidate.id === item.dishId);
          const currentActual = dish?.sbisId ? bySbisId.get(dish.sbisId) : undefined;
          return currentActual ? { ...item, priceSnapshot: currentActual.price } : item;
        }));
        setPriceOverrides((current) => ({ ...current, ...nextOverrides }));
        setAvailabilityOverrides((current) => ({ ...current, ...nextAvailability }));
      },
      removeItem: (dishId) => {
        setToast(null);
        setItems((current) => {
          const index = current.findIndex((item) => item.dishId === dishId);
          if (index < 0) return current;
          if (removalTimerRef.current) window.clearTimeout(removalTimerRef.current);
          const token = Date.now();
          setPendingRemoval({ item: current[index], index, token });
          removalTimerRef.current = window.setTimeout(() => {
            setPendingRemoval((pending) => pending?.token === token ? null : pending);
            removalTimerRef.current = null;
          }, 3000);
          return current.filter((item) => item.dishId !== dishId);
        });
        reachGoal("remove_from_cart", { dishId });
      },
      undoRemove: () => {
        if (!pendingRemoval) return;
        if (removalTimerRef.current) window.clearTimeout(removalTimerRef.current);
        const { item, index } = pendingRemoval;
        setItems((current) => {
          const existing = current.find((currentItem) => currentItem.dishId === item.dishId);
          if (existing) {
            return current.map((currentItem) => currentItem.dishId === item.dishId
              ? { ...currentItem, quantity: currentItem.quantity + item.quantity }
              : currentItem);
          }
          const restored = [...current];
          restored.splice(Math.min(index, restored.length), 0, item);
          return restored;
        });
        setPendingRemoval(null);
        removalTimerRef.current = null;
      },
      pendingRemoval: pendingRemoval ? { item: pendingRemoval.item, index: pendingRemoval.index, expiresAt: pendingRemoval.token + 3000 } : null,
      clear: () => { setItems([]); setOrderCommentState(""); }
      ,getDish: (dishId) => {
        const dish = menuItems.find((candidate) => candidate.id === dishId);
        const override = priceOverrides[dishId];
        const availability = availabilityOverrides[dishId];
        return dish && (override !== undefined || availability !== undefined)
          ? { ...dish, ...(override !== undefined ? { price: override } : {}), ...(availability !== undefined ? { temporarilyUnavailable: !availability } : {}) }
          : dish;
      }
    }),
    [hydrated, items, orderComment, pendingRemoval, menuItems, ordersEnabled, priceOverrides, availabilityOverrides]
  );

  return (
    <CartContext.Provider value={value}>
      {children}
      {toast ? (
        <div className="fixed bottom-24 left-1/2 z-50 w-[calc(100%-32px)] max-w-sm -translate-x-1/2 rounded-lg border border-white/12 bg-kiln-graphite/96 p-3 shadow-ember backdrop-blur md:bottom-6 md:right-6 md:left-auto md:translate-x-0">
          <div className="flex items-center justify-between gap-3">
            <span className="text-sm">{toast}</span>
            {ordersEnabled ? <Link href="/cart" className="text-sm text-kiln-flame">
              Открыть
            </Link> : null}
          </div>
        </div>
      ) : null}
    </CartContext.Provider>
  );
}

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

export function useCartTotals() {
  const context = useCart();
  return calculateCart(context.items, context.items.map((item) => context.getDish(item.dishId)).filter((dish): dish is Dish => Boolean(dish)));
}
