import { useEffect, useState } from "react";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
import { api } from "../api";
import { useConfirm } from "../confirm";
import { useAuth } from "../auth";
import BarcodeList from "../components/BarcodeList";
import Icon from "../components/Icon";
import OffVergleich from "../components/OffVergleich";
import ProduktBild from "../components/ProduktBild";
import { useToast } from "../toast";
import { useSettings } from "../settings";
import { asTree } from "../categoryTree";
import {
  daysUntil, expiryRowClass, fmt, fromMonthInput, isExpired, relativeExpiry, toMonthInput, unitShort,
} from "../units";

const EMPTY = {
  barcode: "", name: "", brand: "", image_url: "",
  unit_id: "", package_size: "", package_label: "", date_precision: "day", min_stock: "",
  group_id: "", category_id: "",
};

// Auswahl für die Gebinde-Bezeichnung ("Packung" ist der leere Standardwert).
const PACKAGE_LABELS = [
  "Glas", "Tüte", "Flasche", "Dose", "Tube", "Becher", "Beutel", "Karton", "Riegel", "Rolle",
];

// Kanonische Einheit je Basiseinheit (für OFF-Vorschläge und Altbestand).
const CANONICAL_NAME = { piece: "Stück", gram: "Gramm", milliliter: "Milliliter" };

const KIND_LABEL = { count: "Anzahl", weight: "Gewicht", volume: "Volumen" };
const KIND_ORDER = ["count", "weight", "volume"];

export default function ProductForm() {
  const confirm = useConfirm();
  const toast = useToast();
  const { id } = useParams();
  const isNew = !id;
  const { isAdmin } = useAuth();
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();

  const [form, setForm] = useState(EMPTY);
  const [product, setProduct] = useState(null);
  const [lots, setLots] = useState([]);
  const [groups, setGroups] = useState([]);
  const [categories, setCategories] = useState([]);
  const [units, setUnits] = useState([]);
  const [error, setError] = useState(null);
  const [busy, setBusy] = useState(false);
  // Einheit für die Mindestbestand-Eingabe: "package" oder die ID einer Einheit.
  const [minUnit, setMinUnit] = useState("");
  const [warnDays, setWarnDays] = useState(7);
  // Offene Gegenüberstellung mit Open Food Facts (null = zu).
  const [offDaten, setOffDaten] = useState(null);
  const [offBusy, setOffBusy] = useState(false);
  const [bildVersion, setBildVersion] = useState(0);

  const selectedUnit = units.find((u) => String(u.id) === String(form.unit_id)) || null;
  const unitFactor = selectedUnit ? selectedUnit.factor : 1;
  const unitName = selectedUnit ? selectedUnit.name : "";

  function set(k, v) {
    setForm((f) => ({ ...f, [k]: v }));
  }

  function canonicalUnitId(unitList, baseUnit) {
    const name = CANONICAL_NAME[baseUnit];
    const hit = unitList.find((u) => u.name === name);
    return hit ? String(hit.id) : "";
  }

  // Faktor, mit dem der angezeigte Mindestbestand in Basiseinheiten umgerechnet wird.
  // sel ist "package" oder die ID einer verwalteten Einheit.
  function minFactor(sel, pkgSize, unitList) {
    if (sel === "package") return Number(pkgSize) > 0 ? Number(pkgSize) : 1;
    const u = unitList.find((x) => String(x.id) === String(sel));
    return u ? u.factor : 1;
  }

  function changeMinUnit(newSel) {
    if (form.min_stock !== "" && newSel !== minUnit) {
      const oldF = minFactor(minUnit, form.package_size, units);
      const newF = minFactor(newSel, form.package_size, units);
      set("min_stock", String((Number(form.min_stock) * oldF) / newF));
    }
    setMinUnit(newSel);
  }

  function applySuggestion(res, unitList) {
    const s = res.suggestion;
    setForm((f) => ({
      ...f,
      barcode: s.barcode || f.barcode,
      name: s.name || f.name,
      brand: s.brand || f.brand,
      image_url: s.image_url || f.image_url,
      unit_id: f.unit_id || canonicalUnitId(unitList, s.base_unit || "piece"),
      package_size: s.package_size != null ? String(s.package_size) : f.package_size,
      // Kategorie schlaegt das Backend aus der OFF-Einordnung vor; die Gruppe
      // nur, wenn der Code dort ausdruecklich hinterlegt ist.
      category_id: f.category_id || (res.category_id ? String(res.category_id) : ""),
      group_id: f.group_id || (res.group_id ? String(res.group_id) : ""),
    }));
    if (s.package_size != null) setMinUnit("package");
    toast(
      "Daten von Open Food Facts übernommen." +
        (s.package_size != null ? "" : " (Füllmenge nicht hinterlegt – bitte Packungsgröße prüfen.)") +
        (res.category_name ? ` Kategorie „${res.category_name}“ vorgeschlagen.` : "") +
        (res.group_name ? ` Gruppe „${res.group_name}“ über den EAN-Code erkannt.` : "")
    );
  }

  async function runLookup(code, unitList) {
    if (!code) return;
    setError(null);

    try {
      const res = await api.lookup(code.trim());
      if (res.found && res.existing_product) {
        toast("Dieses Produkt existiert bereits.");
        navigate(`/products/${res.existing_product.id}`);
      } else if (res.found && res.suggestion) {
        applySuggestion(res, unitList);
      } else {
        toast("Barcode unbekannt – bitte Daten selbst eingeben.", "warn");
      }
    } catch (err) {
      setError(err.message);
    }
  }

  /**
   * Open Food Facts erneut befragen, obwohl der Artikel schon existiert.
   * Übernommen wird nichts von allein – das entscheidet die Gegenüberstellung.
   */
  async function holeOffDaten() {
    setError(null);
    setOffBusy(true);
    try {
      const res = await api.offCompare(id);
      if (res.found && res.suggestion) {
        setOffDaten({ ...res.suggestion, category_id: res.category_id, category_name: res.category_name });
      } else {
        setOffDaten(null);
        toast("Open Food Facts kennt keinen der hinterlegten EAN-Codes.", "warn");
      }
    } catch (err) {
      setError(err.message);
    } finally {
      setOffBusy(false);
    }
  }

  /** Welche Felder die Gegenüberstellung zeigt – und woher ihr Wert kommt. */
  function offFelder() {
    if (!offDaten) return [];
    const kategorie = categories.find((c) => String(c.id) === String(form.category_id));
    return [
      { schluessel: "name", titel: "Name", eigen: form.name, fremd: offDaten.name || "" },
      { schluessel: "brand", titel: "Marke", eigen: form.brand, fremd: offDaten.brand || "" },
      {
        schluessel: "package_size", titel: "Packungsgröße",
        eigen: form.package_size, fremd: offDaten.package_size ?? "",
      },
      {
        schluessel: "category_id", titel: "Kategorie",
        eigen: form.category_id, fremd: offDaten.category_id ?? "",
        anzeigeEigen: kategorie ? kategorie.name : "–",
        anzeigeFremd: offDaten.category_name || "–",
      },
    ];
  }

  function uebernehmen(schluessel) {
    if (!offDaten) return;
    if (schluessel === "image_url") {
      set("image_url", offDaten.image_url || "");
      // Das Bild selbst wechselt erst beim Speichern - ohne Hinweis wirkt der
      // Knopf folgenlos.
      toast("Bild übernommen. Mit „Speichern“ wird es geholt.");
      return;
    }
    if (schluessel === "package_size") {
      set("package_size", offDaten.package_size != null ? String(offDaten.package_size) : "");
      return;
    }
    if (schluessel === "category_id") {
      set("category_id", offDaten.category_id ? String(offDaten.category_id) : "");
      return;
    }
    set(schluessel, offDaten[schluessel] || "");
  }

  function alleUebernehmen() {
    offFelder().forEach((f) => {
      if (f.fremd !== "" && f.fremd !== null && String(f.fremd) !== String(f.eigen)) {
        uebernehmen(f.schluessel);
      }
    });
    if (offDaten?.image_url) uebernehmen("image_url");
  }

  useEffect(() => {
    async function load() {
      try {
        const [gs, us, cs] = await Promise.all([
          api.listGroups(), api.listUnits(), api.listCategories(),
        ]);
        setGroups(gs);
        setUnits(us);
        setCategories(cs);
        try {
          const s = await api.listSettings();
          const row = s.find((x) => x.key === "expiry_warning_days");
          if (row) setWarnDays(parseInt(row.value, 10) || 7);
        } catch { /* optional */ }

        if (!isNew) {
          const p = await api.getProduct(id);
          setProduct(p);
          const uid = p.display_unit_id
            ? String(p.display_unit_id)
            : canonicalUnitId(us, p.base_unit);
          // Erfassungseinheit des Mindestbestands wiederherstellen.
          const mode = p.min_stock_in_packages
            ? "package"
            : p.min_stock_unit_id
              ? String(p.min_stock_unit_id)
              : uid;
          const f = minFactor(mode, p.package_size, us);
          setMinUnit(mode);
          setForm({
            barcode: p.barcode || "", name: p.name, brand: p.brand || "",
            image_url: p.image_url || "", unit_id: uid,
            package_size: p.package_size ?? "", package_label: p.package_label || "",
            date_precision: p.date_precision === "month" ? "month" : "day",
            min_stock: p.min_stock != null ? p.min_stock / f : "",
            group_id: p.group_id ?? "",
            category_id: p.category_id ?? "",
          });
          setLots(await api.listLots(id));
        } else {
          const bc = searchParams.get("barcode");
          if (bc) {
            set("barcode", bc);
            await runLookup(bc, us);
          }
        }
      } catch (err) {
        setError(err.message);
      }
    }
    load();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [id]);

  function buildPayload() {
    const sel = minUnit || form.unit_id;
    let minBase = null;
    if (form.min_stock !== "") {
      minBase = Number(form.min_stock) * minFactor(sel, form.package_size, units);
    }
    return {
      barcode: form.barcode || null,
      name: form.name,
      brand: form.brand || null,
      image_url: form.image_url || null,
      unit_id: form.unit_id === "" ? null : Number(form.unit_id),
      package_size: form.package_size === "" ? null : Number(form.package_size),
      package_label: form.package_label.trim() || null,
      date_precision: form.date_precision || "day",
      min_stock: minBase,
      min_stock_unit_id: sel === "package" || sel === "" ? null : Number(sel),
      min_stock_in_packages: sel === "package",
      group_id: form.group_id === "" ? null : Number(form.group_id),
      category_id: form.category_id === "" ? null : Number(form.category_id),
    };
  }

  async function save(e) {
    e.preventDefault();
    setError(null);
    setBusy(true);
    try {
      if (isNew) {
        const created = await api.createProduct(buildPayload());
        navigate(`/products/${created.id}`);
      } else {
        await api.updateProduct(id, buildPayload());
        toast("Gespeichert.");
        setProduct(await api.getProduct(id));
        setLots(await api.listLots(id));
        // Der Server holt bei geaenderter Bildadresse ein neues Bild. Ohne
        // diesen Zaehler zeigte die Seite weiter das alte aus dem Zwischenspeicher.
        setBildVersion((v) => v + 1);
        setOffDaten(null);
      }
    } catch (err) {
      setError(err.message);
    } finally {
      setBusy(false);
    }
  }

  async function remove() {
    const ok = await confirm({
      title: "Produkt löschen?",
      message: "Alle Chargen dieses Produkts gehen dabei verloren.",
      confirmLabel: "Löschen",
      danger: true,
    });
    if (!ok) return;
    try {
      await api.deleteProduct(id);
      navigate("/products");
    } catch (err) {
      setError(err.message);
    }
  }

  const readOnly = !isAdmin;
  const BASE_SHORT_OF_KIND = { count: "Stk", weight: "g", volume: "ml" };
  const baseShort = selectedUnit
    ? BASE_SHORT_OF_KIND[selectedUnit.kind]
    : product ? unitShort(product.base_unit) : "";

  return (
    <div>
      <div className="page-head">
        <div>
          <h1>{isNew ? "Neues Produkt" : form.name || "Produkt"}</h1>
          {!isNew && product && (
            <div className="sub">
              Bestand: {fmt(product.stock / (product.unit_factor || 1))} {product.unit_name}
              {product.package_size ? ` · ${fmt(product.stock / product.package_size)} Pkg` : ""}
            </div>
          )}
        </div>
        <button className="btn ghost" onClick={() => navigate(-1)}>Zurück</button>
      </div>

      {error && <div className="alert error"><Icon name="alert" size={16} />{error}</div>}

      <div className="grid-2">
        <form className="card" onSubmit={save}>
          {/* Bild steht neben den Kennfeldern, nicht darueber: Der Platz rechts
              von Barcode, Name und Marke ist ohnehin selten ausgenutzt. Fehlt
              ein Bild, rendert die Komponente nichts und die Felder nehmen die
              volle Breite ein. */}
          <div className="produkt-kopf">
            <div className="produkt-kopf-felder">
              <div className="field-inline">
                <label className="grow">
                  Barcode
                  <input value={form.barcode} onChange={(e) => set("barcode", e.target.value)} disabled={readOnly} />
                </label>
                {isAdmin && (
                  <div className="knopf-spalte">
                    <button type="button" className="btn" onClick={() => runLookup(form.barcode, units)}>
                      <Icon name="search" size={16} />Nachschlagen
                    </button>
                    {!isNew && (
                      <button type="button" className="btn" disabled={offBusy}
                        onClick={holeOffDaten}>
                        <Icon name="download" size={16} />
                        {offBusy ? "Frage an…" : "Mit Open Food Facts vergleichen"}
                      </button>
                    )}
                  </div>
                )}
              </div>
              <label>
                Name
                <input value={form.name} onChange={(e) => set("name", e.target.value)} required disabled={readOnly} />
              </label>
              <label>
                Marke
                <input value={form.brand} onChange={(e) => set("brand", e.target.value)} disabled={readOnly} />
              </label>
            </div>
            {!isNew && <ProduktBild productId={id} alt={form.name} version={bildVersion} />}
          </div>

          {offDaten && (
            <OffVergleich
              felder={offFelder()}
              bildEigenId={id}
              bildFremdUrl={offDaten.image_url || ""}
              bildUebernommen={Boolean(offDaten.image_url) && form.image_url === offDaten.image_url}
              onUebernehmen={uebernehmen}
              onAlle={alleUebernehmen}
              onSchliessen={() => setOffDaten(null)}
            />
          )}
          <div className="row">
            <label className="grow">
              Einheit
              <select value={form.unit_id} onChange={(e) => set("unit_id", e.target.value)} disabled={readOnly} required>
                <option value="">– wählen –</option>
                {KIND_ORDER.filter((k) => units.some((u) => u.kind === k)).map((k) => (
                  <optgroup key={k} label={KIND_LABEL[k]}>
                    {units.filter((u) => u.kind === k).map((u) => (
                      <option key={u.id} value={u.id}>{u.name}</option>
                    ))}
                  </optgroup>
                ))}
              </select>
            </label>
            <label className="grow">
              Packungsgröße{baseShort ? ` (in ${baseShort})` : ""}
              <input type="number" step="any" value={form.package_size}
                onChange={(e) => set("package_size", e.target.value)} disabled={readOnly} placeholder="z.B. 500" />
            </label>
          </div>
          <div className="row">
            <label className="grow">
              Bezeichnung der Einheit
              <select value={form.package_label} onChange={(e) => set("package_label", e.target.value)}
                disabled={readOnly}>
                <option value="">Packung (Standard)</option>
                {PACKAGE_LABELS.map((l) => <option key={l} value={l}>{l}</option>)}
                {form.package_label && !PACKAGE_LABELS.includes(form.package_label) && (
                  <option value={form.package_label}>{form.package_label}</option>
                )}
              </select>
            </label>
            <label className="grow">
              <span className="tip" title="Voreinstellung beim Einlagern – z.B. Konserven tragen oft nur „09/2026“.">
                MHD-Angabe
              </span>
              <select value={form.date_precision} onChange={(e) => set("date_precision", e.target.value)}
                disabled={readOnly}>
                <option value="day">Tagesdatum</option>
                <option value="month">nur Monat/Jahr</option>
              </select>
            </label>
          </div>
          <div className="row">
            <label className="grow">
              Mindestbestand
              <div className="field-inline">
                <input type="number" step="any" value={form.min_stock}
                  onChange={(e) => set("min_stock", e.target.value)} disabled={readOnly} placeholder="z.B. 2" />
                <select value={minUnit || form.unit_id} onChange={(e) => changeMinUnit(e.target.value)}
                  disabled={readOnly} style={{ marginTop: 0 }}>
                  {units
                    .filter((u) => !selectedUnit || u.kind === selectedUnit.kind)
                    .map((u) => <option key={u.id} value={u.id}>{u.name}</option>)}
                  {form.package_size && (
                    <option value="package">
                      {form.package_label.trim() || "Packung"} à {fmt(form.package_size)} {baseShort}
                    </option>
                  )}
                </select>
              </div>
            </label>
            <label className="grow">
              <span className="tip" title="Zählt Bestände mehrerer Marken zusammen. Der EAN-Code dieses Artikels erscheint danach automatisch bei der Gruppe.">
                Gruppe
              </span>
              <select value={form.group_id} onChange={(e) => set("group_id", e.target.value)} disabled={readOnly}>
                <option value="">– keine –</option>
                {groups.map((g) => <option key={g.id} value={g.id}>{g.name}</option>)}
              </select>
            </label>
          </div>
          <div className="row">
            <label className="grow">
              <span className="tip" title="Nur für den Überblick in der Artikelliste – ohne Einfluss auf Bestände.">
                Kategorie
              </span>
              <select value={form.category_id} onChange={(e) => set("category_id", e.target.value)}
                disabled={readOnly}>
                <option value="">– keine –</option>
                {asTree(categories).map((c) => (
                  <option key={c.id} value={c.id}>{"— ".repeat(c.depth)}{c.name}</option>
                ))}
              </select>
            </label>
            <div className="grow" />
          </div>

          {isAdmin && (
            <div className="field-inline" style={{ marginTop: "var(--sp-2)" }}>
              <button className="btn primary" disabled={busy}>{busy ? "Speichern…" : "Speichern"}</button>
              {!isNew && (
                <button type="button" className="btn danger" onClick={remove}>
                  <Icon name="trash" size={16} />Löschen
                </button>
              )}
            </div>
          )}
          {readOnly && <p className="muted small mt-0">Nur Administratoren können Produkte bearbeiten.</p>}
        </form>

        {!isNew && (
          <LotsCard
            product={product}
            lots={lots}
            baseShort={baseShort}
            warnDays={warnDays}
            isAdmin={isAdmin}
            onChanged={async () => {
              setLots(await api.listLots(id));
              setProduct(await api.getProduct(id));
            }}
            onError={setError}
          />
        )}
      </div>

      {/* Unterhalb der beiden Spalten: die Codes braucht man selten, sie sollen
          Formular und Chargen nicht auseinanderschieben. */}
      {!isNew && product && (
        <section className="card">
          <div className="card-head"><Icon name="search" /><h2>Weitere EAN-Codes</h2></div>
          <BarcodeList
            barcodes={product.barcodes || []}
            disabled={readOnly}
            hint="Nützlich, wenn dasselbe Produkt mehrere Codes hat (z.B. Aktionspackung)."
            onAdd={async (body) => {
              try {
                setProduct(await api.addProductBarcode(id, body));
              } catch (err) { setError(err.message); }
            }}
            onDelete={async (code) => {
              try {
                await api.deleteProductBarcode(id, code);
                setProduct(await api.getProduct(id));
              } catch (err) { setError(err.message); }
            }}
          />
        </section>
      )}
    </div>
  );
}

/** Chargen-Karte mit Bearbeiten/Löschen. Bearbeitet wird in der Produkteinheit. */
function LotsCard({ product, lots, baseShort, warnDays, isAdmin, onChanged, onError }) {
  const confirm = useConfirm();
  const toast = useToast();
  const { formatBestBefore } = useSettings();
  const [editId, setEditId] = useState(null);
  const [draft, setDraft] = useState({ quantity: "", best_before: "", precision: "day" });
  // In welcher Einheit die Menge bearbeitet wird: "unit" oder "package".
  const [editUnit, setEditUnit] = useState("unit");

  const unitFactor = product?.unit_factor || 1;
  const unitName = product?.unit_name || baseShort;
  const pkgSize = product?.package_size || 0;
  const pkgLabel = product?.package_label || "Packung";

  // Leitangabe: Packungen, sobald eine Packungsgröße hinterlegt ist –
  // sonst die Produkteinheit. Darunter steht die jeweils andere Angabe klein.
  const primaryFactor = pkgSize > 0 ? pkgSize : unitFactor;
  const primaryLabel = pkgSize > 0 ? pkgLabel : unitName;

  function secondary(qty) {
    if (pkgSize > 0) return `${fmt(qty / unitFactor)} ${unitName}`;
    return unitFactor !== 1 ? `${fmt(qty)} ${baseShort}` : "";
  }

  // Faktor der aktuell im Editor gewählten Eingabeeinheit.
  function editFactorOf(mode) {
    return mode === "package" && pkgSize > 0 ? pkgSize : unitFactor;
  }
  const editFactor = editFactorOf(editUnit);

  function startEdit(l) {
    // Bearbeiten startet in der Leitangabe (Packungen, falls vorhanden).
    const mode = pkgSize > 0 ? "package" : "unit";
    setEditId(l.id);
    setEditUnit(mode);
    setDraft({
      quantity: l.quantity / editFactorOf(mode),
      best_before:
        l.best_before_precision === "month"
          ? toMonthInput(l.best_before)
          : l.best_before || "",
      precision: l.best_before_precision === "month" ? "month" : "day",
    });
  }

  function changeEditUnit(newMode) {
    if (draft.quantity !== "" && newMode !== editUnit) {
      const oldF = editFactorOf(editUnit);
      const newF = editFactorOf(newMode);
      setDraft((d) => ({ ...d, quantity: String((Number(d.quantity) * oldF) / newF) }));
    }
    setEditUnit(newMode);
  }

  async function saveEdit(l) {
    try {
      await api.updateLot(l.id, {
        quantity: Number(draft.quantity) * editFactor,
        best_before:
          (draft.precision === "month" ? fromMonthInput(draft.best_before) : draft.best_before) ||
          null,
        best_before_precision: draft.precision || "day",
      });
      setEditId(null);
      await onChanged();
    } catch (err) {
      onError(err.message);
    }
  }

  async function removeLot(l) {
    const ok = await confirm({
      title: "Charge löschen?",
      message: "Die Menge wird als Korrektur im Verlauf protokolliert.",
      confirmLabel: "Löschen",
      danger: true,
    });
    if (!ok) return;
    try {
      await api.deleteLot(l.id);
      await onChanged();
    } catch (err) {
      onError(err.message);
    }
  }

  return (
    <section className="card">
      <div className="card-head"><Icon name="box" /><h2>Chargen im Bestand</h2></div>
      {lots.some((l) => isExpired(l.best_before)) && (
        <div className="alert error"><Icon name="alert" size={16} />
          Dieses Produkt hat abgelaufene Chargen im Bestand.
        </div>
      )}
      <div className="table-wrap">
        <table className="table">
          <thead>
            <tr>
              <th className="num" style={{ minWidth: 150 }}>Menge</th>
              <th style={{ minWidth: 160 }}>MHD</th>
              <th>Eingelagert</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {lots.map((l) => {
              const cls = expiryRowClass(l.best_before, warnDays);
              const dLeft = daysUntil(l.best_before);
              const editing = editId === l.id;
              return (
                <tr key={l.id} className={cls}>
                  <td data-label="Menge" className="num">
                    {editing ? (
                      <div className="field-inline" style={{ justifyContent: "flex-end" }}>
                        <input type="number" step="any" min="0" value={draft.quantity}
                          onChange={(e) => setDraft({ ...draft, quantity: e.target.value })}
                          style={{ marginTop: 0 }} />
                        {pkgSize > 0 ? (
                          <select value={editUnit} onChange={(e) => changeEditUnit(e.target.value)}
                            style={{ marginTop: 0 }}>
                            <option value="package">{pkgLabel}</option>
                            <option value="unit">{unitName}</option>
                          </select>
                        ) : (
                          <span className="muted small">{unitName}</span>
                        )}
                      </div>
                    ) : (
                      <>
                        {fmt(l.quantity / primaryFactor)} {primaryLabel}
                        {secondary(l.quantity) && (
                          <div className="muted small">{secondary(l.quantity)}</div>
                        )}
                      </>
                    )}
                  </td>
                  <td data-label="MHD">
                    {editing ? (
                      <input type={draft.precision === "month" ? "month" : "date"}
                        value={draft.best_before}
                        onChange={(e) => setDraft({ ...draft, best_before: e.target.value })}
                        style={{ marginTop: 0, minWidth: 150 }} />
                    ) : (
                      <>
                        {l.best_before ? formatBestBefore(l.best_before, l.best_before_precision) : "–"}
                        {cls && (
                          <span className={`badge ${cls === "row-danger" ? "danger" : "warn"}`}
                            style={{ marginLeft: 6 }}>
                            {relativeExpiry(dLeft)}
                          </span>
                        )}
                      </>
                    )}
                  </td>
                  <td data-label="Eingelagert" className="muted">{new Date(l.created_at).toLocaleDateString("de-DE")}</td>
                  <td className="num">
                    {isAdmin && (editing ? (
                      <div className="btn-pair">
                        <button className="btn sm primary" onClick={() => saveEdit(l)}>Speichern</button>
                        <button className="btn sm" onClick={() => setEditId(null)}>Abbrechen</button>
                      </div>
                    ) : (
                      <div className="field-inline" style={{ justifyContent: "flex-end" }}>
                        <button className="btn-icon" onClick={() => startEdit(l)} title="Charge bearbeiten">
                          <Icon name="edit" size={16} />
                        </button>
                        <button className="btn-icon danger" onClick={() => removeLot(l)} title="Charge löschen">
                          <Icon name="trash" size={16} />
                        </button>
                      </div>
                    ))}
                  </td>
                </tr>
              );
            })}
            {lots.length === 0 && <tr><td colSpan={4} className="empty">Keine Chargen im Bestand.</td></tr>}
          </tbody>
        </table>
      </div>
      {pkgSize > 0 && (
        <p className="muted small">1 {pkgLabel} = {fmt(pkgSize)} {baseShort}</p>
      )}
    </section>
  );
}
