// ====== Menu page ======
const DASHBOARD_FILTER_STORAGE_KEY_FOR_MENU_PAGE = "teaGangDashboardFiltersV1";
const readDashboardCategoryOrderForMenuPage = () => {
  try {
    const saved = JSON.parse(window.localStorage.getItem(DASHBOARD_FILTER_STORAGE_KEY_FOR_MENU_PAGE) || "{}");
    return Array.isArray(saved.reportCategoryOrder) ? saved.reportCategoryOrder.filter(Boolean) : [];
  } catch {
    return [];
  }
};

// Category manager modal — add / rename / delete categories
const CategoryManagerModal = ({ cats, items, onClose, onSave }) => {
  const [draft, setDraft] = React.useState(cats);
  const [newLabel, setNewLabel] = React.useState("");
  const [saving, setSaving] = React.useState(false);
  const [dialog, setDialog] = React.useState(null);

  const slug = (s) => s.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");

  const renameAt = (idx, label) => {
    setDraft(prev => prev.map((c, i) => i === idx ? { ...c, label } : c));
  };
  const removeAt = (idx) => {
    const target = draft[idx];
    if (target.id === "all") return;
    const doRemove = () => setDraft(prev => prev.filter((_, i) => i !== idx));
    if (items.some(it => it.cat === target.id)) {
      setDialog({ title: "Remove category?", message: `"${target.label}" has drinks in it. They will become uncategorized.`, confirmLabel: "Remove anyway", onConfirm: doRemove });
    } else {
      doRemove();
    }
  };
  const moveAt = (idx, dir) => {
    const i2 = idx + dir;
    if (i2 < 1 || i2 >= draft.length) return; // keep "all" pinned at 0
    setDraft(prev => {
      const next = [...prev];
      [next[idx], next[i2]] = [next[i2], next[idx]];
      return next;
    });
  };
  const add = () => {
    const label = newLabel.trim();
    if (!label) return;
    const id = slug(label);
    if (draft.some(c => c.id === id)) return;
    setDraft(prev => [...prev, { id, label, count: 0 }]);
    setNewLabel("");
  };
  const onKey = (e) => { if (e.key === "Enter") add(); };

  return (
    <React.Fragment>
      <div className="modal-scrim open" onClick={onClose}>
        <div className="modal edit-modal" onClick={e => e.stopPropagation()} style={{ maxWidth: 560 }}>
          <div className="modal-left edit-pane">
            <div className="modal-head">
              <div>
                <div style={{ fontFamily: "var(--font-script)", color: "var(--gold-600)", fontSize: 18, lineHeight: 1 }}>
                  Menu sections
                </div>
                <h2>Manage categories</h2>
                <div className="sub">{draft.filter(c => c.id !== "all").length} categories · used to group drinks on the menu</div>
              </div>
              <button className="icon-btn" onClick={onClose}><Ic name="x" /></button>
            </div>

            <div className="modal-body" style={{ display: "flex", flexDirection: "column", gap: 14, minWidth: 0 }}>
              <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                {draft.map((c, i) => {
                  const isAll = c.id === "all";
                  const count = isAll ? items.length : items.filter(it => it.cat === c.id).length;
                  return (
                    <div key={c.id} className="cat-row">
                      <div style={{ display: "flex", flexDirection: "column", gap: 2, width: 18 }}>
                        <button
                          className="cat-arrow"
                          disabled={i <= 1}
                          onClick={() => moveAt(i, -1)}
                          title="Move up"
                        >▲</button>
                        <button
                          className="cat-arrow"
                          disabled={i === 0 || i === draft.length - 1}
                          onClick={() => moveAt(i, 1)}
                          title="Move down"
                        >▼</button>
                      </div>
                      {isAll ? (
                        <span className="cat-label-pinned">{c.label} <span className="muted" style={{ fontSize: 11 }}>· pinned</span></span>
                      ) : (
                        <input
                          className="cat-input"
                          value={c.label}
                          onChange={e => renameAt(i, e.target.value)}
                        />
                      )}
                      <span className="cat-count">{count} drink{count !== 1 ? "s" : ""}</span>
                      {!isAll && (
                        <button
                          className="icon-btn"
                          style={{ width: 30, height: 30, color: "var(--rose-500)" }}
                          onClick={() => removeAt(i)}
                          title="Remove category"
                        ><Ic name="trash" size={13} /></button>
                      )}
                    </div>
                  );
                })}
              </div>

              <div className="edit-divider"><span>Add a new category</span></div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: 10 }}>
                <input
                  className="cat-input"
                  placeholder="e.g. Seasonal, Specials, Hot Drinks"
                  value={newLabel}
                  onChange={e => setNewLabel(e.target.value)}
                  onKeyDown={onKey}
                />
                <button className="btn btn-gold" onClick={add} disabled={!newLabel.trim()}>
                  <Ic name="plus" size={14} /> Add
                </button>
              </div>
            </div>

            <div className="modal-foot">
              <button className="btn btn-ghost" onClick={onClose} style={{ marginLeft: "auto" }}>Cancel</button>
              <button className="btn btn-primary" disabled={saving} onClick={async () => { setSaving(true); await onSave(draft); }}>
                {saving ? <><span className="btn-spinner" /> Saving…</> : <><Ic name="check" size={14} /> Save sections</>}
              </button>
            </div>
          </div>
        </div>
      </div>
      {dialog && <ConfirmDialog title={dialog.title} message={dialog.message} confirmLabel={dialog.confirmLabel} onConfirm={() => { setDialog(null); dialog.onConfirm(); }} onCancel={() => setDialog(null)} />}
    </React.Fragment>
  );
};

// Edit modal for a menu item
const MenuEditModal = ({ item, cats, items, onClose, onSave, onDelete, isNew = false }) => {
  const [draft, setDraft] = React.useState(item);
  const [imageFile, setImageFile] = React.useState(null);
  const [imagePreview, setImagePreview] = React.useState(item?.image_url || null);
  const [saving, setSaving] = React.useState(false);
  const [dialog, setDialog] = React.useState(null);
  React.useEffect(() => {
    setDraft(item);
    setImageFile(null);
    setImagePreview(item?.image_url || null);
    setSaving(false);
  }, [item]);
  if (!item || !draft) return null;

  const handleImagePick = (e) => {
    const file = e.target.files[0];
    if (!file) return;
    setImageFile(file);
    const reader = new FileReader();
    reader.onload = (ev) => setImagePreview(ev.target.result);
    reader.readAsDataURL(file);
  };

  const sizes = draft.sizes || [{ label: "No size", price: draft.price }];
  const setSize = (i, patch) => {
    const next = sizes.map((s, idx) => idx === i ? { ...s, ...patch } : s);
    setDraft({ ...draft, sizes: next, price: next[0]?.price ?? draft.price });
  };
  const SIZE_LABELS = ["No size", "S", "M", "L", "XL"];
  const addSize = () => {
    const used = new Set(sizes.map(s => s.label));
    const next = SIZE_LABELS.find(l => !used.has(l)) || SIZE_LABELS[0];
    setDraft({ ...draft, sizes: [...sizes, { label: next, price: 0 }] });
  };
  const removeSize = (i) => setDraft({ ...draft, sizes: sizes.filter((_, idx) => idx !== i) });

  const set = (patch) => setDraft({ ...draft, ...patch });
  const imageZoom = Number(draft.image_zoom || 1);

  return (
    <React.Fragment>
      <div className="modal-scrim open" onClick={onClose}>
        <div className="modal edit-modal" onClick={e => e.stopPropagation()}>
          <div className="modal-left edit-pane">
            <div className="modal-head">
              <div>
                <div style={{ fontFamily: "var(--font-script)", color: "var(--gold-600)", fontSize: 18, lineHeight: 1 }}>
                  {item.id === draft.id && item.name === draft.name ? "Editing" : "Editing"}
                </div>
                <h2>{draft.name || "Untitled drink"}</h2>
                <div className="sub">SKU <span className="mono">{draft.id}</span> · Updated just now</div>
              </div>
              <div className="row" style={{ gap: 8 }}>
                <span className={`tag ${draft.available ? "ready" : "cancelled"}`}>
                  <span className="tag-dot" /> {draft.available ? "Pouring" : "Resting"}
                </span>
                <button className="icon-btn" onClick={onClose}><Ic name="x" /></button>
              </div>
            </div>

            <div className="modal-body" style={{ display: "flex", flexDirection: "column", gap: 18, minWidth: 0 }}>
              {/* Hero / image */}
              <div style={{ display: "grid", gridTemplateColumns: "140px 1fr", gap: 16, minWidth: 0 }}>
                <label style={{
                  aspectRatio: "1/1",
                  borderRadius: "var(--r-lg)",
                  background: imagePreview ? "#fff" : "radial-gradient(circle at 50% 48%, rgba(251,247,236,0.96) 0 34%, rgba(234,217,171,0.34) 35% 58%, transparent 59%), repeating-linear-gradient(45deg, rgba(31,58,42,0.05) 0 8px, rgba(31,58,42,0.0) 8px 16px), linear-gradient(135deg, var(--cream-200), var(--cream-100))",
                  display: "grid", placeItems: "center",
                  border: "1px solid var(--line-soft)",
                  position: "relative", overflow: "hidden", cursor: "pointer",
                }}>
                  {imagePreview
                    ? imageFile
                      ? <img src={imagePreview} alt="" decoding="async" style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "contain", padding: 12, transform: `scale(${imageZoom})`, transformOrigin: "center" }} />
                      : <MenuCachedImage itemId={draft.id} imageUrl={imagePreview} alt="" loading="eager" style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "contain", padding: 12, transform: `scale(${imageZoom})`, transformOrigin: "center" }} />
                    : <div style={{
                      width: 76, height: 76, borderRadius: 999,
                      background: "var(--cream-50)",
                      border: "1px solid var(--line-gold)",
                      display: "grid", placeItems: "center",
                      fontFamily: "var(--font-display)", fontSize: 32, color: "var(--green-700)",
                      boxShadow: "0 0 0 6px rgba(251,247,236,0.6)",
                    }}>{draft.glyph}</div>
                  }
                  <div style={{
                    position: "absolute", bottom: 0, left: 0, right: 0,
                    background: "rgba(0,0,0,0.45)", color: "white",
                    fontSize: 11, fontWeight: 600, textAlign: "center", padding: "5px 0",
                  }}>
                    {imagePreview ? "Change photo" : "+ Add photo"}
                  </div>
                  <input type="file" accept="image/*" style={{ display: "none" }} onChange={handleImagePick} />
                </label>

                <div style={{ display: "flex", flexDirection: "column", gap: 12, minWidth: 0 }}>
                  <div className="field">
                    <label>Item name</label>
                    <input value={draft.name} onChange={e => set({ name: e.target.value })} />
                  </div>
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
                    <div className="field">
                      <label>Category</label>
                      <select value={draft.cat} onChange={e => set({ cat: e.target.value })}>
                        {(cats || []).filter(c => c.id !== "all").map(c => (
                          <option key={c.id} value={c.id}>{c.label}</option>
                        ))}
                      </select>
                    </div>
                    <div className="field">
                      <label>Tag</label>
                      <select value={draft.tag || ""} onChange={e => set({ tag: e.target.value || undefined })}>
                        <option value="">None</option>
                        <option>Signature</option>
                        <option>Bestseller</option>
                        <option>New</option>
                        <option>Limited</option>
                      </select>
                    </div>
                  </div>
                  <div className="field">
                    <label>Description</label>
                    <textarea
                      rows={3}
                      value={draft.desc}
                      onChange={e => set({ desc: e.target.value })}
                      style={{ resize: "vertical" }}
                    />
                  </div>
                </div>
              </div>

              {imagePreview && (
                <div className="cust-row image-zoom-row">
                  <label>Photo zoom</label>
                  <div className="image-zoom-control">
                    <input
                      type="range"
                      min="0.5"
                      max="2"
                      step="0.05"
                      value={imageZoom}
                      onChange={e => set({ image_zoom: Number(e.target.value) })}
                    />
                    <span>{Math.round(imageZoom * 100)}%</span>
                  </div>
                </div>
              )}

              <div className="edit-divider"><span>Sizes &amp; pricing</span></div>

              <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                {sizes.map((s, i) => (
                  <div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 110px 32px", gap: 8, alignItems: "center", minWidth: 0 }}>
                    <select
                      value={s.label}
                      onChange={e => setSize(i, { label: e.target.value })}
                      style={{ padding: "9px 12px", background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: "var(--r-md)", fontSize: 13, outline: "none", width: "100%", color: "var(--ink-800)" }}
                    >
                      {["No size", "S", "M", "L", "XL"].map(opt => (
                        <option key={opt} value={opt}>{opt}</option>
                      ))}
                    </select>
                    <div style={{ display: "flex", alignItems: "center", gap: 0, background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: "var(--r-md)" }}>
                      <span style={{ padding: "0 10px", color: "var(--ink-500)", fontSize: 13 }}>$</span>
                      <input
                        type="number" step="0.25" min="0"
                        value={s.price}
                        onChange={e => setSize(i, { price: +e.target.value })}
                        style={{ padding: "9px 8px 9px 0", background: "transparent", border: "none", fontSize: 13, outline: "none", width: "100%", fontFamily: "var(--font-mono)" }}
                      />
                    </div>
                    <button
                      className="icon-btn"
                      onClick={() => removeSize(i)}
                      style={{ width: 32, height: 32, color: "var(--rose-500)" }}
                      title="Remove size"
                    ><Ic name="trash" size={14} /></button>
                  </div>
                ))}
                <button className="btn btn-ghost" onClick={addSize} style={{ alignSelf: "flex-start", marginTop: 4 }}>
                  <Ic name="plus" size={14} /> Add size
                </button>
              </div>

              <div className="edit-divider"><span>Options &amp; inventory</span></div>

              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
                <div className="opt-tile">
                  <div>
                    <div className="opt-tile-name">Sweetness levels</div>
                    <div className="opt-tile-sub">Lets guests pick a sugar %</div>
                  </div>
                  <span
                    className={`toggle ${draft.item_type !== "addon" && draft.sweetness_enabled !== false ? "on" : ""}`}
                    onClick={() => draft.item_type !== "addon" && set({ sweetness_enabled: draft.sweetness_enabled === false })}
                  />
                </div>
                <div className="opt-tile">
                  <div>
                    <div className="opt-tile-name">Ice levels</div>
                    <div className="opt-tile-sub">Lets guests pick ice amount</div>
                  </div>
                  <span
                    className={`toggle ${draft.item_type !== "addon" && draft.ice_enabled !== false ? "on" : ""}`}
                    onClick={() => draft.item_type !== "addon" && set({ ice_enabled: draft.ice_enabled === false })}
                  />
                </div>
                <div className="opt-tile">
                  <div>
                    <div className="opt-tile-name">Item type</div>
                    <div className="opt-tile-sub">Main drinks appear on the menu; add-ons attach to mains.</div>
                  </div>
                  <div className="seg" style={{ width: 160 }}>
                    <button className={draft.item_type !== "addon" ? "on" : ""} onClick={() => set({ item_type: "main" })}>Main</button>
                    <button className={draft.item_type === "addon" ? "on" : ""} onClick={() => set({ item_type: "addon", sweetness_enabled: false, ice_enabled: false, addon_item_ids: [], addons: [], included_addon_item_ids: [] })}>Add-on</button>
                  </div>
                </div>
              </div>

              <div className="edit-divider"><span>Compatible add-ons</span></div>

              <div className="opt-group" style={{ paddingBottom: 6 }}>
                {(items || []).filter(a => a.item_type === "addon" && a.id !== draft.id).map(a => {
                  const selectedAddOns = Array.isArray(draft.addon_item_ids) ? draft.addon_item_ids : (draft.addons || []);
                  const on = selectedAddOns.includes(a.id);
                  return (
                    <button
                      key={a.id}
                      className={`opt ${on ? "active" : ""}`}
                      onClick={() => {
                        const cur = selectedAddOns;
                        const next = on ? cur.filter(x => x !== a.id) : [...cur, a.id];
                        const included = (draft.included_addon_item_ids || []).filter(id => id !== a.id);
                        set({ addon_item_ids: next, addons: next, included_addon_item_ids: included });
                      }}
                    >
                      {on && <Ic name="check" size={11} />} {a.name}
                      <span className="opt-price">+${a.price.toFixed(2)}</span>
                    </button>
                  );
                })}
              </div>

              <div className="edit-divider"><span>Included default add-ons</span></div>

              <div className="opt-group" style={{ paddingBottom: 6 }}>
                {(items || []).filter(a => a.item_type === "addon" && a.id !== draft.id).map(a => {
                  const selectedIncluded = Array.isArray(draft.included_addon_item_ids) ? draft.included_addon_item_ids : [];
                  const on = selectedIncluded.includes(a.id);
                  return (
                    <button
                      key={a.id}
                      className={`opt ${on ? "active" : ""}`}
                      onClick={() => {
                        const cur = selectedIncluded;
                        const next = on ? cur.filter(x => x !== a.id) : [...cur, a.id];
                        const paid = (Array.isArray(draft.addon_item_ids) ? draft.addon_item_ids : (draft.addons || [])).filter(id => id !== a.id);
                        set({ included_addon_item_ids: next, addon_item_ids: paid, addons: paid });
                      }}
                    >
                      {on && <Ic name="check" size={11} />} {a.name}
                      <span className="opt-price">$0 hidden</span>
                    </button>
                  );
                })}
              </div>
            </div>

            <div className="modal-foot">
              {!isNew && (
                <button className="btn btn-ghost" style={{ color: "var(--rose-500)" }} onClick={() => setDialog({ title: "Delete item?", message: `Permanently delete "${item.name}"? This cannot be undone.`, confirmLabel: "Delete", onConfirm: () => onDelete(item.id) })}>
                  <Ic name="trash" size={14} /> Delete
                </button>
              )}
              <button
                className="btn btn-ghost"
                onClick={() => set({ available: !draft.available })}
                style={{ marginLeft: "auto" }}
              >
                {draft.available ? "Rest" : "Pour"}
              </button>
              <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
              <button className="btn btn-primary" disabled={saving} onClick={async () => { setSaving(true); await onSave(draft, imageFile); }}>
                {saving ? <><span className="btn-spinner" /> Saving…</> : <><Ic name="check" size={14} /> Save</>}
              </button>
            </div>
          </div>
        </div>
      </div>
      {dialog && <ConfirmDialog title={dialog.title} message={dialog.message} confirmLabel={dialog.confirmLabel} onConfirm={() => { setDialog(null); dialog.onConfirm(); }} onCancel={() => setDialog(null)} />}
    </React.Fragment>
  );
};

const Menu = () => {
  const [active, setActive] = React.useState("all");
  const [items, setItems] = React.useState([]);
  const [cats, setCats] = React.useState([{ id: "all", label: "All", count: 0 }]);
  const [view, setView] = React.useState(() => localStorage.getItem("menuView") || "grid");
  const [editingItem, setEditingItem] = React.useState(null);
  const [search, setSearch] = React.useState("");
  const [catModalOpen, setCatModalOpen] = React.useState(false);
  const [backendReady, setBackendReady] = React.useState(false);
  const [dialog, setDialog] = React.useState(null);
  const showConfirm = (title, message, onConfirm, confirmLabel = "Confirm") => setDialog({ title, message, onConfirm, confirmLabel });

  const loadMenu = React.useCallback(async () => {
    const backend = window.TeaGangBackend;
    if (!backend?.enabled) return;
    try {
      const data = await backend.fetchMenu();
      setItems(data.items);
      setCats(data.cats);
      setBackendReady(true);
    } catch (error) {
      console.error("Menu backend unavailable.", error);
      setItems([]);
      setCats([{ id: "all", label: "All", count: 0 }]);
      setBackendReady(false);
    }
  }, []);

  React.useEffect(() => { loadMenu(); }, [loadMenu]);

  const dashboardCategoryOrder = React.useMemo(readDashboardCategoryOrderForMenuPage, []);
  const categoryForMenuItem = React.useCallback((item) =>
    cats.find(c => c.id === item.cat) || { id: item.cat || "uncategorized", label: "Uncategorized", sort_order: 999999 },
  [cats]);
  const categoryRankForMenuItem = React.useCallback((item) => {
    const cat = categoryForMenuItem(item);
    const savedIndex = dashboardCategoryOrder.indexOf(cat.id);
    if (savedIndex !== -1) return savedIndex;
    const sortOrder = Number(cat.sort_order);
    return 100000 + (Number.isFinite(sortOrder) ? sortOrder : 999999);
  }, [categoryForMenuItem, dashboardCategoryOrder]);
  const sortMenuItemsByCategory = React.useCallback((list) =>
    [...list].sort((a, b) => {
      const catCmp = categoryRankForMenuItem(a) - categoryRankForMenuItem(b);
      if (catCmp !== 0) return catCmp;
      return (a.name || "").localeCompare(b.name || "");
    }),
  [categoryRankForMenuItem]);

  const baseVisible = sortMenuItemsByCategory(active === "all" ? items : items.filter(i => i.cat === active));
  const q = normalizeVi(search.trim());
  const visible = q
    ? baseVisible.filter(i => normalizeVi(i.name).includes(q) || normalizeVi(i.desc).includes(q))
    : baseVisible;

  const toggleAvailable = async (id) => {
    const item = items.find(i => i.id === id);
    setItems(prev => prev.map(i => i.id === id ? { ...i, available: !i.available } : i));
    try {
      await window.TeaGangBackend?.toggleMenuItemAvailability?.(item);
    } catch (error) {
      console.warn("Could not update availability.", error);
      setItems(prev => prev.map(i => i.id === id ? { ...i, available: item.available } : i));
    }
  };
  const applySavedItem = (item, originalId = item?.id) => {
    if (!item?.id) return;
    setItems(prev => {
      const exists = prev.some(i => i.id === originalId || i.id === item.id);
      const nextItems = exists
        ? prev.map(i => (i.id === originalId || i.id === item.id) ? { ...i, ...item } : i)
        : [item, ...prev];
      setCats(prevCats => prevCats.map(c => ({
        ...c,
        count: c.id === "all" ? nextItems.length : nextItems.filter(i => i.cat === c.id).length,
      })));
      return nextItems;
    });
  };
  const saveItem = async (draft, imageFile) => {
    try {
      const previousImageUrl = draft?.image_url || null;
      let saved = await window.TeaGangBackend?.saveMenuItem?.(draft);
      if (imageFile && saved?.id) {
        const imageUrl = await window.TeaGangBackend.uploadMenuItemImage(saved.id, imageFile);
        saved = await window.TeaGangBackend.saveMenuItem({ ...saved, image_url: imageUrl });
        if (previousImageUrl && previousImageUrl !== imageUrl) {
          await window.TeaGangBackend.deleteMenuImageUrl?.(previousImageUrl);
        }
      }
      applySavedItem(saved || draft, draft.id);
      setEditingItem(null);
      if (backendReady) loadMenu().catch(error => console.error("Could not refresh menu after save.", error));
    } catch (error) {
      console.error("Could not save menu item.", error);
      window.alert?.(`Could not save menu item: ${error.message || error}`);
    }
  };
  const deleteItem = async (id) => {
    try {
      await window.TeaGangBackend?.deleteMenuItem?.(id);
    } catch (error) {
      console.warn("Could not delete menu item from backend.", error);
    }
    setItems(prev => prev.filter(i => i.id !== id));
    setEditingItem(null);
  };
  const saveCategories = async (nextCats) => {
    try {
      const data = await window.TeaGangBackend?.saveCategories?.(nextCats, cats);
      if (data?.cats) setCats(data.cats);
      if (data?.items) setItems(data.items);
    } catch (error) {
      console.error("Could not save categories.", error);
    }
    setCatModalOpen(false);
  };


  return (
    <div>
      <div className="page-head">
        <div>
          <div className="page-eyebrow">Our menu</div>
          <h1 className="page-title">The Tea Cabinet</h1>
          <div className="page-meta" style={{ marginTop: 8 }}>
            <span className="ornament"></span>
            <span><b style={{ color: "var(--green-700)" }}>{items.filter(i => i.available).length}</b> drinks pouring · <b>{items.filter(i => !i.available).length}</b> resting · last updated 9:14 AM</span>
          </div>
        </div>
        <div className="row" style={{ gap: 10 }}>
          <div className="search" style={{ width: 220, margin: 0 }}>
            <Ic name="search" size={14} />
            <input placeholder="Search drinks…" value={search} onChange={e => setSearch(e.target.value)} />
          </div>
          <button className="btn btn-ghost"><Ic name="filter" /> Sort</button>
          <button className="btn btn-gold" onClick={() => setEditingItem({
            id: `new-${Date.now()}`,
            cat: cats.find(c => c.id !== "all")?.id || "",
            name: "", price: 0, glyph: "茶", desc: "", tag: undefined,
            available: true, sold: 0,
            sizes: [{ label: "No size", price: 0 }],
            image_zoom: 1,
            item_type: "main", sweetness_enabled: false, ice_enabled: false,
            stock_count: 0, addons: [], addon_item_ids: [], included_addon_item_ids: [],
          })}><Ic name="plus" /> New Item</button>
        </div>
      </div>

      <div className="menu-toolbar">
        {cats.map(c => (
          <button
            key={c.id}
            className={`chip ${active === c.id ? "active" : ""}`}
            onClick={() => setActive(c.id)}
          >
            {c.label}
            <span className="chip-count">{c.id === "all" ? items.length : items.filter(i => i.cat === c.id).length}</span>
          </button>
        ))}
        <button
          className="chip chip-add"
          onClick={() => setCatModalOpen(true)}
          title="Manage categories"
        >
          <Ic name="plus" size={11} /> Category
        </button>
        <div style={{ marginLeft: "auto" }} className="row" >
          <div className="row" style={{ background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: "var(--r-md)", padding: 3 }}>
            {[
              { id: "grid", label: "Cards" },
              { id: "list", label: "List" },
            ].map(v => (
              <button
                key={v.id}
                onClick={() => { setView(v.id); localStorage.setItem("menuView", v.id); }}
                style={{
                  padding: "5px 12px", fontSize: 12, borderRadius: 5,
                  background: view === v.id ? "var(--green-700)" : "transparent",
                  color: view === v.id ? "var(--cream-50)" : "var(--ink-700)",
                }}
              >{v.label}</button>
            ))}
          </div>
        </div>
      </div>

      {view === "grid" ? (
        <div className="menu-grid">
          {visible.map(m => (
            <div
              key={m.id}
              className="menu-card"
              style={{ opacity: m.available ? 1 : 0.7, cursor: "pointer" }}
              onClick={() => setEditingItem(m)}
            >
              <div className={`img ${m.image_url ? "has-image" : ""}`}>
                {m.image_url
                  ? <MenuCachedImage itemId={m.id} imageUrl={m.image_url} alt={m.name} style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "contain", padding: 14, transform: `scale(${Number(m.image_zoom || 1)})`, transformOrigin: "center" }} />
                  : <div className="img-emblem">{m.glyph}</div>
                }
                {m.tag && <span className="img-pill">{m.tag}</span>}
                {!m.available && (
                  <span className="img-pill" style={{ left: "auto", right: 10, background: "rgba(179,90,74,0.85)" }}>Sold out</span>
                )}
              </div>
              <div className="body">
                <div className="name">
                  <span>{m.name}</span>
                  <span className="price">${m.price.toFixed(2)}</span>
                </div>
                <div className="desc">{m.desc}</div>
              </div>
              <div className="foot">
                <span className="row" style={{ gap: 8 }} onClick={(e) => e.stopPropagation()}>
                  <span style={{ fontSize: 11 }}>{m.available ? "Pouring" : "Resting"}</span>
                  <span
                    className={`toggle ${m.available ? "on" : ""}`}
                    onClick={() => toggleAvailable(m.id)}
                  />
                </span>
              </div>
            </div>
          ))}
        </div>
      ) : (
        <div className="card">
          <table className="table">
            <thead>
              <tr>
                <th style={{ width: 60 }}></th>
                <th>Drink</th>
                <th>Category</th>
                <th className="num" style={{ textAlign: "right" }}>Price</th>
                <th>Status</th>
                <th style={{ width: 60 }}></th>
              </tr>
            </thead>
            <tbody>
              {visible.map(m => (
                <tr key={m.id} style={{ cursor: "pointer" }} onClick={() => setEditingItem(m)}>
                  <td>
                    <div className={`detail-thumb ${m.image_url ? "has-image" : ""}`} style={{ width: 38, height: 38, fontSize: 16, overflow: "hidden", position: "relative" }}>
                      {m.image_url
                        ? <MenuCachedImage itemId={m.id} imageUrl={m.image_url} alt={m.name} style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "contain", padding: 4, transform: `scale(${Number(m.image_zoom || 1)})`, transformOrigin: "center" }} />
                        : m.glyph}
                    </div>
                  </td>
                  <td>
                    <div style={{ fontFamily: "var(--font-display)", fontSize: 16, color: "var(--green-800)" }}>{m.name}</div>
                    <div className="muted" style={{ fontSize: 11.5 }}>{m.desc}</div>
                  </td>
                  <td>
                    <span className="tag">{cats.find(c => c.id === m.cat)?.label}</span>
                  </td>
                  <td className="num" style={{ textAlign: "right" }}>${m.price.toFixed(2)}</td>
                  <td onClick={(e) => e.stopPropagation()}>
                    <span className="row" style={{ gap: 8 }}>
                      <span className={`toggle ${m.available ? "on" : ""}`} onClick={() => toggleAvailable(m.id)} />
                      <span style={{ fontSize: 12 }}>{m.available ? "Pouring" : "Resting"}</span>
                    </span>
                  </td>
                  <td onClick={(e) => { e.stopPropagation(); setEditingItem(m); }}>
                    <button className="icon-btn" style={{ width: 30, height: 30 }}><Ic name="edit" size={14} /></button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {editingItem && (
        <MenuEditModal
          item={editingItem}
          isNew={!editingItem.id.match(/^[0-9a-f]{8}-[0-9a-f]{4}-/)}
          cats={cats}
          items={items}
          onClose={() => setEditingItem(null)}
          onSave={saveItem}
          onDelete={deleteItem}
        />
      )}

      {catModalOpen && (
        <CategoryManagerModal
          cats={cats}
          items={items}
          onClose={() => setCatModalOpen(false)}
          onSave={saveCategories}
        />
      )}

      {dialog && <ConfirmDialog title={dialog.title} message={dialog.message} confirmLabel={dialog.confirmLabel} onConfirm={() => { setDialog(null); dialog.onConfirm(); }} onCancel={() => setDialog(null)} />}
    </div>
  );
};

window.Menu = Menu;
