// ====== Ingredient inventory + batch production ======
const INGREDIENT_UNITS = [
  {
    label: "Count",
    units: ["unit", "ct", "each", "piece", "serving", "bottle", "bag", "box", "case", "pack", "carton", "tray", "can", "jar", "tub", "roll", "sheet", "batch"],
  },
  {
    label: "Weight",
    units: ["mg", "g", "kg", "oz", "lb"],
  },
  {
    label: "Volume",
    units: ["mL", "L", "fl oz", "tsp", "tbsp", "cup", "pt", "qt", "gal"],
  },
];

const INGREDIENT_CATEGORIES = [
  "Liquid",
  "Dry",
  "Fresh",
  "Topping",
  "Packaging",
  "Supply",
  "Other",
];

const INGREDIENT_UNITS_BY_CATEGORY = {
  Liquid: ["mL", "L", "fl oz", "tsp", "tbsp", "cup", "pt", "qt", "gal", "bottle"],
  Dry: ["mg", "g", "kg", "oz", "lb", "bag", "box", "pack", "case"],
  Fresh: ["g", "kg", "oz", "lb", "each", "piece", "pack", "tray", "case"],
  Topping: ["mg", "g", "kg", "oz", "lb", "mL", "L", "tsp", "tbsp", "cup", "each", "serving", "pack"],
  Packaging: ["unit", "ct", "each", "piece", "bottle", "cup", "bag", "box", "case", "pack", "carton", "tray", "can", "jar", "tub", "roll", "sheet"],
  Supply: ["unit", "ct", "each", "piece", "bag", "box", "case", "pack", "carton", "roll", "sheet"],
  Other: INGREDIENT_UNITS.flatMap((group) => group.units),
};

const ingredientCategory = (category) =>
  INGREDIENT_CATEGORIES.includes(category) ? category : "Other";

const ingredientUnitOptions = (category) => {
  const allowed = new Set(INGREDIENT_UNITS_BY_CATEGORY[ingredientCategory(category)] || INGREDIENT_UNITS_BY_CATEGORY.Other);
  return INGREDIENT_UNITS
    .map((group) => ({
      ...group,
      units: group.units.filter((unit) => allowed.has(unit)),
    }))
    .filter((group) => group.units.length);
};

const defaultIngredientUnit = (category) =>
  ingredientUnitOptions(category)[0]?.units[0] || "unit";

const ingredientUnit = (category, unit) => {
  const normalizedCategory = ingredientCategory(category);
  const allowedUnits = INGREDIENT_UNITS_BY_CATEGORY[normalizedCategory] || INGREDIENT_UNITS_BY_CATEGORY.Other;
  return allowedUnits.includes(unit) ? unit : defaultIngredientUnit(normalizedCategory);
};

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

const Inventory = () => {
  const blankIngredient = {
    id: "",
    name: "",
    category: "Liquid",
    unit: "mL",
    par_quantity: 0,
    supplier: "",
    glyph: "",
    notes: "",
  };
  const blankStockAdjustment = {
    ingredientId: "",
    mode: "add",
    quantity: "",
    totalCost: "",
    supplier: "",
    notes: "",
  };
  const [loading, setLoading] = React.useState(true);
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState("");
  const [search, setSearch] = React.useState("");
  const [activeCat, setActiveCat] = React.useState("All");
  const [ingredients, setIngredients] = React.useState([]);
  const [menuItems, setMenuItems] = React.useState([]);
  const [recipes, setRecipes] = React.useState([]);
  const [batches, setBatches] = React.useState([]);
  const [movements, setMovements] = React.useState([]);
  const [ingredientDraft, setIngredientDraft] = React.useState(blankIngredient);
  const [stockAdjustment, setStockAdjustment] = React.useState(blankStockAdjustment);
  const [recipeMenuItemId, setRecipeMenuItemId] = React.useState("");
  const [recipeOutput, setRecipeOutput] = React.useState(50);
  const [recipeNotes, setRecipeNotes] = React.useState("");
  const [recipeLines, setRecipeLines] = React.useState([]);
  const [recipeDialogView, setRecipeDialogView] = React.useState("list");
  const [produceDraft, setProduceDraft] = React.useState({
    menuItemId: "",
    quantityMade: "",
    expiresAt: "",
    notes: "",
  });
  const [stockDrafts, setStockDrafts] = React.useState({});
  const [menuStockEdit, setMenuStockEdit] = React.useState(null);
  const [inventoryAction, setInventoryAction] = React.useState("");
  const [confirmDialog, setConfirmDialog] = React.useState(null);

  const backend = window.TeaGangBackend;
  const notify = (title, message, tone = "success") =>
    window.TeaGangNotify?.(title, message, tone);

  const money = (value) => `$${Number(value || 0).toFixed(2)}`;
  const qty = (value) => Number(value || 0).toLocaleString(undefined, {
    maximumFractionDigits: 3,
  });
  const unitCost = (lot) => Number(lot.unit_cost || 0);
  const ingredientValue = (ingredient) =>
    (ingredient.lots || []).reduce(
      (sum, lot) => sum + Number(lot.remaining_quantity || 0) * unitCost(lot),
      0,
    );
  const ingredientQty = (ingredient) => Number(ingredient.quantity_on_hand || 0);
  const stockPct = (ingredient) => {
    const par = Number(ingredient.par_quantity || 0);
    if (par <= 0) return ingredientQty(ingredient) > 0 ? 100 : 0;
    return Math.min(100, (ingredientQty(ingredient) / par) * 100);
  };
  const statusOf = (ingredient) => {
    const par = Number(ingredient.par_quantity || 0);
    if (par <= 0) return "ok";
    const pct = stockPct(ingredient);
    if (pct < 20) return "critical";
    if (pct < 50) return "low";
    return "ok";
  };

  const loadInventory = React.useCallback(async ({ silent = false } = {}) => {
    if (!backend?.fetchInventory) {
      setError("Inventory backend is not available. Apply the latest backend files and migration.");
      setLoading(false);
      return;
    }
    if (!silent) setLoading(true);
    setError("");
    try {
      const data = await backend.fetchInventory();
      setIngredients(data.ingredients || []);
      setMenuItems(data.menuItems || []);
      setRecipes(data.recipes || []);
      setBatches(data.batches || []);
      setMovements(data.movements || []);
      setStockDrafts({});
      if (!recipeMenuItemId && data.menuItems?.length) {
        const firstMain = data.menuItems.find((item) => item.item_type !== "addon") || data.menuItems[0];
        setRecipeMenuItemId(firstMain.id);
      }
    } catch (err) {
      console.error("Could not load inventory.", err);
      setError(err.message || "Could not load inventory.");
    } finally {
      if (!silent) setLoading(false);
    }
  }, [backend, recipeMenuItemId]);

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

  React.useEffect(() => {
    let disposed = false;
    let subscription;
    const refreshSoon = () => {
      if (!disposed) window.setTimeout(() => loadInventory({ silent: true }), 250);
    };
    backend?.subscribeToStoreData?.(refreshSoon, [
      "ingredients",
      "ingredient_lots",
      "ingredient_stock_movements",
      "menu_item_batch_recipes",
      "menu_item_batch_recipe_ingredients",
      "production_batches",
      "production_batch_ingredients",
      "ingredient_lot_consumptions",
      "product_stock_movements",
      "menu_items",
    ]).then((sub) => {
      if (disposed) sub?.unsubscribe?.();
      else subscription = sub;
    }).catch(() => {});
    return () => {
      disposed = true;
      subscription?.unsubscribe?.();
    };
  }, [backend, loadInventory]);

  const categories = React.useMemo(() => {
    const set = new Set(["All"]);
    ingredients.forEach((ingredient) => set.add(ingredient.category || "General"));
    return [...set];
  }, [ingredients]);

  const visibleIngredients = React.useMemo(() => {
    const q = normalizeVi(search.trim());
    return ingredients
      .filter((ingredient) => ingredient.is_active !== false)
      .filter((ingredient) => activeCat === "All" || ingredient.category === activeCat)
      .filter((ingredient) => {
        if (!q) return true;
        return [ingredient.name, ingredient.category, ingredient.supplier]
          .some((part) => normalizeVi(part || "").includes(q));
      })
      .sort((a, b) => {
        const statusRank = { critical: 0, low: 1, ok: 2 };
        return statusRank[statusOf(a)] - statusRank[statusOf(b)] || a.name.localeCompare(b.name);
      });
  }, [ingredients, activeCat, search]);

  const selectedRecipe = React.useMemo(
    () => recipes.find((recipe) => recipe.menu_item_id === recipeMenuItemId),
    [recipes, recipeMenuItemId],
  );

  const selectedRecipeMenuItem = React.useMemo(
    () => menuItems.find((item) => item.id === recipeMenuItemId),
    [menuItems, recipeMenuItemId],
  );

  const dashboardCategoryOrder = React.useMemo(readDashboardCategoryOrderForInventoryMenu, []);
  const sortedMenuItems = React.useMemo(() => {
    const rankFor = (item) => {
      const catId = item.cat || item.category_id || item.category || "uncategorized";
      const savedIndex = dashboardCategoryOrder.indexOf(catId);
      if (savedIndex !== -1) return savedIndex;
      const sortOrder = Number(item.category_sort_order);
      return 100000 + (Number.isFinite(sortOrder) ? sortOrder : 999999);
    };
    return [...menuItems].sort((a, b) => {
      const catCmp = rankFor(a) - rankFor(b);
      if (catCmp !== 0) return catCmp;
      return (a.name || "").localeCompare(b.name || "");
    });
  }, [menuItems, dashboardCategoryOrder]);

  React.useEffect(() => {
    if (!recipeMenuItemId) return;
    const recipe = recipes.find((item) => item.menu_item_id === recipeMenuItemId);
    setRecipeOutput(recipe?.batch_output_quantity || 50);
    setRecipeNotes(recipe?.notes || "");
    setRecipeLines(
      recipe?.lines?.length
        ? recipe.lines.map((line) => ({
            ingredient_id: line.ingredient_id,
            quantity_required: line.quantity_required,
          }))
        : [{ ingredient_id: "", quantity_required: "" }],
    );
  }, [recipeMenuItemId, recipes]);

  const totalValue = ingredients.reduce((sum, ingredient) => sum + ingredientValue(ingredient), 0);
  const critical = ingredients.filter((ingredient) => statusOf(ingredient) === "critical").length;
  const low = ingredients.filter((ingredient) => statusOf(ingredient) === "low").length;

  const runAction = async (title, action) => {
    setSaving(true);
    setError("");
    try {
      await action();
      await loadInventory({ silent: true });
      notify(title, "Inventory updated.");
      return true;
    } catch (err) {
      console.error(title, err);
      setError(err.message || "Inventory action failed.");
      notify(title, err.message || "Inventory action failed.", "error");
      return false;
    } finally {
      setSaving(false);
    }
  };

  const saveIngredient = () => runAction("Ingredient saved", async () => {
    const category = ingredientCategory(ingredientDraft.category);
    await backend.saveIngredient({
      ...ingredientDraft,
      category,
      unit: ingredientUnit(category, ingredientDraft.unit),
    });
    setIngredientDraft(blankIngredient);
    setInventoryAction("");
  });

  const removeIngredient = () => {
    if (!ingredientDraft.id) return;
    const name = ingredientDraft.name || "this ingredient";
    const ingredientId = ingredientDraft.id;
    setConfirmDialog({
      title: "Remove ingredient?",
      message: `Remove ${name}? It will be hidden from active ingredients and recipes, but history stays saved.`,
      confirmLabel: "Remove",
      onConfirm: () => runAction("Ingredient removed", async () => {
        if (!backend.archiveIngredient) throw new Error("Ingredient removal backend is not available.");
        await backend.archiveIngredient(ingredientId);
        setIngredientDraft(blankIngredient);
        setInventoryAction("");
      }),
    });
  };

  const editIngredient = (ingredient) => {
    const category = ingredientCategory(ingredient.category);
    setIngredientDraft({
      id: ingredient.id,
      name: ingredient.name || "",
      category,
      unit: ingredientUnit(category, ingredient.unit),
      par_quantity: ingredient.par_quantity || 0,
      supplier: ingredient.supplier || "",
      glyph: ingredient.glyph || "",
      notes: ingredient.notes || "",
    });
    setInventoryAction("ingredient");
  };

  const openStockAdjustment = (ingredient) => {
    setStockAdjustment({
      ingredientId: ingredient.id,
      mode: "add",
      quantity: "",
      totalCost: "",
      supplier: ingredient.supplier || "",
      notes: "",
    });
    setInventoryAction("stock");
  };

  const saveStockAdjustment = () => runAction("Ingredient stock updated", async () => {
    if (!backend.adjustIngredientStock) throw new Error("Inventory stock adjustment backend is not available.");
    await backend.adjustIngredientStock(stockAdjustment);
    setStockAdjustment((prev) => ({
      ...prev,
      quantity: "",
      totalCost: "",
      notes: "",
    }));
  });

  const saveRecipe = () => runAction("Recipe saved", async () => {
    await backend.saveBatchRecipe({
      menuItemId: recipeMenuItemId,
      batchOutputQuantity: recipeOutput,
      notes: recipeNotes,
      lines: recipeLines,
    });
    setInventoryAction("");
    setRecipeDialogView("list");
  });

  const openMenuStockEdit = (event, menuItem, mode) => {
    const rect = event.currentTarget.getBoundingClientRect();
    const width = 280;
    const height = 182;
    const margin = 12;
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth || width;
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight || height;
    const left = Math.max(margin, Math.min(rect.right - width, viewportWidth - width - margin));
    const aboveTop = rect.top - height - 8;
    const belowTop = rect.bottom + 8;
    const top = aboveTop >= margin
      ? aboveTop
      : Math.max(margin, Math.min(belowTop, viewportHeight - height - margin));
    setStockDrafts((prev) => ({
      ...prev,
      [menuItem.id]: mode === "modify" ? String(menuItem.stock_count || 0) : "",
    }));
    setMenuStockEdit({ item: menuItem, mode, top, left, width });
  };

  const setProductStock = (menuItem, mode) => runAction("Product stock updated", async () => {
    const current = Number(menuItem.stock_count || 0);
    const entered = Number(stockDrafts[menuItem.id] || 0);
    if (entered < 0) throw new Error("Stock number cannot be negative.");
    if (mode !== "modify" && entered <= 0) throw new Error("Enter a quantity greater than 0.");
    const next = mode === "add"
      ? current + entered
      : mode === "remove"
        ? Math.max(0, current - entered)
        : entered;
    await backend.setProductStockWithInventory({
      menuItemId: menuItem.id,
      stockCount: next,
      notes: `Inventory menu item stock ${mode}`,
      reflectIngredients: mode === "add",
    });
    setStockDrafts((prev) => ({ ...prev, [menuItem.id]: "" }));
  });

  const saveMenuStockEdit = async () => {
    if (!menuStockEdit) return;
    const saved = await setProductStock(menuStockEdit.item, menuStockEdit.mode);
    if (saved) setMenuStockEdit(null);
  };

  const costForRecipeLines = React.useCallback((lines) => {
    const ingredientMap = new Map(ingredients.map((ingredient) => [ingredient.id, ingredient]));
    return (lines || []).reduce((sum, line) => {
      const ingredient = ingredientMap.get(line.ingredient_id);
      const amount = Number(line.quantity_required || 0);
      if (!ingredient || amount <= 0) return sum;
      let remaining = amount;
      let cost = 0;
      for (const lot of ingredient.lots || []) {
        if (remaining <= 0) break;
        const use = Math.min(remaining, Number(lot.remaining_quantity || 0));
        cost += use * Number(lot.unit_cost || 0);
        remaining -= use;
      }
      return sum + cost;
    }, 0);
  }, [ingredients]);

  const recipeCostPreview = React.useMemo(
    () => costForRecipeLines(recipeLines),
    [costForRecipeLines, recipeLines],
  );

  const recipeCostByMenuItem = React.useMemo(() => {
    const costs = new Map();
    recipes.forEach((recipe) => {
      const output = Number(recipe.batch_output_quantity || 0);
      const batchCost = costForRecipeLines(recipe.lines || []);
      costs.set(recipe.menu_item_id, output > 0 ? batchCost / output : 0);
    });
    return costs;
  }, [costForRecipeLines, recipes]);

  const selectedStockIngredient = React.useMemo(
    () => ingredients.find((ingredient) => ingredient.id === stockAdjustment.ingredientId),
    [ingredients, stockAdjustment.ingredientId],
  );

  const stockAdjustmentCost = React.useMemo(() => {
    if (!selectedStockIngredient) return 0;
    if (stockAdjustment.mode === "remove") {
      let remaining = Number(stockAdjustment.quantity || 0);
      let cost = 0;
      for (const lot of selectedStockIngredient.lots || []) {
        if (remaining <= 0) break;
        const use = Math.min(remaining, Number(lot.remaining_quantity || 0));
        cost += use * Number(lot.unit_cost || 0);
        remaining -= use;
      }
      return cost;
    }
    return Number(stockAdjustment.totalCost || 0);
  }, [selectedStockIngredient, stockAdjustment.mode, stockAdjustment.quantity, stockAdjustment.totalCost]);

  const selectedStockActivity = React.useMemo(() => {
    const unit = selectedStockIngredient?.unit || "";
    const movementLabel = (type) => {
      if (type === "add") return "Added stock";
      if (type === "remove") return "Removed stock";
      if (type === "set") return "Modified stock";
      if (type === "consume") return "Used in batch";
      return "Adjusted stock";
    };
    const movements = [...(selectedStockIngredient?.stock_movements || [])]
      .sort((a, b) =>
        new Date(b.created_at || 0).getTime() -
        new Date(a.created_at || 0).getTime()
      );
    if (movements.length) {
      return movements.map((movement) => {
        const delta = Number(movement.quantity_delta || 0);
        const sign = movement.movement_type === "set"
          ? delta > 0 ? "+" : delta < 0 ? "-" : "="
          : delta >= 0 ? "+" : "-";
        const amount = movement.movement_type === "set" && delta === 0
          ? Number(movement.quantity_after || 0)
          : Math.abs(delta);
        return {
          id: movement.id,
          title: movementLabel(movement.movement_type),
          at: movement.created_at,
          supplier: movement.supplier,
          notes: movement.notes,
          tone: delta > 0 ? "added" : delta < 0 ? "removed" : "neutral",
          quantityText: `${sign} ${qty(amount)}${unit}`,
          moneyAmount: Math.abs(Number(movement.cost_delta || 0)),
          leftText: `${qty(movement.quantity_after || 0)}${unit} left`,
        };
      });
    }
    let runningLeft = 0;
    return [...(selectedStockIngredient?.lots || [])]
      .sort((a, b) =>
        new Date(a.received_at || a.created_at || 0).getTime() -
        new Date(b.received_at || b.created_at || 0).getTime()
      )
      .map((lot) => {
        runningLeft += Number(lot.received_quantity || 0);
        return {
          id: lot.id,
          title: "Added stock",
          at: lot.received_at || lot.created_at,
          supplier: lot.supplier,
          notes: lot.notes,
          tone: "added",
          quantityText: `+ ${qty(lot.received_quantity || 0)}${unit}`,
          moneyAmount: Number(lot.total_cost || 0),
          leftText: `${qty(runningLeft)}${unit} left`,
        };
      })
      .reverse();
  }, [selectedStockIngredient]);

  if (loading) {
    return (
      <div className="card" style={{ padding: 28 }}>
        Loading inventory...
      </div>
    );
  }

  return (
    <div>
      <div className="page-head">
        <div>
          <div className="page-eyebrow">Ingredients and production</div>
          <h1 className="page-title">Inventory</h1>
          <div className="page-meta" style={{ marginTop: 8 }}>
            <span className="ornament"></span>
            <span>
              <b>{ingredients.length}</b> ingredients · <b style={{ color: "var(--rose-500)" }}>{critical}</b> critical · <b style={{ color: "var(--gold-700)" }}>{low}</b> low · value <b style={{ color: "var(--green-700)" }}>{money(totalValue)}</b>
            </span>
          </div>
        </div>
        <div className="row" style={{ gap: 10 }}>
          <div className="search" style={{ width: 240, margin: 0 }}>
            <Ic name="search" size={14} />
            <input placeholder="Search ingredients" value={search} onChange={(e) => setSearch(e.target.value)} />
          </div>
          <button className="btn btn-ghost" onClick={loadInventory} disabled={saving}>
            <Ic name="refresh" size={14} /> Refresh
          </button>
        </div>
      </div>

      {error && (
        <div className="card" style={{ padding: 14, color: "var(--rose-500)", marginBottom: 14 }}>
          {error}
        </div>
      )}

      <div className="inventory-action-bar" aria-label="Inventory actions">
        <button
          className={`inventory-action-pill ${inventoryAction === "ingredient" ? "active" : ""}`}
          onClick={() => {
            setIngredientDraft(blankIngredient);
            setInventoryAction("ingredient");
          }}
        >
          <Ic name="plus" size={16} />
          Ingredient
        </button>
        <button
          className={`inventory-action-pill ${inventoryAction === "recipe" ? "active" : ""}`}
          onClick={() => {
            setRecipeDialogView("list");
            setInventoryAction("recipe");
          }}
        >
          <Ic name="leaf" size={16} />
          Batch recipe
        </button>
      </div>

      <div className="card">
        <div className="card-head">
          <div>
            <div className="card-title">Ingredient storage</div>
            <div className="card-sub">{visibleIngredients.length} ingredient{visibleIngredients.length === 1 ? "" : "s"} · exact lot value</div>
          </div>
        </div>
        <div style={{ padding: "0 16px 8px" }}>
          <div className="menu-toolbar" style={{ marginBottom: 8 }}>
            {categories.map((cat) => (
              <button key={cat} className={`chip ${activeCat === cat ? "active" : ""}`} onClick={() => setActiveCat(cat)}>
                {cat}
              </button>
            ))}
          </div>
        </div>
        <div className="card-divider" />
        <div style={{ overflowX: "auto" }}>
          <table className="table inv-table">
            <thead>
              <tr>
                <th>Ingredient</th>
                <th style={{ width: "30%" }}>Stock vs par</th>
                <th className="num">Exact value</th>
                <th>Lots</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {visibleIngredients.map((ingredient) => {
                const pct = stockPct(ingredient);
                const status = statusOf(ingredient);
                const color = status === "critical" ? "var(--rose-500)" : status === "low" ? "var(--gold-700)" : "var(--green-700)";
                return (
                  <tr key={ingredient.id}>
                    <td>
                      <div className="row" style={{ gap: 10 }}>
                        <div className="detail-thumb" style={{ width: 34, height: 34, fontSize: 15 }}>{ingredient.glyph || ingredient.name.slice(0, 1)}</div>
                        <div>
                          <div style={{ fontFamily: "var(--font-display)", fontSize: 15, color: "var(--green-800)" }}>{ingredient.name}</div>
                          <div className="muted" style={{ fontSize: 11.5 }}>{ingredient.category} · {ingredient.supplier || "No supplier"}</div>
                        </div>
                      </div>
                    </td>
                    <td>
                      <div className="stock-bar">
                        <div className="stock-bar-track">
                          <div className="stock-bar-fill" style={{ width: `${pct}%`, background: color }} />
                          <div className="stock-bar-par" title="Par level" />
                        </div>
                        <div className="stock-bar-num">
                          <span className="mono" style={{ color }}>{qty(ingredientQty(ingredient))}{ingredient.unit}</span>
                          <span className="muted"> / {qty(ingredient.par_quantity)}{ingredient.unit}</span>
                        </div>
                      </div>
                    </td>
                    <td className="num">{money(ingredientValue(ingredient))}</td>
                    <td>
                      <div className="muted" style={{ fontSize: 12 }}>
                        {(ingredient.lots || []).filter((lot) => Number(lot.remaining_quantity || 0) > 0).length} active
                      </div>
                    </td>
                    <td>
                      <div className="row" style={{ gap: 6, justifyContent: "flex-end" }}>
                        <button className="btn btn-ghost" style={{ padding: "5px 10px", fontSize: 11.5 }} onClick={() => editIngredient(ingredient)}>
                          Edit
                        </button>
                        <button className="btn btn-gold" style={{ padding: "5px 10px", fontSize: 11.5 }} onClick={() => openStockAdjustment(ingredient)}>
                          Stock
                        </button>
                      </div>
                    </td>
                  </tr>
                );
              })}
              {!visibleIngredients.length && (
                <tr>
                  <td colSpan="5" className="muted" style={{ textAlign: "center", padding: 24 }}>No ingredients yet.</td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      <div className="card" style={{ marginTop: 16 }}>
        <div className="card-head">
          <div>
            <div className="card-title">Menu item</div>
            <div className="card-sub">Stock increases consume ingredients from the item batch recipe.</div>
          </div>
        </div>
        <div className="card-divider" />
        <div style={{ overflowX: "auto" }}>
          <table className="table">
            <thead>
              <tr>
                <th>Item</th>
                <th className="num">In stock</th>
                <th className="num">Cost/item</th>
                <th style={{ textAlign: "right" }}>Actions</th>
              </tr>
            </thead>
            <tbody>
              {sortedMenuItems.map((item) => {
                const recipe = recipes.find((entry) => entry.menu_item_id === item.id);
                return (
                  <tr key={item.id}>
                    <td>
                      <div className="row" style={{ gap: 10 }}>
                        <div className={`detail-thumb ${item.image_url ? "has-image" : ""}`} style={{ width: 34, height: 34, fontSize: 15, overflow: "hidden", position: "relative" }}>
                          {item.image_url ? (
                            <MenuCachedImage
                              itemId={item.id}
                              imageUrl={item.image_url}
                              alt={item.name}
                              style={{
                                position: "absolute",
                                inset: 0,
                                width: "100%",
                                height: "100%",
                                objectFit: "contain",
                                padding: 4,
                                transform: `scale(${Number(item.image_zoom || 1)})`,
                                transformOrigin: "center",
                              }}
                            />
                          ) : (
                            (item.name || "M").slice(0, 1)
                          )}
                        </div>
                        <div>
                          <div style={{ fontFamily: "var(--font-display)", fontSize: 15, color: "var(--green-800)" }}>{item.name}</div>
                          <div className="muted" style={{ fontSize: 11.5 }}>{recipe ? `${recipe.lines?.length || 0} recipe ingredients` : "No batch recipe"}</div>
                        </div>
                      </div>
                    </td>
                    <td className="num mono">{qty(item.stock_count || 0)}</td>
                    <td className="num mono">{recipe ? money(recipeCostByMenuItem.get(item.id) || 0) : "-"}</td>
                    <td>
                      <div className="row" style={{ gap: 6, justifyContent: "flex-end", flexWrap: "wrap" }}>
                        <button className="btn btn-gold" style={{ padding: "5px 10px", fontSize: 11.5 }} onClick={(e) => openMenuStockEdit(e, item, "add")} disabled={saving}>
                          Add
                        </button>
                        <button className="btn btn-ghost" style={{ padding: "5px 10px", fontSize: 11.5, color: "var(--rose-500)" }} onClick={(e) => openMenuStockEdit(e, item, "remove")} disabled={saving}>
                          Remove
                        </button>
                        <button className="btn btn-ghost" style={{ padding: "5px 10px", fontSize: 11.5 }} onClick={(e) => openMenuStockEdit(e, item, "modify")} disabled={saving}>
                          Modify
                        </button>
                      </div>
                    </td>
                  </tr>
                );
              })}
              {!menuItems.length && (
                <tr>
                  <td colSpan="4" className="muted" style={{ textAlign: "center", padding: 24 }}>No menu items yet.</td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      {menuStockEdit && ReactDOM.createPortal(
        <React.Fragment>
          <div style={{ position: "fixed", inset: 0, zIndex: 289 }} onClick={() => setMenuStockEdit(null)} />
          <div
            style={{
              position: "fixed",
              top: menuStockEdit.top,
              left: menuStockEdit.left,
              zIndex: 290,
              width: menuStockEdit.width,
              maxWidth: "calc(100vw - 24px)",
              boxSizing: "border-box",
              background: "var(--cream-50)",
              border: "1px solid var(--line-gold)",
              borderRadius: "var(--r-lg)",
              boxShadow: "0 12px 32px rgba(30, 42, 31, 0.18)",
              padding: 14,
            }}
            onClick={(e) => e.stopPropagation()}
          >
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: 10 }}>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 11, fontWeight: 800, color: "var(--ink-500)", textTransform: "uppercase", letterSpacing: 1 }}>
                  {menuStockEdit.mode === "add" ? "Add stock" : menuStockEdit.mode === "remove" ? "Remove stock" : "Modify stock"}
                </div>
                <div style={{ color: "var(--green-800)", fontFamily: "var(--font-display)", fontSize: 15, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                  {menuStockEdit.item.name}
                </div>
              </div>
              <button className="icon-btn" style={{ width: 30, height: 30, flex: "0 0 30px" }} onClick={() => setMenuStockEdit(null)} title="Close">
                <Ic name="x" size={12} />
              </button>
            </div>
            <div className="field" style={{ marginBottom: 12 }}>
              <label>{menuStockEdit.mode === "modify" ? "New stock number" : "Change number"}</label>
              <input
                type="number"
                min="0"
                step="1"
                autoFocus
                placeholder="0"
                value={stockDrafts[menuStockEdit.item.id] ?? ""}
                onChange={(e) => setStockDrafts({ ...stockDrafts, [menuStockEdit.item.id]: e.target.value })}
                onKeyDown={(e) => {
                  if (e.key === "Enter") saveMenuStockEdit();
                  if (e.key === "Escape") setMenuStockEdit(null);
                }}
                style={{ fontFamily: "var(--font-mono)", fontSize: 20, fontWeight: 800, textAlign: "left", paddingLeft: 14 }}
              />
            </div>
            <div className="row" style={{ justifyContent: "space-between", gap: 8 }}>
              <span className="muted" style={{ fontSize: 11 }}>Current {qty(menuStockEdit.item.stock_count || 0)}</span>
              <div className="row" style={{ gap: 8 }}>
                <button className="btn btn-ghost" style={{ padding: "6px 10px" }} onClick={() => setMenuStockEdit(null)}>Cancel</button>
                <button className="btn btn-primary" style={{ padding: "6px 12px" }} onClick={saveMenuStockEdit} disabled={saving}>
                  Save
                </button>
              </div>
            </div>
          </div>
        </React.Fragment>,
        document.body
      )}

      {inventoryAction === "ingredient" && ReactDOM.createPortal(
        <div className="date-dialog-scrim" onClick={() => setInventoryAction("")}>
          <div className="date-dialog inventory-floating-dialog inventory-stock-dialog" onClick={(e) => e.stopPropagation()}>
            <div className="date-dialog-head">
              <div>
                <div className="date-dialog-eyebrow">Ingredient</div>
                <h2>{ingredientDraft.id ? "Edit ingredient" : "New ingredient"}</h2>
              </div>
              <button className="icon-btn" onClick={() => setInventoryAction("")} title="Close">
                <Ic name="x" size={14} />
              </button>
            </div>
            <div className="inventory-editor-head">
              <div className="detail-thumb inventory-editor-glyph">
                {(ingredientDraft.glyph || ingredientDraft.name || "I").trim().slice(0, 1).toUpperCase()}
              </div>
              <div style={{ minWidth: 0 }}>
                <div className="card-title">{ingredientDraft.name || "Raw ingredient"}</div>
                <div className="card-sub">Storage item for lots and batch recipes.</div>
              </div>
            </div>
            <div className="inventory-form-grid">
              <div className="field inventory-field-wide">
                <label>Name</label>
                <input placeholder="Thai tea leaves" value={ingredientDraft.name} onChange={(e) => setIngredientDraft({ ...ingredientDraft, name: e.target.value })} />
              </div>
              <div className="field">
                <label>Glyph</label>
                <input placeholder="T" maxLength="2" value={ingredientDraft.glyph} onChange={(e) => setIngredientDraft({ ...ingredientDraft, glyph: e.target.value })} />
              </div>
              <div className="field">
                <label>Category</label>
                <select
                  value={ingredientCategory(ingredientDraft.category)}
                  onChange={(e) => {
                    const category = e.target.value;
                    setIngredientDraft({
                      ...ingredientDraft,
                      category,
                      unit: ingredientUnit(category, ingredientDraft.unit),
                    });
                  }}
                >
                  {INGREDIENT_CATEGORIES.map((category) => (
                    <option key={category} value={category}>{category}</option>
                  ))}
                </select>
              </div>
              <div className="field">
                <label>Unit</label>
                <select value={ingredientUnit(ingredientDraft.category, ingredientDraft.unit)} onChange={(e) => setIngredientDraft({ ...ingredientDraft, unit: e.target.value })}>
                  {ingredientUnitOptions(ingredientDraft.category).map((group) => (
                    <optgroup key={group.label} label={group.label}>
                      {group.units.map((unit) => (
                        <option key={unit} value={unit}>{unit}</option>
                      ))}
                    </optgroup>
                  ))}
                </select>
              </div>
              <div className="field">
                <label>Par level</label>
                <input type="number" min="0" step="0.001" placeholder="0" value={ingredientDraft.par_quantity} onChange={(e) => setIngredientDraft({ ...ingredientDraft, par_quantity: e.target.value })} />
              </div>
              <div className="field">
                <label>Supplier</label>
                <input placeholder="Supplier name" value={ingredientDraft.supplier} onChange={(e) => setIngredientDraft({ ...ingredientDraft, supplier: e.target.value })} />
              </div>
              <div className="field inventory-field-wide">
                <label>Notes</label>
                <textarea placeholder="Storage notes, reorder hints, prep notes" value={ingredientDraft.notes} onChange={(e) => setIngredientDraft({ ...ingredientDraft, notes: e.target.value })} />
              </div>
            </div>
            <div className="date-dialog-foot inventory-dialog-foot">
              {ingredientDraft.id && (
                <button className="btn btn-danger" onClick={removeIngredient} disabled={saving}>
                  Remove ingredient
                </button>
              )}
              <button className="btn btn-ghost" onClick={() => { setIngredientDraft(blankIngredient); setInventoryAction(""); }}>Cancel</button>
              <button className="btn btn-primary" onClick={saveIngredient} disabled={saving}>
                <Ic name="check" size={14} /> Save ingredient
              </button>
            </div>
          </div>
        </div>,
        document.body
      )}

      {inventoryAction === "recipe" && ReactDOM.createPortal(
        <div className="date-dialog-scrim" onClick={() => setInventoryAction("")}>
          <div className="date-dialog inventory-floating-dialog inventory-recipe-dialog" onClick={(e) => e.stopPropagation()}>
            <div className="date-dialog-head">
              <div>
                <div className="date-dialog-eyebrow">Batch recipe</div>
                <h2>{recipeDialogView === "list" ? "Choose menu item" : selectedRecipeMenuItem?.name || "Batch recipe"}</h2>
              </div>
              <button className="icon-btn" onClick={() => setInventoryAction("")} title="Close">
                <Ic name="x" size={14} />
              </button>
            </div>
            {recipeDialogView === "list" ? (
              <div className="inventory-recipe-list">
                {sortedMenuItems.map((item) => {
                  const recipe = recipes.find((entry) => entry.menu_item_id === item.id);
                  return (
                    <button
                      key={item.id}
                      className="inventory-recipe-choice"
                      onClick={() => {
                        setRecipeMenuItemId(item.id);
                        setRecipeDialogView("editor");
                      }}
                    >
                      <div className="detail-thumb inventory-recipe-choice-glyph">
                        {(item.name || "M").trim().slice(0, 1).toUpperCase()}
                      </div>
                      <div className="inventory-recipe-choice-main">
                        <b>{item.name}</b>
                        <span>{recipe ? `${recipe.lines?.length || 0} ingredient${recipe.lines?.length === 1 ? "" : "s"} · batch ${qty(recipe.batch_output_quantity)}` : "No recipe yet"}</span>
                      </div>
                      <div className="inventory-recipe-choice-end">
                        <span className={`tag ${recipe ? "ok" : ""}`}>{recipe ? "Saved" : "New"}</span>
                        <Ic name="arrow-right" size={14} />
                      </div>
                    </button>
                  );
                })}
                {!menuItems.length && (
                  <div className="muted" style={{ padding: 18, textAlign: "center" }}>No menu items available.</div>
                )}
              </div>
            ) : (
              <div className="inventory-recipe-editor-view">
                <button className="inventory-recipe-back" onClick={() => setRecipeDialogView("list")}>
                  Menu items
                </button>
                <div className="inventory-recipe-editor-head">
                  <div className="detail-thumb inventory-editor-glyph">
                    {(selectedRecipeMenuItem?.name || "R").trim().slice(0, 1).toUpperCase()}
                  </div>
                  <div className="inventory-recipe-editor-main">
                    <div className="inventory-recipe-editor-title">{selectedRecipeMenuItem?.name || "Selected item"}</div>
                    <div className="card-sub">Recipe is for one full production batch.</div>
                  </div>
                  <span className={`tag ${selectedRecipe ? "ok" : ""}`}>{selectedRecipe ? "Saved" : "New"}</span>
                </div>
                <div className="inventory-recipe-meta">
                  <div className="field inventory-recipe-output">
                    <label>Batch output</label>
                    <input type="number" placeholder="Batch output quantity" value={recipeOutput} onChange={(e) => setRecipeOutput(e.target.value)} />
                  </div>
                  <div className="inventory-stock-cost">
                    <span>Current lot cost</span>
                    <b>{money(recipeCostPreview)}</b>
                  </div>
                </div>
                <div className="inventory-recipe-section-head">
                  <span>Ingredients</span>
                  <button className="btn btn-ghost" onClick={() => setRecipeLines([...recipeLines, { ingredient_id: "", quantity_required: "" }])}>
                    <Ic name="plus" size={13} /> Ingredient
                  </button>
                </div>
                <div className="inventory-recipe-lines">
                  {recipeLines.map((line, index) => {
                    const ingredient = ingredients.find((item) => item.id === line.ingredient_id);
                    return (
                      <div key={index} className="inventory-recipe-line">
                        <div className="inventory-recipe-line-index">{index + 1}</div>
                        <select value={line.ingredient_id} onChange={(e) => {
                          const next = [...recipeLines];
                          next[index] = { ...next[index], ingredient_id: e.target.value };
                          setRecipeLines(next);
                        }}>
                          <option value="">Ingredient</option>
                          {ingredients.filter((i) => i.is_active !== false).map((item) => (
                            <option key={item.id} value={item.id}>{item.name}</option>
                          ))}
                        </select>
                        <div className="inventory-recipe-unit">{ingredient?.unit || "-"}</div>
                        <input
                          type="number"
                          placeholder="Qty"
                          value={line.quantity_required}
                          onChange={(e) => {
                            const next = [...recipeLines];
                            next[index] = { ...next[index], quantity_required: e.target.value };
                            setRecipeLines(next);
                          }}
                        />
                        <button className="icon-btn" title="Remove line" onClick={() => setRecipeLines(recipeLines.filter((_, i) => i !== index))}>
                          <Ic name="x" size={12} />
                        </button>
                      </div>
                    );
                  })}
                </div>
                <div className="field inventory-recipe-notes">
                  <label>Notes</label>
                  <textarea placeholder="Recipe notes" value={recipeNotes} onChange={(e) => setRecipeNotes(e.target.value)} />
                </div>
                <div className="date-dialog-foot inventory-dialog-foot inventory-recipe-foot">
                  <span className="muted">Preview batch cost from current lots: <b>{money(recipeCostPreview)}</b></span>
                  <button className="btn btn-primary" onClick={saveRecipe} disabled={saving}>Save recipe</button>
                </div>
              </div>
            )}
          </div>
        </div>,
        document.body
      )}

      {inventoryAction === "stock" && ReactDOM.createPortal(
        <div className="date-dialog-scrim" onClick={() => setInventoryAction("")}>
          <div className="date-dialog inventory-floating-dialog inventory-stock-dialog" onClick={(e) => e.stopPropagation()}>
            <div className="date-dialog-head">
              <div>
                <div className="date-dialog-eyebrow">Ingredient stock</div>
                <h2>{selectedStockIngredient?.name || "Change stock"}</h2>
              </div>
              <button className="icon-btn" onClick={() => setInventoryAction("")} title="Close">
                <Ic name="x" size={14} />
              </button>
            </div>
            <div className="inventory-stock-summary">
              <div>
                <span>Current</span>
                <b>{qty(ingredientQty(selectedStockIngredient || {}))}{selectedStockIngredient?.unit || ""}</b>
              </div>
              <div>
                <span>Value</span>
                <b>{money(ingredientValue(selectedStockIngredient || {}))}</b>
              </div>
              <div>
                <span>Active lots</span>
                <b>{(selectedStockIngredient?.lots || []).filter((lot) => Number(lot.remaining_quantity || 0) > 0).length}</b>
              </div>
            </div>
            <div className="inventory-stock-layout">
              <div className="inventory-stock-history">
                <div className="inventory-recipe-section-head">
                  <span>Activity history</span>
                </div>
                <div className="inventory-stock-history-list">
                  {selectedStockActivity.map((activity) => (
                    <div key={activity.id} className="inventory-stock-history-row">
                      <div className="inventory-stock-history-main">
                        <b>{activity.title}</b>
                        <span>
                          {activity.at ? new Date(activity.at).toLocaleString() : ""}
                          {activity.supplier ? ` · ${activity.supplier}` : ""}
                        </span>
                        {activity.notes && <em>{activity.notes}</em>}
                      </div>
                      <div className="inventory-stock-history-nums">
                        <div className="inventory-stock-history-transaction">
                          <b className={`inventory-stock-history-amount ${activity.tone || "neutral"}`}>{activity.quantityText}</b>
                          <span></span>
                          <b className={`inventory-stock-history-amount ${activity.tone || "neutral"}`}>{money(activity.moneyAmount)}</b>
                        </div>
                        <small>{activity.leftText}</small>
                      </div>
                    </div>
                  ))}
                  {!selectedStockActivity.length && (
                    <div className="muted" style={{ padding: 12, textAlign: "center" }}>No stock activity yet.</div>
                  )}
                </div>
              </div>
              <div className="inventory-stock-action-panel">
                <div className="inventory-stock-modes">
                  {[
                    ["add", "Add"],
                    ["remove", "Remove"],
                    ["set", "Modify"],
                  ].map(([mode, label]) => (
                    <button
                      key={mode}
                      className={stockAdjustment.mode === mode ? "active" : ""}
                      onClick={() => setStockAdjustment({
                        ...stockAdjustment,
                        mode,
                        quantity: "",
                        totalCost: "",
                      })}
                    >
                      {label}
                    </button>
                  ))}
                </div>
                <div className="inventory-form-grid">
                  <div className="field inventory-field-wide">
                    <label>
                      {stockAdjustment.mode === "set"
                        ? "New quantity"
                        : stockAdjustment.mode === "remove"
                          ? "Quantity to remove"
                          : "Quantity to add"}
                    </label>
                    <div className="inventory-stock-quantity-row">
                      <div className="inventory-recipe-unit">{selectedStockIngredient?.unit || "-"}</div>
                      <input
                        type="number"
                        min="0"
                        step="0.001"
                        placeholder="0"
                        value={stockAdjustment.quantity}
                        onChange={(e) => setStockAdjustment({ ...stockAdjustment, quantity: e.target.value })}
                      />
                    </div>
                  </div>
                  <div className="field inventory-field-wide">
                    <label>
                      {stockAdjustment.mode === "set"
                        ? "Total value"
                        : stockAdjustment.mode === "remove"
                          ? "Removed value"
                          : "Total cost"}
                    </label>
                    <div className="inventory-money-input">
                      <span>$</span>
                      <input
                        type="number"
                        min="0"
                        step="0.01"
                        placeholder={stockAdjustment.mode === "remove" ? Number(stockAdjustmentCost || 0).toFixed(2) : "0.00"}
                        value={stockAdjustment.totalCost}
                        onChange={(e) => setStockAdjustment({ ...stockAdjustment, totalCost: e.target.value })}
                      />
                    </div>
                  </div>
                  <div className="field inventory-field-wide">
                    <label>Supplier</label>
                    <input placeholder="Supplier name" value={stockAdjustment.supplier} onChange={(e) => setStockAdjustment({ ...stockAdjustment, supplier: e.target.value })} />
                  </div>
                  <div className="field inventory-field-wide">
                    <label>Note</label>
                    <textarea placeholder="Invoice, waste, recount, correction note" value={stockAdjustment.notes} onChange={(e) => setStockAdjustment({ ...stockAdjustment, notes: e.target.value })} />
                  </div>
                </div>
              </div>
            </div>
            <div className="date-dialog-foot inventory-dialog-foot">
              <button className="btn btn-ghost" onClick={() => { setStockAdjustment(blankStockAdjustment); setInventoryAction(""); }}>Cancel</button>
              <button className="btn btn-gold" onClick={saveStockAdjustment} disabled={saving}>
                {stockAdjustment.mode === "set" ? "Modify stock" : stockAdjustment.mode === "remove" ? "Remove stock" : "Add stock"}
              </button>
            </div>
          </div>
        </div>,
        document.body
      )}
      {confirmDialog && (
        <ConfirmDialog
          title={confirmDialog.title}
          message={confirmDialog.message}
          confirmLabel={confirmDialog.confirmLabel}
          zIndex={3000}
          onConfirm={() => {
            const confirm = confirmDialog.onConfirm;
            setConfirmDialog(null);
            confirm?.();
          }}
          onCancel={() => setConfirmDialog(null)}
        />
      )}
    </div>
  );
};

window.Inventory = Inventory;
