// Kotleto · atoms (part 1): contexts, i18n, formatters

// Expose React hooks as globals so every <script type="text/babel"> file can use them
// without re-importing — each Babel script gets its own scope, so we hoist to window.
Object.assign(window, {
  createContext: React.createContext,
  useContext:    React.useContext,
  useState:      React.useState,
  useEffect:     React.useEffect,
  useMemo:       React.useMemo,
  useRef:        React.useRef,
  useCallback:   React.useCallback,
  useReducer:    React.useReducer,
  Fragment:      React.Fragment,
});
const { createContext, useContext, useState, useEffect, useMemo, useRef, useCallback } = React;

const LangContext = createContext({ lang: "fa", setLang: () => {} });
function useLang() { return useContext(LangContext); }

function L({ fa, en }) {
  const { lang } = useLang();
  return lang === "en" ? (en ?? fa) : (fa ?? en);
}
function pick(obj, lang) {
  if (!obj) return "";
  if (typeof obj === "string") return obj;
  return lang === "en" ? (obj.en ?? obj.fa) : (obj.fa ?? obj.en);
}

const FA_DIGITS = ["۰","۱","۲","۳","۴","۵","۶","۷","۸","۹"];
function toFa(s) { return String(s).replace(/[0-9]/g, d => FA_DIGITS[+d]); }
function toEn(s) { return String(s).replace(/[\u06F0-\u06F9]/g, d => String(FA_DIGITS.indexOf(d))); }
function formatPrice(n, lang) {
  const f = n.toLocaleString("en-US");
  return lang === "en" ? f : toFa(f);
}
function Price({ value, suffix }) {
  const { lang } = useLang();
  const sfx = suffix ?? (lang === "en" ? " T" : " تومن");
  return <span className="tnum">{formatPrice(value, lang)}<span style={{opacity:.6, fontWeight:500}}>{sfx}</span></span>;
}

// CART state
const CartContext = createContext(null);
function useCart() { return useContext(CartContext); }

const DELIVERY_DEFAULTS = { fee: 65000, freeFrom: 900000, minOrder: 250000, maxDistance: 8 };

// Shared read/write hook: initial JSON, imports and other tabs use the same state path.
function useStoredValue(key, fallback) {
  const fallbackRef = useRef(fallback);
  fallbackRef.current = fallback;
  const [value, setValue] = useState(() => LocalDB.get(key, fallback));
  useEffect(() => {
    const sync = db => setValue(db[key] ?? fallbackRef.current);
    const unsubscribe = LocalDB.subscribe(sync);
    sync(LocalDB.snapshot());
    return unsubscribe;
  }, [key]);
  const save = useCallback(nextOrUpdater => {
    const current = LocalDB.get(key, fallbackRef.current);
    const next = typeof nextOrUpdater === "function" ? nextOrUpdater(current) : nextOrUpdater;
    LocalDB.set(key, next);
    setValue(next);
    return next;
  }, [key]);
  return [value, save];
}

function useDeliveryConfig() {
  const [config, setConfig] = useState(() => ({ ...DELIVERY_DEFAULTS, ...LocalDB.get("deliveryConfig", {}) }));
  useEffect(() => {
    const sync = db => setConfig({ ...DELIVERY_DEFAULTS, ...(db.deliveryConfig || {}) });
    sync(LocalDB.snapshot());
    return LocalDB.subscribe(sync);
  }, []);
  return config;
}

function CartProvider({ children }) {
  const [items, setItems] = useStoredValue("cart", []);
  const [open, setOpen] = useState(false);
  const [promo, setPromo] = useStoredValue("cartPromo", "");

  const add = useCallback((item) => {
    setItems(prev => {
      const found = prev.find(i => i.id === item.id);
      if (found) return prev.map(i => i.id === item.id ? { ...i, ...item, qty: i.qty + 1 } : i);
      return [...prev, { ...item, qty: 1 }];
    });
  }, [setItems]);
  const remove = useCallback((id) => setItems(prev => prev.filter(i => i.id !== id)), [setItems]);
  const setQty = useCallback((id, qty) => setItems(prev => qty <= 0 ? prev.filter(i => i.id !== id) : prev.map(i => i.id === id ? { ...i, qty } : i)), [setItems]);
  const clear = useCallback(() => setItems([]), [setItems]);

  const subtotal = useMemo(() => items.reduce((s,i)=>s + i.price * i.qty, 0), [items]);
  const count    = useMemo(() => items.reduce((s,i)=>s + i.qty, 0), [items]);

  const applyPromo = useCallback((code) => {
    const normalized = String(code || "").trim().toUpperCase();
    const valid = PROMOS.some(p => p.code === normalized);
    if (valid) setPromo(normalized);
    return valid;
  }, [setPromo]);

  return <CartContext.Provider value={{ items, add, remove, setQty, clear, open, setOpen, subtotal, count, promo, setPromo, applyPromo }}>{children}</CartContext.Provider>;
}

function getCartTotals(subtotal, promo = "", deliveryConfig = DELIVERY_DEFAULTS) {
  const numberOrDefault = (value, fallback) => value !== "" && value != null && Number.isFinite(Number(value)) && Number(value) >= 0 ? Number(value) : fallback;
  const delivery = numberOrDefault(deliveryConfig.fee, 65000);
  const freeFrom = numberOrDefault(deliveryConfig.freeFrom, 900000);
  const minimumOrder = numberOrDefault(deliveryConfig.minOrder, 250000);
  let promoDiscount = 0;
  if (promo === "BAHAR15") promoDiscount = Math.round(subtotal * 0.15);
  if (promo === "GOLD24" && subtotal >= 700000) promoDiscount = Math.min(465000, subtotal);
  const deliveryDiscount = subtotal >= freeFrom || promo === "FREE20" ? delivery : 0;
  return { delivery, promoDiscount, deliveryDiscount, minimumOrder, total: Math.max(0, subtotal + delivery - promoDiscount - deliveryDiscount) };
}

const OrderContext = createContext(null);
function useOrder() { return useContext(OrderContext); }

function OrderProvider({ children }) {
  const fallbackOrder = useRef({
    id: "KT-4127",
    items: 3,
    total: 925000,
    placedAt: Date.now() - 8 * 60 * 1000,
    eta: 20 * 60 * 1000,
    status: "preparing",
    address: { fa: "شیراز · بلوار سرباز", en: "Shiraz · Sarbaz Boulevard" },
    courier: { fa: "رضا ملکی", en: "Reza M." }
  }).current;
  const [order, setOrder] = useState(() => LocalDB.get("activeOrder", fallbackOrder));
  const [statusOverride, setStatusOverride] = useState(() => LocalDB.get("adminOrderStatuses", {})[order.id]);
  useEffect(() => {
    const syncOrder = db => {
      const active = db.activeOrder || fallbackOrder;
      setOrder(active);
      setStatusOverride(db.adminOrderStatuses?.[active.id]);
    };
    syncOrder(LocalDB.snapshot());
    return LocalDB.subscribe(syncOrder);
  }, [fallbackOrder]);
  const place = useCallback((o) => {
    LocalDB.patch({ activeOrder: o, orders: [o, ...LocalDB.get("orders", [])] });
  }, []);
  return <OrderContext.Provider value={{ order, place, statusOverride }}>{children}</OrderContext.Provider>;
}

function notify(message, type = "success") {
  window.dispatchEvent(new CustomEvent("kotleto:toast", { detail: { message, type } }));
}

function ToastHost() {
  const [toast, setToast] = useState(null);
  useEffect(() => {
    let timer;
    const show = (event) => {
      clearTimeout(timer);
      setToast(event.detail);
      timer = setTimeout(() => setToast(null), 2600);
    };
    window.addEventListener("kotleto:toast", show);
    return () => { clearTimeout(timer); window.removeEventListener("kotleto:toast", show); };
  }, []);
  if (!toast) return null;
  return <div role="status" aria-live="polite" className="toast-host">{toast.message}</div>;
}

Object.assign(window, {
  L, pick, toFa, toEn, formatPrice, Price,
  useLang, LangContext, useStoredValue,
  CartProvider, useCart, OrderProvider, useOrder, useDeliveryConfig, getCartTotals,
  notify, ToastHost,
});
