// =============================================================================
// INVENTORY CONTROL — SAFCC (Gudang) & DAPUR (Induk/Satelit)
// =============================================================================
// Lot-based inventory dengan:
// - FEFO (First-Expired-First-Out) untuk pemakaian & transfer
// - Reorder Point (ROP) + Par Level per lokasi per komoditas
// - Ledger transaksi (MASUK / PAKAI / TRANSFER / WASTE / OPNAME)
// - Stock opname dengan pencatatan selisih (variance)
// - Alert kadaluarsa & rekomendasi jumlah pemesanan ulang
//
// Lokasi: 'SAFCC' (gudang olah/QC), 'ALC' (Agro Logistic Center — gudang
// distribusi hasil olahan SAFCC), 'D1' (Dapur Induk), 'D2' (Dapur Satelit)
// Alur fisik: panen kawasan → SAFCC (olah/bersih) → ALC (simpan) → dapur SPPG
// Storage: window.IDSS.INVENTORY_LOTS / INVENTORY_TRANSAKSI / INVENTORY_PAR
// Semua di-persist via IDSSPersist (keys didaftarkan di bawah).
//
// Integrasi:
// - DapurDeliveryConfirmation → InventoryManager.receive(dapurId, ...)
// - AgroBahanBakuTracking (batch dibuat) → receive('SAFCC', ...)
// - Dapur: stok di bawah ROP → tombol "Minta ke SAFCC" membuat SAFCC_REQUEST
// =============================================================================
const { useState: useS_Inv, useEffect: useE_Inv, useMemo: useM_Inv } = React;

// ---- Umur simpan default per komoditas (hari) ----
const INVENTORY_SHELF_LIFE = {
  "Beras Premium": 180, "Beras": 180,
  "Ayam Karkas": 3, "Telur Ayam": 21,
  "Tahu Putih": 3, "Tempe": 4,
  "Sayur Kangkung": 2, "Bayam Segar": 3, "Sayur Bayam": 3,
  "Wortel": 14, "Pisang Cavendish": 6,
  "Minyak Goreng": 365, "Susu UHT": 90
};

const INVENTORY_LOKASI = {
  SAFCC: { label: "Gudang SAFCC", short: "SAFCC" },
  ALC: { label: "Agro Logistic Center", short: "ALC" },
  D1: { label: "Dapur Induk", short: "D1" },
  D2: { label: "Dapur Satelit", short: "D2" }
};

// ---- Seed PAR config + lots (deterministik, tanggal relatif hari ini) ----
(function seedInventory() {
  if (!window.IDSS) return;
  const today = new Date();
  const iso = (d) => d.toISOString().split("T")[0];
  const addDays = (base, n) => { const d = new Date(base); d.setDate(d.getDate() + n); return d; };

  let s = 13;
  const rnd = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };

  const parList = [];
  const lots = [];
  const txs = [];
  let lotCounter = 0;

  (window.IDSS.NERACA || []).forEach((n) => {
    const shelf = INVENTORY_SHELF_LIFE[n.komoditas] ?? 7;
    [["SAFCC", 0.02], ["ALC", 0.012], ["D1", 0.006], ["D2", 0.004]].forEach(([lok, f]) => {
      const avg = Math.max(4, Math.round(n.kebutuhan * f));
      const leadCover = lok === "SAFCC" || lok === "ALC" ? 3 : 2;
      const parCover = lok === "SAFCC" ? 7 : lok === "ALC" ? 6 : 4;
      parList.push({
        id: `PAR-${lok}-${n.komoditas}`,
        lokasi: lok, komoditas: n.komoditas, satuan: n.satuan,
        avgPakaiHarian: avg,
        reorderPoint: avg * leadCover,
        parLevel: avg * parCover,
        shelfLifeHari: shelf
      });

      // 1-3 lot per komoditas; total antara 0.4×ROP dan par (supaya ada item
      // yang jelas di bawah ROP dan ada lot mendekati kadaluarsa untuk demo alert)
      const rop = avg * leadCover, par = avg * parCover;
      const total = Math.round(rop * 0.4 + rnd() * (par - rop * 0.4));
      const nLots = 1 + Math.floor(rnd() * 3);
      let remaining = total;
      for (let i = 0; i < nLots && remaining > 0; i++) {
        const qty = i === nLots - 1 ? remaining : Math.max(1, Math.round(remaining * (0.3 + rnd() * 0.5)));
        remaining -= qty;
        const umur = Math.floor(rnd() * Math.max(1, Math.min(shelf, 10))); // sudah tersimpan berapa hari
        const masuk = addDays(today, -umur);
        const kadaluarsa = addDays(masuk, shelf);
        lotCounter++;
        const lotId = `LOT-${lok}-${String(lotCounter).padStart(3, "0")}`;
        lots.push({
          id: lotId, lokasi: lok, komoditas: n.komoditas, satuan: n.satuan,
          jumlah_awal: qty, jumlah_sisa: qty,
          tanggal_masuk: iso(masuk), kadaluarsa: iso(kadaluarsa),
          sumber: lok === "SAFCC" ? "Penerimaan supplier" : lok === "ALC" ? "Transfer SAFCC (hasil olahan)" : "Kiriman ALC",
          created_at: masuk.toISOString()
        });
        txs.push({
          id: `TX-SEED-${lotId}`, ts: masuk.toISOString(), lokasi: lok,
          komoditas: n.komoditas, tipe: "MASUK", qty, satuan: n.satuan,
          lotId, oleh: "seed", catatan: "Saldo awal (demo)"
        });
      }
    });
  });

  window.IDSS.INVENTORY_PAR = parList;
  if (!Array.isArray(window.IDSS.INVENTORY_LOTS) || window.IDSS.INVENTORY_LOTS.length === 0) {
    window.IDSS.INVENTORY_LOTS = lots;
  }
  if (!Array.isArray(window.IDSS.INVENTORY_TRANSAKSI) || window.IDSS.INVENTORY_TRANSAKSI.length === 0) {
    window.IDSS.INVENTORY_TRANSAKSI = txs;
  }

  // Daftarkan ke persistence (restore() dipanggil saat App boot — setelah file ini dieksekusi)
  if (window.IDSSPersist && !window.IDSSPersist.PERSISTED_KEYS.includes("INVENTORY_LOTS")) {
    window.IDSSPersist.PERSISTED_KEYS.push("INVENTORY_LOTS", "INVENTORY_TRANSAKSI");
  }
  if (window.IDSS.MESSAGE_TYPES) {
    window.IDSS.MESSAGE_TYPES.INVENTORY_UPDATED = "__inventory_updated";
  }
})();

// =============================================================================
// InventoryManager — API inti
// =============================================================================
const InventoryManager = {
  _lots: () => {
    if (!window.IDSS.INVENTORY_LOTS) window.IDSS.INVENTORY_LOTS = [];
    return window.IDSS.INVENTORY_LOTS;
  },

  getPar: (lokasi, komoditas) =>
    (window.IDSS.INVENTORY_PAR || []).find(p => p.lokasi === lokasi && p.komoditas === komoditas) || null,

  _newTxId: () => `TX-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`,
  _newLotId: (lokasi) => `LOT-${lokasi}-${Date.now().toString(36)}${Math.random().toString(36).substr(2, 3)}`.toUpperCase(),

  _log: (entry) => {
    if (!window.IDSS.INVENTORY_TRANSAKSI) window.IDSS.INVENTORY_TRANSAKSI = [];
    const tx = {
      id: InventoryManager._newTxId(),
      ts: new Date().toISOString(),
      oleh: sessionStorage.getItem("authedUser") || "unknown",
      ...entry
    };
    window.IDSS.INVENTORY_TRANSAKSI.push(tx);
    if (window.IDSS.INVENTORY_TRANSAKSI.length > 600) {
      window.IDSS.INVENTORY_TRANSAKSI = window.IDSS.INVENTORY_TRANSAKSI.slice(-600);
    }
    window.AuditLog?.log("inventory_" + entry.tipe.toLowerCase(), { komoditas: entry.komoditas, qty: entry.qty, lokasi: entry.lokasi });
    window.IDSSPersist?.scheduleSave();
    // Pakai postMessage langsung (bukan MessageBus) — event refresh murni,
    // tidak boleh kena dedupe konten MessageBus
    window.postMessage({ type: "__inventory_updated", lokasi: entry.lokasi, komoditas: entry.komoditas }, "*");
    return tx;
  },

  // --- MASUK: terima barang ke lokasi (lot baru). batchId opsional =
  //     tautan ke batch barcode (B-xxx) supaya traceability ikut alur fisik ---
  receive: (lokasi, { komoditas, qty, satuan, kadaluarsa, sumber, catatan, batchId }) => {
    const q = parseFloat(qty);
    if (!komoditas || isNaN(q) || q <= 0) return null;
    const par = InventoryManager.getPar(lokasi, komoditas);
    const unit = satuan || par?.satuan || "kg";
    let exp = kadaluarsa;
    if (!exp) {
      const shelf = par?.shelfLifeHari ?? INVENTORY_SHELF_LIFE[komoditas] ?? 7;
      const d = new Date(); d.setDate(d.getDate() + shelf);
      exp = d.toISOString().split("T")[0];
    }
    const lot = {
      id: InventoryManager._newLotId(lokasi),
      lokasi, komoditas, satuan: unit,
      jumlah_awal: q, jumlah_sisa: q,
      tanggal_masuk: new Date().toISOString().split("T")[0],
      kadaluarsa: exp,
      sumber: sumber || "Penerimaan",
      batchId: batchId || null,
      created_at: new Date().toISOString()
    };
    InventoryManager._lots().push(lot);
    InventoryManager._log({ lokasi, komoditas, tipe: "MASUK", qty: q, satuan: unit, lotId: lot.id, catatan: catatan || sumber || "" });
    return lot;
  },

  // Lot aktif suatu komoditas, urut FEFO (kadaluarsa terdekat dulu)
  getLotsFEFO: (lokasi, komoditas) =>
    InventoryManager._lots()
      .filter(l => l.lokasi === lokasi && l.komoditas === komoditas && l.jumlah_sisa > 0)
      .sort((a, b) => (a.kadaluarsa || "9999").localeCompare(b.kadaluarsa || "9999")),

  getTotal: (lokasi, komoditas) =>
    InventoryManager.getLotsFEFO(lokasi, komoditas).reduce((s, l) => s + l.jumlah_sisa, 0),

  // --- PAKAI: konsumsi FEFO. Return { ok, dipakai, kurang, slices } ---
  consume: (lokasi, komoditas, qty, { reason = "produksi", catatan = "", tipe = "PAKAI", log = true } = {}) => {
    const q = parseFloat(qty);
    if (isNaN(q) || q <= 0) return { ok: false, dipakai: 0, kurang: 0, slices: [] };
    const lots = InventoryManager.getLotsFEFO(lokasi, komoditas);
    const total = lots.reduce((s, l) => s + l.jumlah_sisa, 0);
    if (total < q) return { ok: false, dipakai: 0, kurang: q - total, tersedia: total, slices: [] };

    let sisa = q;
    const slices = [];
    for (const lot of lots) {
      if (sisa <= 0) break;
      const ambil = Math.min(lot.jumlah_sisa, sisa);
      lot.jumlah_sisa = Math.round((lot.jumlah_sisa - ambil) * 100) / 100;
      sisa -= ambil;
      slices.push({ lotId: lot.id, qty: ambil, kadaluarsa: lot.kadaluarsa, satuan: lot.satuan, batchId: lot.batchId || null });
    }
    if (log) {
      InventoryManager._log({
        lokasi, komoditas, tipe, qty: q,
        satuan: slices[0]?.satuan || "kg",
        lotId: slices.map(sl => sl.lotId).join(", "),
        catatan: [reason, catatan].filter(Boolean).join(" — ")
      });
    }
    return { ok: true, dipakai: q, kurang: 0, slices };
  },

  // --- TRANSFER: SAFCC → Dapur (FEFO di sumber, lot baru di tujuan, kadaluarsa ikut lot asal) ---
  transfer: (dari, ke, komoditas, qty, catatan = "") => {
    const res = InventoryManager.consume(dari, komoditas, qty, { log: false });
    if (!res.ok) return res;
    res.slices.forEach(sl => {
      InventoryManager._lots().push({
        id: InventoryManager._newLotId(ke),
        lokasi: ke, komoditas, satuan: sl.satuan,
        jumlah_awal: sl.qty, jumlah_sisa: sl.qty,
        tanggal_masuk: new Date().toISOString().split("T")[0],
        kadaluarsa: sl.kadaluarsa,
        sumber: `Transfer dari ${INVENTORY_LOKASI[dari]?.label || dari}`,
        batchId: sl.batchId || null,
        created_at: new Date().toISOString()
      });
    });
    InventoryManager._log({ lokasi: dari, komoditas, tipe: "TRANSFER-KELUAR", qty: parseFloat(qty), satuan: res.slices[0]?.satuan || "kg", lotId: res.slices.map(s => s.lotId).join(", "), catatan: `→ ${INVENTORY_LOKASI[ke]?.label || ke}. ${catatan}` });
    InventoryManager._log({ lokasi: ke, komoditas, tipe: "MASUK", qty: parseFloat(qty), satuan: res.slices[0]?.satuan || "kg", lotId: "", catatan: `Transfer dari ${INVENTORY_LOKASI[dari]?.label || dari}. ${catatan}` });
    // Traceability: lokasi batch barcode mengikuti perpindahan lot
    [...new Set(res.slices.map(s => s.batchId).filter(Boolean))]
      .forEach(b => window.BarcodeManager?.syncBatchLocationFromLots?.(b));
    return res;
  },

  // --- WASTE: buang sebagian/seluruh lot (kadaluarsa/rusak) ---
  waste: (lotId, qty, alasan = "Kadaluarsa") => {
    const lot = InventoryManager._lots().find(l => l.id === lotId);
    if (!lot) return false;
    const q = Math.min(parseFloat(qty) || lot.jumlah_sisa, lot.jumlah_sisa);
    if (q <= 0) return false;
    lot.jumlah_sisa = Math.round((lot.jumlah_sisa - q) * 100) / 100;
    InventoryManager._log({ lokasi: lot.lokasi, komoditas: lot.komoditas, tipe: "WASTE", qty: q, satuan: lot.satuan, lotId, catatan: alasan });
    return true;
  },

  // --- OPNAME: samakan stok sistem dengan hitungan fisik ---
  opname: (lokasi, komoditas, fisik, catatan = "") => {
    const f = parseFloat(fisik);
    if (isNaN(f) || f < 0) return null;
    const sistem = InventoryManager.getTotal(lokasi, komoditas);
    const selisih = Math.round((f - sistem) * 100) / 100;
    if (selisih < 0) {
      // stok fisik lebih sedikit → kurangi FEFO tanpa log PAKAI terpisah
      InventoryManager.consume(lokasi, komoditas, -selisih, { log: false });
    } else if (selisih > 0) {
      const par = InventoryManager.getPar(lokasi, komoditas);
      InventoryManager._lots().push({
        id: InventoryManager._newLotId(lokasi),
        lokasi, komoditas, satuan: par?.satuan || "kg",
        jumlah_awal: selisih, jumlah_sisa: selisih,
        tanggal_masuk: new Date().toISOString().split("T")[0],
        kadaluarsa: new Date(Date.now() + (par?.shelfLifeHari ?? 7) * 86400000).toISOString().split("T")[0],
        sumber: "Penyesuaian opname",
        created_at: new Date().toISOString()
      });
    }
    InventoryManager._log({
      lokasi, komoditas, tipe: "OPNAME",
      qty: selisih, satuan: InventoryManager.getPar(lokasi, komoditas)?.satuan || "kg",
      lotId: "", catatan: `Sistem ${sistem} → fisik ${f} (selisih ${selisih > 0 ? "+" : ""}${selisih}). ${catatan}`
    });
    return { sistem, fisik: f, selisih };
  },

  // --- Ringkasan stok per komoditas di satu lokasi ---
  getStok: (lokasi) => {
    const today = new Date().toISOString().split("T")[0];
    const soon = new Date(Date.now() + 3 * 86400000).toISOString().split("T")[0];
    return (window.IDSS.INVENTORY_PAR || [])
      .filter(p => p.lokasi === lokasi)
      .map(p => {
        const lots = InventoryManager.getLotsFEFO(lokasi, p.komoditas);
        const total = lots.reduce((s, l) => s + l.jumlah_sisa, 0);
        const expired = lots.filter(l => l.kadaluarsa < today).reduce((s, l) => s + l.jumlah_sisa, 0);
        const expSoon = lots.filter(l => l.kadaluarsa >= today && l.kadaluarsa <= soon).reduce((s, l) => s + l.jumlah_sisa, 0);
        const coverDays = p.avgPakaiHarian > 0 ? total / p.avgPakaiHarian : 99;
        const status = total <= 0 ? "habis"
          : total < p.reorderPoint * 0.5 ? "kritis"
          : total < p.reorderPoint ? "reorder"
          : "aman";
        const rekomendasi = Math.max(0, Math.ceil((p.parLevel - total) / 5) * 5);
        return { ...p, total: Math.round(total * 100) / 100, lots, expired, expSoon, coverDays, status, rekomendasi };
      });
  },

  getExpiring: (lokasi, hari = 3) => {
    const today = new Date().toISOString().split("T")[0];
    const limit = new Date(Date.now() + hari * 86400000).toISOString().split("T")[0];
    return InventoryManager._lots()
      .filter(l => l.lokasi === lokasi && l.jumlah_sisa > 0 && l.kadaluarsa <= limit)
      .sort((a, b) => a.kadaluarsa.localeCompare(b.kadaluarsa))
      .map(l => ({ ...l, expired: l.kadaluarsa < today }));
  },

  getLedger: ({ lokasi, komoditas, tipe, limit = 100 } = {}) => {
    let txs = window.IDSS.INVENTORY_TRANSAKSI || [];
    if (lokasi) txs = txs.filter(t => t.lokasi === lokasi);
    if (komoditas) txs = txs.filter(t => t.komoditas === komoditas);
    if (tipe) txs = txs.filter(t => t.tipe === tipe);
    return txs.slice().sort((a, b) => b.ts.localeCompare(a.ts)).slice(0, limit);
  },

  getSummary: (lokasi) => {
    const stok = InventoryManager.getStok(lokasi);
    const todayStr = new Date().toISOString().split("T")[0];
    const ledgerToday = (window.IDSS.INVENTORY_TRANSAKSI || []).filter(t => t.lokasi === lokasi && t.ts.startsWith(todayStr));
    return {
      totalKomoditas: stok.length,
      perluReorder: stok.filter(s => s.status === "reorder" || s.status === "kritis" || s.status === "habis").length,
      lotExpiring: InventoryManager.getExpiring(lokasi, 3).length,
      pakaiHariIni: ledgerToday.filter(t => t.tipe === "PAKAI").reduce((s, t) => s + (t.qty || 0), 0),
      masukHariIni: ledgerToday.filter(t => t.tipe === "MASUK").reduce((s, t) => s + (t.qty || 0), 0)
    };
  }
};
window.InventoryManager = InventoryManager;

// =============================================================================
// Komponen UI bersama
// =============================================================================
const INV_STATUS_META = {
  aman: { label: "Aman", pill: "ok" },
  reorder: { label: "Pesan ulang", pill: "warn" },
  kritis: { label: "Kritis", pill: "danger" },
  habis: { label: "Habis", pill: "danger" }
};

function InvStatusPill({ status }) {
  const m = INV_STATUS_META[status] || INV_STATUS_META.aman;
  return <span className={`pill ${m.pill}`}><span className="led"/>{m.label}</span>;
}

function ExpiryTag({ kadaluarsa }) {
  const today = new Date().toISOString().split("T")[0];
  const soon = new Date(Date.now() + 2 * 86400000).toISOString().split("T")[0];
  const expired = kadaluarsa < today;
  const near = !expired && kadaluarsa <= soon;
  const label = new Date(kadaluarsa + "T00:00:00").toLocaleDateString("id-ID", { day: "numeric", month: "short" });
  if (expired) return <span className="pill danger" title={kadaluarsa}><span className="led"/>Kadaluarsa {label}</span>;
  if (near) return <span className="pill warn" title={kadaluarsa}><span className="led"/>≤2 hari · {label}</span>;
  return <span className="pill neutral" title={kadaluarsa}>{label}</span>;
}

function InvKPI({ label, value, unit, tone }) {
  const color = tone === "danger" ? "var(--danger)" : tone === "warn" ? "var(--warn)" : tone === "accent" ? "var(--accent)" : "var(--ink)";
  const bg = tone === "danger" ? "var(--danger-50)" : tone === "warn" ? "var(--warn-50)" : tone === "accent" ? "var(--accent-50)" : "var(--surface)";
  const border = tone === "danger" ? "var(--danger-100)" : tone === "warn" ? "var(--warn-100)" : tone === "accent" ? "var(--accent-100)" : "var(--line)";
  return (
    <div style={{ padding: 16, background: bg, border: `1px solid ${border}`, borderRadius: "var(--radius-lg)" }}>
      <div className="eyebrow" style={{ marginBottom: 6 }}>{label}</div>
      <div style={{ fontSize: 26, fontWeight: 700, color, fontVariantNumeric: "tabular-nums" }}>
        {value}{unit && <span style={{ fontSize: 12, fontWeight: 500, color: "var(--ink-3)", marginLeft: 5 }}>{unit}</span>}
      </div>
    </div>
  );
}

// Modal opname (dipakai SAFCC & Dapur)
function OpnameModal({ lokasi, stok, onClose, onDone }) {
  const [komoditas, setKomoditas] = useS_Inv(stok[0]?.komoditas || "");
  const [fisik, setFisik] = useS_Inv("");
  const [catatan, setCatatan] = useS_Inv("");
  const item = stok.find(s => s.komoditas === komoditas);

  const submit = () => {
    if (!komoditas || fisik === "" || isNaN(parseFloat(fisik)) || parseFloat(fisik) < 0) {
      window.showToast("Masukkan hasil hitung fisik yang valid (≥ 0)", "warn", 2500);
      return;
    }
    const res = InventoryManager.opname(lokasi, komoditas, fisik, catatan);
    if (res) {
      const arah = res.selisih === 0 ? "tidak ada selisih" : res.selisih > 0 ? `+${res.selisih} (fisik lebih banyak)` : `${res.selisih} (fisik lebih sedikit)`;
      window.showToast(`Opname ${komoditas} tersimpan — ${arah}`, "success", 3500);
      onDone();
      onClose();
    }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal-content" onClick={e => e.stopPropagation()}>
        <div className="modal-header">
          <h2 className="h2">Stock opname — {INVENTORY_LOKASI[lokasi]?.label}</h2>
          <button className="btn ghost sm" onClick={onClose}>✕</button>
        </div>
        <div className="modal-body">
          <div className="field">
            <label>Komoditas</label>
            <select className="select" value={komoditas} onChange={e => { setKomoditas(e.target.value); setFisik(""); }}>
              {stok.map(s => <option key={s.komoditas} value={s.komoditas}>{s.komoditas}</option>)}
            </select>
          </div>
          {item && (
            <div style={{ padding: 12, background: "var(--bg-2)", borderRadius: "var(--radius)", marginBottom: 16, fontSize: 12.5 }}>
              Stok menurut sistem: <b className="mono">{item.total} {item.satuan}</b>
              <span className="muted"> · {item.lots.length} lot aktif</span>
            </div>
          )}
          <div className="field">
            <label>Hasil hitung fisik ({item?.satuan || "kg"})</label>
            <input className="input mono" type="number" min="0" step="0.1" value={fisik}
              onChange={e => setFisik(e.target.value)} placeholder="Contoh: 120.5"/>
          </div>
          {fisik !== "" && item && !isNaN(parseFloat(fisik)) && (
            <div style={{
              padding: 10, borderRadius: "var(--radius)", fontSize: 12.5, marginBottom: 14,
              background: parseFloat(fisik) === item.total ? "var(--accent-50)" : "var(--warn-50)",
              border: `1px solid ${parseFloat(fisik) === item.total ? "var(--accent-100)" : "var(--warn-100)"}`
            }}>
              Selisih: <b>{(parseFloat(fisik) - item.total) > 0 ? "+" : ""}{Math.round((parseFloat(fisik) - item.total) * 100) / 100} {item.satuan}</b>
              {parseFloat(fisik) !== item.total && " — akan dicatat sebagai penyesuaian OPNAME di riwayat"}
            </div>
          )}
          <div className="field">
            <label>Catatan (opsional)</label>
            <input className="input" value={catatan} onChange={e => setCatatan(e.target.value)} placeholder="mis. tumpahan saat produksi, salah catat"/>
          </div>
        </div>
        <div className="modal-footer">
          <button className="btn" onClick={onClose}>Batal</button>
          <button className="btn primary" onClick={submit}>Simpan opname</button>
        </div>
      </div>
    </div>
  );
}

// Form buang (waste) inline per lot
function WasteModal({ lot, onClose, onDone }) {
  const [qty, setQty] = useS_Inv(String(lot.jumlah_sisa));
  const [alasan, setAlasan] = useS_Inv("Kadaluarsa");
  const submit = () => {
    const q = parseFloat(qty);
    if (isNaN(q) || q <= 0 || q > lot.jumlah_sisa) {
      window.showToast(`Jumlah harus antara 0 dan ${lot.jumlah_sisa}`, "warn", 2500);
      return;
    }
    InventoryManager.waste(lot.id, q, alasan);
    window.showToast(`${q} ${lot.satuan} ${lot.komoditas} dicatat sebagai waste (${alasan})`, "success", 3000);
    onDone(); onClose();
  };
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal-content" onClick={e => e.stopPropagation()}>
        <div className="modal-header">
          <h2 className="h2">Buang stok — {lot.komoditas}</h2>
          <button className="btn ghost sm" onClick={onClose}>✕</button>
        </div>
        <div className="modal-body">
          <div style={{ padding: 12, background: "var(--bg-2)", borderRadius: "var(--radius)", marginBottom: 16, fontSize: 12.5 }}>
            Lot <span className="mono">{lot.id}</span> · sisa <b>{lot.jumlah_sisa} {lot.satuan}</b> · kadaluarsa {lot.kadaluarsa}
          </div>
          <div className="field">
            <label>Jumlah dibuang ({lot.satuan})</label>
            <input className="input mono" type="number" min="0" step="0.1" max={lot.jumlah_sisa} value={qty} onChange={e => setQty(e.target.value)}/>
          </div>
          <div className="field">
            <label>Alasan</label>
            <select className="select" value={alasan} onChange={e => setAlasan(e.target.value)}>
              {["Kadaluarsa", "Rusak / busuk", "Kontaminasi", "Kemasan rusak", "Lainnya"].map(a => <option key={a}>{a}</option>)}
            </select>
          </div>
        </div>
        <div className="modal-footer">
          <button className="btn" onClick={onClose}>Batal</button>
          <button className="btn danger" onClick={submit}>Catat waste</button>
        </div>
      </div>
    </div>
  );
}

// =============================================================================
// Layar inti (dipakai SAFCC & Dapur dengan konfigurasi berbeda)
// =============================================================================
function InventoryScreen({ lokasi, crumbsRoot, isDapur, dapurId }) {
  const { Tabs } = window.IDSSUI;
  const [tab, setTab] = useS_Inv("stok");
  const [tick, setTick] = useS_Inv(0);
  const refresh = () => setTick(t => t + 1);
  const [showOpname, setShowOpname] = useS_Inv(false);
  const [wasteLot, setWasteLot] = useS_Inv(null);
  const [lotFilter, setLotFilter] = useS_Inv("all");
  const [requestedSet, setRequestedSet] = useS_Inv({}); // komoditas → requestId (cegah double-click)

  // Form transfer (SAFCC) / pemakaian (Dapur)
  // Tujuan default SAFCC = ALC: alur baku hasil olahan SAFCC disimpan di ALC sebelum ke dapur
  const [aksiForm, setAksiForm] = useS_Inv({ komoditas: "", qty: "", tujuan: isDapur ? "D1" : "ALC", keperluan: "Produksi menu harian", catatan: "" });

  const stok = useM_Inv(() => InventoryManager.getStok(lokasi), [tick, lokasi]);
  const summary = useM_Inv(() => InventoryManager.getSummary(lokasi), [tick, lokasi]);
  const expiring = useM_Inv(() => InventoryManager.getExpiring(lokasi, 3), [tick, lokasi]);
  const ledger = useM_Inv(() => InventoryManager.getLedger({ lokasi, limit: 60 }), [tick, lokasi]);
  const allLots = useM_Inv(() =>
    InventoryManager._lots()
      .filter(l => l.lokasi === lokasi && l.jumlah_sisa > 0 && (lotFilter === "all" || l.komoditas === lotFilter))
      .sort((a, b) => a.kadaluarsa.localeCompare(b.kadaluarsa)),
    [tick, lokasi, lotFilter]);

  // Auto-refresh saat ada mutasi inventory dari screen/role lain
  useE_Inv(() => {
    const handler = (e) => { if (e.data?.type === "__inventory_updated") refresh(); };
    window.addEventListener("message", handler);
    return () => window.removeEventListener("message", handler);
  }, []);

  const lokasiMeta = INVENTORY_LOKASI[lokasi] || { label: lokasi };

  // --- Aksi: transfer (SAFCC) ---
  const doTransfer = () => {
    const { komoditas, qty, tujuan, catatan } = aksiForm;
    if (!komoditas || !qty || parseFloat(qty) <= 0) {
      window.showToast("Pilih komoditas dan isi jumlah transfer", "warn", 2500);
      return;
    }
    const res = InventoryManager.transfer(lokasi, tujuan, komoditas, qty, catatan);
    if (!res.ok) {
      window.showToast(`Stok tidak cukup — tersedia ${res.tersedia ?? 0}, diminta ${qty}`, "danger", 3500);
      return;
    }
    window.showToast(`Transfer ${qty} ${res.slices[0]?.satuan || "kg"} ${komoditas} → ${INVENTORY_LOKASI[tujuan]?.label} tercatat (FEFO: ${res.slices.length} lot)`, "success", 3500);
    setAksiForm(f => ({ ...f, qty: "", catatan: "" }));
    refresh();
  };

  // --- Aksi: pemakaian produksi (Dapur) ---
  const doConsume = () => {
    const { komoditas, qty, keperluan, catatan } = aksiForm;
    if (!komoditas || !qty || parseFloat(qty) <= 0) {
      window.showToast("Pilih komoditas dan isi jumlah pemakaian", "warn", 2500);
      return;
    }
    const res = InventoryManager.consume(lokasi, komoditas, qty, { reason: keperluan, catatan });
    if (!res.ok) {
      window.showToast(`Stok tidak cukup — tersedia ${res.tersedia ?? 0}, dibutuhkan ${qty}. Buat permintaan ke SAFCC dari tab Stok.`, "danger", 4500);
      return;
    }
    // Sinkronkan NERACA agar dashboard lain tetap konsisten
    window.NeracaManager?.useStock(komoditas, parseFloat(qty));
    window.showToast(`Pemakaian ${qty} ${res.slices[0]?.satuan || "kg"} ${komoditas} dicatat (FEFO dari ${res.slices.length} lot)`, "success", 3500);
    setAksiForm(f => ({ ...f, qty: "", catatan: "" }));
    refresh();
  };

  // --- Aksi: buat permintaan ke SAFCC untuk item di bawah ROP (Dapur) ---
  const requestToSAFCC = (item) => {
    if (requestedSet[item.komoditas]) {
      window.showToast(`Permintaan ${item.komoditas} sudah dibuat (${requestedSet[item.komoditas]})`, "info", 2500);
      return;
    }
    const jumlah = Math.max(item.rekomendasi, 5);
    const newRequest = {
      id: `REQ-${Date.now().toString(36).toUpperCase()}`,
      tanggalPermintaan: new Date().toISOString().split("T")[0],
      komoditas: item.komoditas,
      klasifikasi: "inventory_reorder",
      jumlahDiminta: jumlah,
      satuanDiminta: item.satuan,
      deadline: new Date(Date.now() + 2 * 86400000).toISOString().split("T")[0],
      dapur: dapurId === "D1" ? "Induk" : "Satelit",
      dapurId,
      dapurNama: window.getDapurName?.(dapurId),
      requestedBy: sessionStorage.getItem("authedUser") || "unknown",
      status: "pending",
      catatan: `Auto-reorder dari Inventory: stok ${item.total} ${item.satuan} < ROP ${item.reorderPoint} ${item.satuan}`
    };
    if (!Array.isArray(window.IDSS.SAFCC_REQUESTS)) window.IDSS.SAFCC_REQUESTS = [];
    window.IDSS.SAFCC_REQUESTS.push(newRequest);
    window.IDSSPersist?.scheduleSave();
    window.MessageBus?.send(window.IDSS.MESSAGE_TYPES.SAFCC_REQUESTS_UPDATED, {
      requests: window.IDSS.SAFCC_REQUESTS, newRequestId: newRequest.id,
      requestId: newRequest.id, komoditas: newRequest.komoditas, dapurId
    });
    window.AuditLog?.log("inventory_reorder_request", { requestId: newRequest.id, komoditas: item.komoditas, jumlah });
    setRequestedSet(r => ({ ...r, [item.komoditas]: newRequest.id }));
    window.showToast(`Permintaan ${jumlah} ${item.satuan} ${item.komoditas} terkirim ke SAFCC (${newRequest.id}) — pantau di menu Permintaan Komoditas`, "success", 4500);
  };

  const exportLedger = () => {
    const rows = InventoryManager.getLedger({ lokasi, limit: 600 }).map(t => [
      t.ts, t.tipe, t.komoditas, t.qty, t.satuan || "", t.lotId || "", t.oleh || "", (t.catatan || "").split('"').join("'")
    ]);
    if (rows.length === 0) { window.showToast("Belum ada transaksi untuk diexport", "warn", 2500); return; }
    window.ComplianceExport?.downloadCSV(
      `Inventory-${lokasi}-${new Date().toISOString().split("T")[0]}.csv`,
      ["Timestamp", "Tipe", "Komoditas", "Qty", "Satuan", "Lot", "Oleh", "Catatan"],
      rows
    );
  };

  const tabs = [
    { id: "stok", label: `Stok & Reorder (${stok.length})` },
    { id: "lot", label: `Lot & Kadaluarsa${expiring.length ? ` (${expiring.length})` : ""}` },
    isDapur ? { id: "pakai", label: "Catat pemakaian" } : { id: "transfer", label: "Transfer ke ALC/dapur" },
    { id: "riwayat", label: "Riwayat transaksi" }
  ];

  const tipeMeta = {
    "MASUK": { label: "Masuk", pill: "ok" },
    "PAKAI": { label: "Pakai", pill: "info" },
    "TRANSFER-KELUAR": { label: "Transfer keluar", pill: "warn" },
    "WASTE": { label: "Waste", pill: "danger" },
    "OPNAME": { label: "Opname", pill: "neutral" }
  };

  return (
    <>
      <div className="page-header">
        <div>
          <div className="crumbs"><span>{crumbsRoot}</span><span>Inventory control</span></div>
          <h1 className="page-title">Inventory {lokasiMeta.label}</h1>
          <div className="page-sub">Kontrol stok berbasis lot: FEFO, reorder point, kadaluarsa, opname, dan riwayat lengkap</div>
        </div>
        <div className="row gap-sm">
          <button className="btn" onClick={exportLedger}>Export CSV</button>
          <button className="btn primary" onClick={() => setShowOpname(true)}>Stock opname</button>
        </div>
      </div>

      {/* KPI */}
      <div className="grid cols-4" style={{ marginBottom: 20 }}>
        <InvKPI label="Komoditas dikelola" value={summary.totalKomoditas} unit="SKU"/>
        <InvKPI label="Perlu pesan ulang" value={summary.perluReorder} unit="item" tone={summary.perluReorder > 0 ? "warn" : "accent"}/>
        <InvKPI label="Lot ≤3 hari / kadaluarsa" value={summary.lotExpiring} unit="lot" tone={summary.lotExpiring > 0 ? "danger" : "accent"}/>
        {isDapur
          ? <InvKPI label="Pemakaian hari ini" value={Math.round(summary.pakaiHariIni)} unit="kg/L" tone="accent"/>
          : <InvKPI label="Barang masuk hari ini" value={Math.round(summary.masukHariIni)} unit="kg/L" tone="accent"/>}
      </div>

      {/* Alert kadaluarsa ringkas */}
      {expiring.length > 0 && (
        <div className="alert danger" style={{ marginBottom: 20 }}>
          <div>
            <div className="alert-title">{expiring.length} lot mendekati / melewati kadaluarsa</div>
            <div className="alert-body">
              {expiring.slice(0, 3).map(l => `${l.komoditas} (${l.jumlah_sisa} ${l.satuan}, ${l.expired ? "kadaluarsa" : "s/d"} ${l.kadaluarsa})`).join(" · ")}
              {expiring.length > 3 && ` · +${expiring.length - 3} lainnya`}
              {" — "}gunakan lebih dulu (FEFO) atau catat sebagai waste di tab Lot & Kadaluarsa.
            </div>
          </div>
        </div>
      )}

      <Tabs tabs={tabs} value={tab} onChange={setTab}/>

      {/* ===== TAB: STOK & REORDER ===== */}
      {tab === "stok" && (
        <div className="card" style={{ marginTop: 16 }}>
          <div style={{ overflowX: "auto" }}>
            <table className="data">
              <thead>
                <tr>
                  <th>Komoditas</th>
                  <th className="num">Stok</th>
                  <th style={{ minWidth: 160 }}>Level vs par</th>
                  <th className="num">Cover</th>
                  <th className="num">ROP / par</th>
                  <th>Status</th>
                  <th>Aksi</th>
                </tr>
              </thead>
              <tbody>
                {stok.map(s => (
                  <tr key={s.komoditas}>
                    <td>
                      <b>{s.komoditas}</b>
                      {s.expSoon > 0 && <div style={{ fontSize: 11, color: "var(--warn)" }}>{s.expSoon} {s.satuan} exp ≤3 hari</div>}
                      {s.expired > 0 && <div style={{ fontSize: 11, color: "var(--danger)" }}>✕ {s.expired} {s.satuan} kadaluarsa</div>}
                    </td>
                    <td className="num"><b>{s.total}</b> <span className="muted">{s.satuan}</span></td>
                    <td>
                      <div className={`bar ${s.status === "aman" ? "accent" : s.status === "reorder" ? "warn" : "danger"}`} title={`${s.total}/${s.parLevel} ${s.satuan}`}>
                        <span style={{ width: `${Math.min(100, (s.total / Math.max(1, s.parLevel)) * 100)}%` }}/>
                      </div>
                      <div style={{ fontSize: 10.5, color: "var(--ink-3)", marginTop: 3 }}>
                        pemakaian ±{s.avgPakaiHarian} {s.satuan}/hari
                      </div>
                    </td>
                    <td className="num">{s.coverDays >= 99 ? "—" : `${s.coverDays.toFixed(1)} hr`}</td>
                    <td className="num">{s.reorderPoint} / {s.parLevel}</td>
                    <td><InvStatusPill status={s.status}/></td>
                    <td>
                      {s.status !== "aman" ? (
                        isDapur ? (
                          <button className="btn sm primary" disabled={!!requestedSet[s.komoditas]} onClick={() => requestToSAFCC(s)}>
                            {requestedSet[s.komoditas] ? "✓ Diminta" : `Minta ${s.rekomendasi} ${s.satuan}`}
                          </button>
                        ) : (
                          <span style={{ fontSize: 11.5, color: "var(--warn)", fontWeight: 600 }}>
                            Rekomendasi order: {s.rekomendasi} {s.satuan}
                          </span>
                        )
                      ) : (
                        !isDapur ? (
                          <button className="btn sm" onClick={() => { setAksiForm(f => ({ ...f, komoditas: s.komoditas })); setTab("transfer"); }}>
                            Transfer →
                          </button>
                        ) : <span className="muted" style={{ fontSize: 11.5 }}>—</span>
                      )}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <div style={{ padding: "10px 16px", fontSize: 11.5, color: "var(--ink-3)", borderTop: "1px solid var(--line)" }}>
            <b>ROP (Reorder Point)</b> = titik pemesanan ulang (≈ pemakaian × lead time). <b>Par</b> = level stok ideal.
            Status <b>Pesan Ulang</b> muncul saat stok &lt; ROP; <b>Kritis</b> saat &lt; 50% ROP.
          </div>
        </div>
      )}

      {/* ===== TAB: LOT & KADALUARSA ===== */}
      {tab === "lot" && (
        <div className="card" style={{ marginTop: 16 }}>
          <div className="card-head">
            <h2 className="h2">Lot aktif — urut FEFO (kadaluarsa terdekat dulu)</h2>
            <select className="select" style={{ padding: "6px 10px", fontSize: 12 }} value={lotFilter} onChange={e => setLotFilter(e.target.value)}>
              <option value="all">Semua komoditas</option>
              {stok.map(s => <option key={s.komoditas} value={s.komoditas}>{s.komoditas}</option>)}
            </select>
          </div>
          <div style={{ overflowX: "auto" }}>
            <table className="data">
              <thead>
                <tr>
                  <th>Lot</th><th>Komoditas</th><th className="num">Sisa / awal</th>
                  <th>Masuk</th><th>Kadaluarsa</th><th>Sumber</th><th>Aksi</th>
                </tr>
              </thead>
              <tbody>
                {allLots.length === 0 && (
                  <tr><td colSpan={7} style={{ textAlign: "center", color: "var(--ink-3)", padding: 28 }}>Tidak ada lot aktif</td></tr>
                )}
                {allLots.map(l => (
                  <tr key={l.id}>
                    <td className="mono" style={{ fontSize: 11 }}>{l.id}</td>
                    <td><b>{l.komoditas}</b></td>
                    <td className="num">{l.jumlah_sisa} / {l.jumlah_awal} {l.satuan}</td>
                    <td>{l.tanggal_masuk}</td>
                    <td><ExpiryTag kadaluarsa={l.kadaluarsa}/></td>
                    <td style={{ fontSize: 11.5, color: "var(--ink-2)" }}>{l.sumber}</td>
                    <td><button className="btn sm" onClick={() => setWasteLot(l)}>Buang</button></td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {/* ===== TAB: TRANSFER (SAFCC) ===== */}
      {tab === "transfer" && !isDapur && (
        <div className="grid cols-2" style={{ marginTop: 16, alignItems: "start" }}>
          <div className="card">
            <div className="card-head"><h2 className="h2">Transfer stok ke ALC / dapur</h2></div>
            <div className="card-body">
              <div className="field">
                <label>Komoditas</label>
                <select className="select" value={aksiForm.komoditas} onChange={e => setAksiForm(f => ({ ...f, komoditas: e.target.value }))}>
                  <option value="">— pilih —</option>
                  {stok.filter(s => s.total > 0).map(s => (
                    <option key={s.komoditas} value={s.komoditas}>{s.komoditas} (stok {s.total} {s.satuan})</option>
                  ))}
                </select>
              </div>
              <div className="grid cols-2" style={{ gap: 12 }}>
                <div className="field">
                  <label>Jumlah</label>
                  <input className="input mono" type="number" min="0" step="0.1" value={aksiForm.qty}
                    onChange={e => setAksiForm(f => ({ ...f, qty: e.target.value }))} placeholder="0"/>
                </div>
                <div className="field">
                  <label>Tujuan</label>
                  <select className="select" value={aksiForm.tujuan} onChange={e => setAksiForm(f => ({ ...f, tujuan: e.target.value }))}>
                    <option value="ALC">Agro Logistic Center (ALC) — direkomendasikan</option>
                    <option value="D1">Dapur Induk (D1) — jalur darurat</option>
                    <option value="D2">Dapur Satelit (D2) — jalur darurat</option>
                  </select>
                </div>
              </div>
              <div className="field">
                <label>Catatan (opsional)</label>
                <input className="input" value={aksiForm.catatan} onChange={e => setAksiForm(f => ({ ...f, catatan: e.target.value }))} placeholder="mis. untuk produksi besok pagi"/>
              </div>
              <button className="btn primary" style={{ width: "100%", justifyContent: "center" }} onClick={doTransfer}>Kirim transfer</button>
              <div style={{ marginTop: 12, fontSize: 11.5, color: "var(--ink-3)", lineHeight: 1.5 }}>
                Sistem otomatis mengambil dari lot dengan kadaluarsa terdekat (FEFO). Tanggal kadaluarsa ikut berpindah ke lot tujuan.
                <br/><b>Alur baku:</b> hasil olahan SAFCC disimpan di <b>ALC</b>; pengiriman ke dapur dilakukan ALC lewat menu <b>Agro Logistic Center</b>. Transfer langsung ke dapur hanya untuk kondisi darurat.
              </div>
            </div>
          </div>
          <div className="card">
            <div className="card-head"><h2 className="h2">Riwayat transfer terakhir</h2></div>
            <div className="card-body tight" style={{ display: "flex", flexDirection: "column", gap: 8, maxHeight: 420, overflowY: "auto" }}>
              {InventoryManager.getLedger({ lokasi, tipe: "TRANSFER-KELUAR", limit: 12 }).map(t => (
                <div key={t.id} style={{ padding: 10, background: "var(--bg-2)", borderRadius: "var(--radius)", fontSize: 12 }}>
                  <b>{t.komoditas}</b> · {t.qty} {t.satuan} <span className="muted">· {new Date(t.ts).toLocaleString("id-ID", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" })}</span>
                  <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>{t.catatan}</div>
                </div>
              ))}
              {InventoryManager.getLedger({ lokasi, tipe: "TRANSFER-KELUAR", limit: 1 }).length === 0 && (
                <div style={{ textAlign: "center", color: "var(--ink-3)", fontSize: 12, padding: 20 }}>Belum ada transfer</div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* ===== TAB: CATAT PEMAKAIAN (DAPUR) ===== */}
      {tab === "pakai" && isDapur && (
        <div className="grid cols-2" style={{ marginTop: 16, alignItems: "start" }}>
          <div className="card">
            <div className="card-head"><h2 className="h2">Catat pemakaian bahan</h2></div>
            <div className="card-body">
              <div className="field">
                <label>Komoditas</label>
                <select className="select" value={aksiForm.komoditas} onChange={e => setAksiForm(f => ({ ...f, komoditas: e.target.value }))}>
                  <option value="">— pilih —</option>
                  {stok.map(s => (
                    <option key={s.komoditas} value={s.komoditas}>{s.komoditas} (stok {s.total} {s.satuan})</option>
                  ))}
                </select>
              </div>
              <div className="grid cols-2" style={{ gap: 12 }}>
                <div className="field">
                  <label>Jumlah dipakai</label>
                  <input className="input mono" type="number" min="0" step="0.1" value={aksiForm.qty}
                    onChange={e => setAksiForm(f => ({ ...f, qty: e.target.value }))} placeholder="0"/>
                </div>
                <div className="field">
                  <label>Keperluan</label>
                  <select className="select" value={aksiForm.keperluan} onChange={e => setAksiForm(f => ({ ...f, keperluan: e.target.value }))}>
                    <option>Produksi menu harian</option>
                    <option>Produksi menu tambahan</option>
                    <option>Uji coba menu</option>
                    <option>Lainnya</option>
                  </select>
                </div>
              </div>
              <div className="field">
                <label>Catatan (opsional)</label>
                <input className="input" value={aksiForm.catatan} onChange={e => setAksiForm(f => ({ ...f, catatan: e.target.value }))} placeholder="mis. menu Nasi Kuning + Ayam Goreng, 3000 porsi"/>
              </div>
              <button className="btn primary" style={{ width: "100%", justifyContent: "center" }} onClick={doConsume}>Catat pemakaian</button>
              <div style={{ marginTop: 12, fontSize: 11.5, color: "var(--ink-3)", lineHeight: 1.5 }}>
                Pemakaian dipotong dari lot dengan kadaluarsa terdekat (FEFO) dan otomatis menyinkronkan neraca komoditas.
                <br/>Menu yang disimpan lewat <b>Optimasi Menu</b> sudah otomatis memotong stok — gunakan form ini hanya untuk pemakaian di luar menu tersimpan (mis. uji coba, tambahan) agar tidak tercatat ganda.
              </div>
            </div>
          </div>
          <div className="card">
            <div className="card-head"><h2 className="h2">Pemakaian terakhir</h2></div>
            <div className="card-body tight" style={{ display: "flex", flexDirection: "column", gap: 8, maxHeight: 420, overflowY: "auto" }}>
              {InventoryManager.getLedger({ lokasi, tipe: "PAKAI", limit: 12 }).map(t => (
                <div key={t.id} style={{ padding: 10, background: "var(--bg-2)", borderRadius: "var(--radius)", fontSize: 12 }}>
                  <b>{t.komoditas}</b> · {t.qty} {t.satuan} <span className="muted">· {new Date(t.ts).toLocaleString("id-ID", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" })}</span>
                  <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>{t.catatan}</div>
                </div>
              ))}
              {InventoryManager.getLedger({ lokasi, tipe: "PAKAI", limit: 1 }).length === 0 && (
                <div style={{ textAlign: "center", color: "var(--ink-3)", fontSize: 12, padding: 20 }}>Belum ada pemakaian tercatat</div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* ===== TAB: RIWAYAT ===== */}
      {tab === "riwayat" && (
        <div className="card" style={{ marginTop: 16 }}>
          <div className="card-head">
            <h2 className="h2">Riwayat transaksi ({ledger.length} terakhir)</h2>
            <button className="btn sm" onClick={exportLedger}>Export CSV</button>
          </div>
          <div style={{ overflowX: "auto" }}>
            <table className="data">
              <thead>
                <tr><th>Waktu</th><th>Tipe</th><th>Komoditas</th><th className="num">Qty</th><th>Oleh</th><th>Catatan</th></tr>
              </thead>
              <tbody>
                {ledger.length === 0 && (
                  <tr><td colSpan={6} style={{ textAlign: "center", color: "var(--ink-3)", padding: 28 }}>Belum ada transaksi</td></tr>
                )}
                {ledger.map(t => {
                  const m = tipeMeta[t.tipe] || { label: t.tipe, pill: "neutral" };
                  return (
                    <tr key={t.id}>
                      <td className="mono" style={{ fontSize: 11, whiteSpace: "nowrap" }}>
                        {new Date(t.ts).toLocaleString("id-ID", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" })}
                      </td>
                      <td><span className={`pill ${m.pill}`}><span className="led"/>{m.label}</span></td>
                      <td><b>{t.komoditas}</b></td>
                      <td className="num">{t.tipe === "OPNAME" && t.qty > 0 ? "+" : ""}{t.qty} {t.satuan}</td>
                      <td style={{ fontSize: 11.5 }}>{t.oleh}</td>
                      <td style={{ fontSize: 11.5, color: "var(--ink-2)", maxWidth: 320 }}>{t.catatan}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {showOpname && <OpnameModal lokasi={lokasi} stok={stok} onClose={() => setShowOpname(false)} onDone={refresh}/>}
      {wasteLot && <WasteModal lot={wasteLot} onClose={() => setWasteLot(null)} onDone={refresh}/>}
    </>
  );
}

// ===== Wrapper per role =====
function AgroInventory() {
  return <InventoryScreen lokasi="SAFCC" crumbsRoot="Smart Agro" isDapur={false}/>;
}

function DapurInventory({ role }) {
  const dapurId = window.getDapurId(role) || "D1";
  return <InventoryScreen lokasi={dapurId} crumbsRoot={window.getDapurName(dapurId)} isDapur={true} dapurId={dapurId}/>;
}

window.AgroInventory = AgroInventory;
window.DapurInventory = DapurInventory;

// =============================================================================
// AGRO LOGISTIC CENTER (ALC) — layar terpusat di role SAFCC
// =============================================================================
// ALC = gudang distribusi bahan produksi. Hasil olahan SAFCC (sayur bersih/
// frozen, ikan mentah/olahan, dst) dibawa & disimpan di ALC; saat ada
// permintaan dapur SPPG, ALC yang mengirim langsung ke dapur.
//
// Data flow yang tersambung:
// 1. SAFCC validasi kiriman supplier → stok Gudang SAFCC (status req "fulfilled")
// 2. Tab "Inbound SAFCC" : tarik hasil olahan Gudang SAFCC → stok ALC (FEFO)
// 3. Tab "Permintaan Dapur": kirim stok ALC → dapur; request jadi "shipped"
// + dibuat entri fulfillment PENDING sehingga muncul di layar dapur
// "Konfirmasi Penerimaan" (dapur verifikasi fisik → stok Inventory Dapur)
// =============================================================================
const ALC_BENTUK_OLAHAN = ["Segar (sudah dibersihkan)", "Frozen / beku", "Olahan setengah jadi", "Kering / kemasan"];

// Status request yang masih bisa dilayani ALC (belum terkirim ke dapur)
const ALC_SERVICEABLE_STATUS = ["pending", "partial", "pending_fulfillment", "ready_to_ship", "fulfilled"];

// Label fase memakai kamus status tunggal — konsisten dengan dapur & supplier
const ALC_REQ_STATUS_META = window.IDSS.REQUEST_STATUS_META || {};

function AgroALC() {
  const { Tabs } = window.IDSSUI;
  const [tab, setTab] = useS_Inv("permintaan");
  const [tick, setTick] = useS_Inv(0);
  const refresh = () => setTick(t => t + 1);
  const [showOpname, setShowOpname] = useS_Inv(false);
  const [wasteLot, setWasteLot] = useS_Inv(null);
  const [inForm, setInForm] = useS_Inv({ komoditas: "", qty: "", bentuk: ALC_BENTUK_OLAHAN[0], catatan: "" });
  const [shipForm, setShipForm] = useS_Inv({}); // requestId → qty yang akan dikirim

  const stokALC = useM_Inv(() => InventoryManager.getStok("ALC"), [tick]);
  const stokSAFCC = useM_Inv(() => InventoryManager.getStok("SAFCC"), [tick]);
  const summary = useM_Inv(() => InventoryManager.getSummary("ALC"), [tick]);
  const expiring = useM_Inv(() => InventoryManager.getExpiring("ALC", 3), [tick]);
  const ledger = useM_Inv(() => InventoryManager.getLedger({ lokasi: "ALC", limit: 60 }), [tick]);
  const lotsALC = useM_Inv(() =>
    InventoryManager._lots()
      .filter(l => l.lokasi === "ALC" && l.jumlah_sisa > 0)
      .sort((a, b) => a.kadaluarsa.localeCompare(b.kadaluarsa)),
    [tick]);

  const activeRequests = useM_Inv(() =>
    (window.IDSS.SAFCC_REQUESTS || [])
      .filter(r => ALC_SERVICEABLE_STATUS.includes(r.status))
      .slice()
      .sort((a, b) => (a.deadline || "9999").localeCompare(b.deadline || "9999")),
    [tick]);

  const dikirimHariIni = useM_Inv(() => {
    const todayStr = new Date().toISOString().split("T")[0];
    return (window.IDSS.INVENTORY_TRANSAKSI || [])
      .filter(t => t.lokasi === "ALC" && t.tipe === "TRANSFER-KELUAR" && t.ts.startsWith(todayStr))
      .reduce((s, t) => s + (t.qty || 0), 0);
  }, [tick]);

  // Kiriman ALC terakhir — untuk memantau mana yang sudah/belum dikonfirmasi dapur
  const kirimanALC = useM_Inv(() =>
    (window.IDSS.SUPPLIER_FULFILLMENT_SUBMISSIONS || [])
      .filter(f => f.sumber === "ALC")
      .slice(-10)
      .reverse(),
    [tick]);

  // Auto-refresh saat inventory berubah, ada permintaan baru, atau dapur konfirmasi terima
  useE_Inv(() => {
    const handler = (e) => {
      const t = e.data?.type;
      const MT = window.IDSS?.MESSAGE_TYPES || {};
      if (t === "__inventory_updated" || t === MT.SAFCC_REQUESTS_UPDATED || t === MT.DELIVERY_RECEIVED) refresh();
    };
    window.addEventListener("message", handler);
    return () => window.removeEventListener("message", handler);
  }, []);

  // --- Inbound: tarik hasil olahan dari Gudang SAFCC ke ALC ---
  const tarikDariSAFCC = () => {
    const { komoditas, qty, bentuk, catatan } = inForm;
    if (!komoditas || !qty || parseFloat(qty) <= 0) {
      window.showToast("Pilih komoditas dan isi jumlah yang ditarik dari SAFCC", "warn", 2500);
      return;
    }
    const res = InventoryManager.transfer("SAFCC", "ALC", komoditas, qty, `Hasil olahan: ${bentuk}${catatan ? ` — ${catatan}` : ""}`);
    if (!res.ok) {
      window.showToast(`Stok Gudang SAFCC tidak cukup — tersedia ${res.tersedia ?? 0}, diminta ${qty}`, "danger", 3500);
      return;
    }
    window.AuditLog?.log("alc_inbound", { komoditas, qty: parseFloat(qty), bentuk });
    window.showToast(`${qty} ${res.slices[0]?.satuan || "kg"} ${komoditas} (${bentuk}) masuk ALC dari Gudang SAFCC (FEFO: ${res.slices.length} lot)`, "success", 3500);
    setInForm(f => ({ ...f, qty: "", catatan: "" }));
    refresh();
  };

  // --- Outbound: penuhi permintaan dapur dari stok ALC ---
  const kirimKeDapur = (req) => {
    // A4: dapur tujuan harus tunggal & jelas — kiriman tanpa dapur tujuan tidak
    // akan pernah muncul di layar konfirmasi dapur mana pun (fail-closed)
    const dapurTujuan = window.resolveDapurId?.(req);
    if (!dapurTujuan) {
      window.showToast(`Request ${req.id} tidak punya dapur tujuan tunggal — perbarui request-nya dulu (satu request = satu dapur).`, "danger", 5000);
      return;
    }
    const tersedia = InventoryManager.getTotal("ALC", req.komoditas);
    const qty = parseFloat(shipForm[req.id] ?? req.jumlahDiminta);
    if (isNaN(qty) || qty <= 0) {
      window.showToast("Isi jumlah kirim yang valid (> 0)", "warn", 2500);
      return;
    }
    if (qty > tersedia) {
      window.showToast(`Stok ALC ${req.komoditas} tidak cukup — tersedia ${tersedia}, diminta ${qty}. Ambil dulu dari Gudang SAFCC di tab 1.`, "danger", 4500);
      return;
    }

    // 1. Potong stok ALC (FEFO) — tercatat sebagai TRANSFER-KELUAR di ledger ALC
    const dapurNama = req.dapurNama || (req.dapur ? `Dapur ${req.dapur}` : "Dapur");
    const res = InventoryManager.consume("ALC", req.komoditas, qty, {
      tipe: "TRANSFER-KELUAR",
      reason: `Kirim ke ${dapurNama}`,
      catatan: `Pemenuhan permintaan ${req.id}`
    });
    if (!res.ok) {
      window.showToast(`Gagal memotong stok ALC (tersedia ${res.tersedia ?? 0})`, "danger", 3500);
      return;
    }

    // 2. Buat entri fulfillment PENDING → muncul di layar dapur "Konfirmasi
    // Penerimaan"; stok masuk Inventory Dapur saat dapur konfirmasi fisik
    // (bukan di sini, agar tidak dobel hitung).
    const now = new Date();
    const persentase = Math.min(100, Math.round((qty / (req.jumlahDiminta || qty)) * 100));
    const fulfillment = {
      id: `ALC-${Date.now().toString(36).toUpperCase()}`,
      requestId: req.id,
      tanggalSubmit: now.toISOString().split("T")[0],
      komoditas: req.komoditas,
      jumlahDiminta: req.jumlahDiminta,
      jumlahDiberikan: qty,
      persentase: String(persentase),
      satuan: req.satuanDiminta || res.slices[0]?.satuan || "kg",
      status: "PENDING",
      statusHistory: [
        { status: "PENDING", timestamp: now.toISOString(), reason: "ALC mengirim bahan ke dapur (menunggu konfirmasi fisik dapur)" }
      ],
      catatan: `Dikirim dari Agro Logistic Center (FEFO ${res.slices.length} lot)`,
      dapur: req.dapur,
      dapurId: dapurTujuan,
      dapurNama: req.dapurNama || window.getDapurName?.(dapurTujuan),
      deadline: req.deadline,
      sumber: "ALC",
      // Traceability: batch bahan baku yang ikut terkirim (dari lot FEFO) —
      // saat dapur konfirmasi, status batch pindah ke di_dapur_Dx
      bahan_baku_batches: [...new Set(res.slices.map(s => s.batchId).filter(Boolean))],
      submittedBy: sessionStorage.getItem("authedUser") || "ALC — SAFCC",
      _timestamp: now.toISOString()
    };
    if (!Array.isArray(window.IDSS.SUPPLIER_FULFILLMENT_SUBMISSIONS)) window.IDSS.SUPPLIER_FULFILLMENT_SUBMISSIONS = [];
    window.IDSS.SUPPLIER_FULFILLMENT_SUBMISSIONS.push(fulfillment);

    // 3. Sinkronkan lokasi batch yang masih tersisa di ALC/SAFCC
    fulfillment.bahan_baku_batches.forEach(b => window.BarcodeManager?.syncBatchLocationFromLots?.(b));

    // 4. Status request via mesin status tunggal (persist + broadcast di dalamnya)
    window.RequestFlow?.set(req.id, "shipped", {
      shippedVia: "ALC", shippedAt: now.toISOString(), alcShipmentId: fulfillment.id
    });

    // 5. Broadcast kiriman ke layar dapur (badge + daftar konfirmasi)
    window.MessageBus?.send(window.IDSS.MESSAGE_TYPES.ALC_SHIPMENT_CREATED, fulfillment);
    window.AuditLog?.log("alc_shipment", {
      fulfillmentId: fulfillment.id, requestId: req.id, komoditas: req.komoditas,
      qty, dapur: fulfillment.dapurId || req.dapur
    });

    window.showToast(`${qty} ${fulfillment.satuan} ${req.komoditas} dikirim ALC → ${dapurNama} (${req.id}). Menunggu konfirmasi fisik di layar dapur "Konfirmasi Penerimaan".`, "success", 5000);
    setShipForm(f => { const n = { ...f }; delete n[req.id]; return n; });
    refresh();
  };

  const exportLedgerALC = () => {
    const rows = InventoryManager.getLedger({ lokasi: "ALC", limit: 600 }).map(t => [
      t.ts, t.tipe, t.komoditas, t.qty, t.satuan || "", t.lotId || "", t.oleh || "", (t.catatan || "").split('"').join("'")
    ]);
    if (rows.length === 0) { window.showToast("Belum ada transaksi ALC untuk diexport", "warn", 2500); return; }
    window.ComplianceExport?.downloadCSV(
      `ALC-Ledger-${new Date().toISOString().split("T")[0]}.csv`,
      ["Timestamp", "Tipe", "Komoditas", "Qty", "Satuan", "Lot", "Oleh", "Catatan"],
      rows
    );
  };

  const tabs = [
    { id: "inbound", label: "1 · Ambil stok dari SAFCC" },
    { id: "permintaan", label: `2 · Kirim ke dapur (${activeRequests.length})` },
    { id: "stok", label: `Stok & Lot ALC (${stokALC.filter(s => s.total > 0).length})` },
    { id: "riwayat", label: "Riwayat" }
  ];

  const tipeMeta = {
    "MASUK": { label: "Masuk", pill: "ok" },
    "TRANSFER-KELUAR": { label: "Kirim ke dapur", pill: "warn" },
    "WASTE": { label: "Waste", pill: "danger" },
    "OPNAME": { label: "Opname", pill: "neutral" }
  };

  return (
    <>
      <div className="page-header">
        <div>
          <div className="crumbs"><span>Smart Agro</span><span>Distribusi</span><span>Agro Logistic Center</span></div>
          <h1 className="page-title">Agro Logistic Center (ALC)</h1>
          <div className="page-sub">Gudang distribusi hasil olahan SAFCC — panen kawasan diolah SAFCC, disimpan di ALC, lalu ALC mengirim langsung ke dapur SPPG saat ada permintaan</div>
        </div>
        <div className="row gap-sm">
          <button className="btn" onClick={exportLedgerALC}>Export CSV</button>
          <button className="btn primary" onClick={() => setShowOpname(true)}>Stock opname</button>
        </div>
      </div>

      {/* Diagram alur ringkas */}
      <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", padding: "10px 14px", background: "var(--bg-2)", border: "1px solid var(--line)", borderRadius: "var(--radius-lg)", marginBottom: 18, fontSize: 12 }}>
        {[
          { label: "Panen kawasan" },
          { label: "SAFCC (olah/bersih)" },
          { label: "ALC (simpan)", active: true },
          { label: "Dapur SPPG" },
          { label: "Penerima Manfaat" }
        ].map((s, i, arr) => (
          <React.Fragment key={s.label}>
            <span style={{
              display: "inline-flex", alignItems: "center", gap: 6, padding: "5px 10px", borderRadius: 999,
              background: s.active ? "var(--primary-50)" : "var(--surface)",
              border: `1px solid ${s.active ? "var(--primary)" : "var(--line)"}`,
              fontWeight: s.active ? 700 : 500, color: s.active ? "var(--primary)" : "var(--ink-2)"
            }}>{s.label}</span>
            {i < arr.length - 1 && <span style={{ color: "var(--ink-3)" }}>→</span>}
          </React.Fragment>
        ))}
      </div>

      {/* KPI */}
      <div className="grid cols-4" style={{ marginBottom: 20 }}>
        <InvKPI label="Permintaan dapur aktif" value={activeRequests.length} unit="request" tone={activeRequests.length > 0 ? "warn" : "accent"}/>
        <InvKPI label="Komoditas tersimpan" value={stokALC.filter(s => s.total > 0).length} unit="SKU"/>
        <InvKPI label="Lot ≤3 hari / kadaluarsa" value={summary.lotExpiring} unit="lot" tone={summary.lotExpiring > 0 ? "danger" : "accent"}/>
        <InvKPI label="Dikirim ke dapur hari ini" value={Math.round(dikirimHariIni)} unit="kg/L" tone="accent"/>
      </div>

      {/* Alert kadaluarsa */}
      {expiring.length > 0 && (
        <div className="alert danger" style={{ marginBottom: 20 }}>
          <div>
            <div className="alert-title">{expiring.length} lot ALC mendekati / melewati kadaluarsa</div>
            <div className="alert-body">
              {expiring.slice(0, 3).map(l => `${l.komoditas} (${l.jumlah_sisa} ${l.satuan}, ${l.expired ? "kadaluarsa" : "s/d"} ${l.kadaluarsa})`).join(" · ")}
              {expiring.length > 3 && ` · +${expiring.length - 3} lainnya`}
              {" — "}prioritaskan lot ini saat memenuhi permintaan dapur (FEFO otomatis), atau catat waste di tab Stok & Lot.
            </div>
          </div>
        </div>
      )}

      <Tabs tabs={tabs} value={tab} onChange={setTab}/>

      {/* ===== TAB: KIRIM KE DAPUR (OUTBOUND) ===== */}
      {tab === "permintaan" && (
        <div style={{ marginTop: 16, display: "flex", flexDirection: "column", gap: 16 }}>
          <div className="card">
            <div className="card-head">
              <h2 className="h2">Permintaan dapur menunggu pengiriman</h2>
              <span className="pill primary"><span className="led"/>{activeRequests.length} permintaan · {new Set(activeRequests.map(r => window.resolveDapurId?.(r) || r.dapur)).size} dapur</span>
            </div>
            {activeRequests.length === 0 ? (
              <div className="card-body" style={{ textAlign: "center", padding: 36, color: "var(--ink-3)" }}>
                <div style={{ fontSize: 13.5, fontWeight: 600, color: "var(--ink-2)" }}>Semua permintaan dapur sudah terkirim</div>
                <div style={{ fontSize: 12, marginTop: 4 }}>Permintaan baru dari Dapur Induk/Satelit akan muncul otomatis di sini.</div>
              </div>
            ) : (
              <div style={{ overflowX: "auto" }}>
                <table className="data">
                  <thead>
                    <tr>
                      <th style={{ width: "30%" }}>Dapur & permintaan</th>
                      <th style={{ width: "26%" }}>Komoditas</th>
                      <th className="num" style={{ width: 110 }}>Stok ALC</th>
                      <th style={{ width: 100 }}>Deadline</th>
                      <th style={{ width: 190 }}>Kirim</th>
                    </tr>
                  </thead>
                  <tbody>
                    {activeRequests.map(req => {
                      const tersedia = Math.round(InventoryManager.getTotal("ALC", req.komoditas) * 100) / 100;
                      const cukup = tersedia >= (req.jumlahDiminta || 0);
                      const meta = ALC_REQ_STATUS_META[req.status] || { label: req.status, pill: "neutral" };
                      const satuan = req.satuanDiminta || "kg";
                      const telat = req.deadline && req.deadline < new Date().toISOString().split("T")[0];
                      return (
                        <tr key={req.id}>
                          <td>
                            <b style={{ fontSize: 13 }}>{req.dapurNama || (req.dapur ? `Dapur ${req.dapur}` : "—")}</b>
                            <div style={{ display: "flex", alignItems: "center", gap: 6, marginTop: 3 }}>
                              <span className="mono" style={{ fontSize: 10.5, color: "var(--ink-3)" }}>{req.id}</span>
                              <span className={`pill ${meta.pill}`} style={{ fontSize: 10 }}><span className="led"/>{meta.label}</span>
                            </div>
                          </td>
                          <td>
                            <b>{req.komoditas}</b>
                            <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>diminta {req.jumlahDiminta} {satuan}</div>
                          </td>
                          <td className="num">
                            <b style={{ color: cukup ? "var(--accent)" : tersedia > 0 ? "var(--warn)" : "var(--danger)" }}>{tersedia}</b> <span className="muted">{satuan}</span>
                            <div style={{ fontSize: 10.5, marginTop: 2, color: cukup ? "var(--accent)" : "var(--warn)" }}>
                              {cukup ? "✓ cukup" : tersedia > 0 ? `kurang ${Math.round((req.jumlahDiminta - tersedia) * 100) / 100}` : "kosong"}
                            </div>
                          </td>
                          <td style={{ fontSize: 12, color: telat ? "var(--danger)" : "var(--ink-2)", fontWeight: telat ? 600 : 400, whiteSpace: "nowrap" }}>
                            {req.deadline || "—"}
                            {telat && <div style={{ fontSize: 10.5, fontWeight: 400 }}>lewat deadline</div>}
                          </td>
                          <td>
                            <div className="row" style={{ gap: 6, alignItems: "center" }}>
                              <input
                                className="input mono" type="number" min="0" step="0.1"
                                style={{ width: 86, padding: "6px 8px", fontSize: 12 }}
                                value={shipForm[req.id] ?? req.jumlahDiminta}
                                onChange={e => setShipForm(f => ({ ...f, [req.id]: e.target.value }))}
                              />
                              <button
                                className={`btn sm ${tersedia > 0 ? "primary" : ""}`}
                                disabled={tersedia <= 0}
                                title={tersedia <= 0 ? "Stok ALC kosong — ambil dulu dari Gudang SAFCC (tab 1)" : "Kirim ke dapur (FEFO)"}
                                onClick={() => kirimKeDapur(req)}
                              >Kirim</button>
                            </div>
                            {tersedia <= 0 && (
                              <div style={{ fontSize: 10.5, color: "var(--warn)", marginTop: 4 }}>Ambil stok dulu di tab 1</div>
                            )}
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            )}
            <div style={{ padding: "10px 16px", fontSize: 11.5, color: "var(--ink-3)", borderTop: "1px solid var(--line)", lineHeight: 1.6 }}>
              Klik <b>Kirim</b> → stok ALC terpotong otomatis (FEFO) dan kiriman langsung tampil di aplikasi dapur pada menu <b>"Konfirmasi Penerimaan"</b>.
              Setelah dapur verifikasi fisik, stok masuk Inventory Dapur dan statusnya berubah <b>Diterima</b> (pantau di panel bawah & menu <i>Status Pengiriman</i>).
            </div>
          </div>

          {/* Status kiriman ALC — jembatan visual ke layar dapur */}
          <div className="card">
            <div className="card-head">
              <h2 className="h2">Kiriman ALC & status konfirmasi dapur</h2>
              <span className="pill warn"><span className="led"/>{kirimanALC.filter(f => f.status === "PENDING").length} menunggu dapur</span>
            </div>
            <div className="card-body tight" style={{ display: "flex", flexDirection: "column", gap: 8, maxHeight: 320, overflowY: "auto" }}>
              {kirimanALC.length === 0 && (
                <div style={{ textAlign: "center", color: "var(--ink-3)", fontSize: 12, padding: 20 }}>Belum ada kiriman dari ALC</div>
              )}
              {kirimanALC.map(f => (
                <div key={f.id} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, padding: 10, background: "var(--bg-2)", borderRadius: "var(--radius)", fontSize: 12 }}>
                  <div style={{ minWidth: 0 }}>
                    <b>{f.komoditas}</b> · {f.jumlahDiberikan} {f.satuan || "kg"} → {f.dapurNama || (f.dapur ? `Dapur ${f.dapur}` : "Dapur")}
                    <div style={{ fontSize: 10.5, color: "var(--ink-3)", marginTop: 2 }}>
                      <span className="mono">{f.requestId}</span> · dikirim {f.tanggalSubmit}
                    </div>
                  </div>
                  {f.status === "RECEIVED"
                    ? <span className="pill ok" style={{ flexShrink: 0 }}><span className="led"/>✓ Diterima dapur</span>
                    : <span className="pill warn" style={{ flexShrink: 0 }}><span className="led"/>Menunggu konfirmasi</span>}
                </div>
              ))}
            </div>
            <div style={{ padding: "10px 16px", fontSize: 11.5, color: "var(--ink-3)", borderTop: "1px solid var(--line)", lineHeight: 1.6 }}>
              Kiriman berstatus <b>"Menunggu konfirmasi"</b> muncul di sisi dapur: login sebagai Dapur Induk/Satelit → menu <b>"Konfirmasi Penerimaan"</b> → verifikasi volume fisik & catatan kualitas.
            </div>
          </div>
        </div>
      )}

      {/* ===== TAB: INBOUND DARI SAFCC ===== */}
      {tab === "inbound" && (
        <div className="grid cols-2" style={{ marginTop: 16, alignItems: "start" }}>
          <div className="card">
            <div className="card-head"><h2 className="h2">Ambil hasil olahan dari Gudang SAFCC</h2></div>
            <div className="card-body">
              <div className="field">
                <label>Komoditas (stok Gudang SAFCC)</label>
                <select className="select" value={inForm.komoditas} onChange={e => setInForm(f => ({ ...f, komoditas: e.target.value }))}>
                  <option value="">— pilih —</option>
                  {stokSAFCC.filter(s => s.total > 0).map(s => (
                    <option key={s.komoditas} value={s.komoditas}>{s.komoditas} (tersedia {s.total} {s.satuan})</option>
                  ))}
                </select>
              </div>
              <div className="grid cols-2" style={{ gap: 12 }}>
                <div className="field">
                  <label>Jumlah</label>
                  <input className="input mono" type="number" min="0" step="0.1" value={inForm.qty}
                    onChange={e => setInForm(f => ({ ...f, qty: e.target.value }))} placeholder="0"/>
                </div>
                <div className="field">
                  <label>Bentuk hasil olahan</label>
                  <select className="select" value={inForm.bentuk} onChange={e => setInForm(f => ({ ...f, bentuk: e.target.value }))}>
                    {ALC_BENTUK_OLAHAN.map(b => <option key={b}>{b}</option>)}
                  </select>
                </div>
              </div>
              <div className="field">
                <label>Catatan (opsional)</label>
                <input className="input" value={inForm.catatan} onChange={e => setInForm(f => ({ ...f, catatan: e.target.value }))} placeholder="mis. hasil pembersihan panen kangkung pagi"/>
              </div>
              <button className="btn primary" style={{ width: "100%", justifyContent: "center" }} onClick={tarikDariSAFCC}>Simpan ke ALC</button>
              <div style={{ marginTop: 12, fontSize: 11.5, color: "var(--ink-3)", lineHeight: 1.5 }}>
                Stok berpindah dari Gudang SAFCC ke ALC secara FEFO — tanggal kadaluarsa ikut lot asal.
                Bahan yang tersimpan di ALC siap dikirim ke dapur dari tab <b>2 · Kirim ke dapur</b>.
              </div>
            </div>
          </div>
          <div className="card">
            <div className="card-head"><h2 className="h2">Barang masuk ALC terakhir</h2></div>
            <div className="card-body tight" style={{ display: "flex", flexDirection: "column", gap: 8, maxHeight: 460, overflowY: "auto" }}>
              {InventoryManager.getLedger({ lokasi: "ALC", tipe: "MASUK", limit: 12 }).map(t => (
                <div key={t.id} style={{ padding: 10, background: "var(--bg-2)", borderRadius: "var(--radius)", fontSize: 12 }}>
                  <b>{t.komoditas}</b> · {t.qty} {t.satuan} <span className="muted">· {new Date(t.ts).toLocaleString("id-ID", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" })}</span>
                  <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>{t.catatan}</div>
                </div>
              ))}
              {InventoryManager.getLedger({ lokasi: "ALC", tipe: "MASUK", limit: 1 }).length === 0 && (
                <div style={{ textAlign: "center", color: "var(--ink-3)", fontSize: 12, padding: 20 }}>Belum ada barang masuk ALC</div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* ===== TAB: STOK & LOT ALC ===== */}
      {tab === "stok" && (
        <div style={{ marginTop: 16, display: "flex", flexDirection: "column", gap: 16 }}>
          <div className="card">
            <div className="card-head"><h2 className="h2">Stok ALC per komoditas</h2></div>
            <div style={{ overflowX: "auto" }}>
              <table className="data">
                <thead>
                  <tr><th>Komoditas</th><th className="num">Stok</th><th style={{ minWidth: 160 }}>Level vs par</th><th className="num">ROP / par</th><th>Status</th></tr>
                </thead>
                <tbody>
                  {stokALC.map(s => (
                    <tr key={s.komoditas}>
                      <td>
                        <b>{s.komoditas}</b>
                        {s.expSoon > 0 && <div style={{ fontSize: 11, color: "var(--warn)" }}>{s.expSoon} {s.satuan} exp ≤3 hari</div>}
                        {s.expired > 0 && <div style={{ fontSize: 11, color: "var(--danger)" }}>✕ {s.expired} {s.satuan} kadaluarsa</div>}
                      </td>
                      <td className="num"><b>{s.total}</b> <span className="muted">{s.satuan}</span></td>
                      <td>
                        <div className={`bar ${s.status === "aman" ? "accent" : s.status === "reorder" ? "warn" : "danger"}`} title={`${s.total}/${s.parLevel} ${s.satuan}`}>
                          <span style={{ width: `${Math.min(100, (s.total / Math.max(1, s.parLevel)) * 100)}%` }}/>
                        </div>
                      </td>
                      <td className="num">{s.reorderPoint} / {s.parLevel}</td>
                      <td>
                        <InvStatusPill status={s.status}/>
                        {s.status !== "aman" && (
                          <div style={{ fontSize: 10.5, color: "var(--warn)", marginTop: 3 }}>Tarik ±{s.rekomendasi} {s.satuan} dari SAFCC</div>
                        )}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
          <div className="card">
            <div className="card-head"><h2 className="h2">Lot aktif ALC — urut FEFO</h2></div>
            <div style={{ overflowX: "auto" }}>
              <table className="data">
                <thead>
                  <tr><th>Lot</th><th>Komoditas</th><th className="num">Sisa / awal</th><th>Masuk</th><th>Kadaluarsa</th><th>Sumber</th><th>Aksi</th></tr>
                </thead>
                <tbody>
                  {lotsALC.length === 0 && (
                    <tr><td colSpan={7} style={{ textAlign: "center", color: "var(--ink-3)", padding: 28 }}>Belum ada lot aktif di ALC — ambil hasil olahan dari tab 1 · Ambil stok dari SAFCC</td></tr>
                  )}
                  {lotsALC.map(l => (
                    <tr key={l.id}>
                      <td className="mono" style={{ fontSize: 11 }}>{l.id}</td>
                      <td><b>{l.komoditas}</b></td>
                      <td className="num">{l.jumlah_sisa} / {l.jumlah_awal} {l.satuan}</td>
                      <td>{l.tanggal_masuk}</td>
                      <td><ExpiryTag kadaluarsa={l.kadaluarsa}/></td>
                      <td style={{ fontSize: 11.5, color: "var(--ink-2)" }}>{l.sumber}</td>
                      <td><button className="btn sm" onClick={() => setWasteLot(l)}>Buang</button></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      )}

      {/* ===== TAB: RIWAYAT ALC ===== */}
      {tab === "riwayat" && (
        <div className="card" style={{ marginTop: 16 }}>
          <div className="card-head">
            <h2 className="h2">Riwayat transaksi ALC ({ledger.length} terakhir)</h2>
            <button className="btn sm" onClick={exportLedgerALC}>Export CSV</button>
          </div>
          <div style={{ overflowX: "auto" }}>
            <table className="data">
              <thead>
                <tr><th>Waktu</th><th>Tipe</th><th>Komoditas</th><th className="num">Qty</th><th>Oleh</th><th>Catatan</th></tr>
              </thead>
              <tbody>
                {ledger.length === 0 && (
                  <tr><td colSpan={6} style={{ textAlign: "center", color: "var(--ink-3)", padding: 28 }}>Belum ada transaksi ALC</td></tr>
                )}
                {ledger.map(t => {
                  const m = tipeMeta[t.tipe] || { label: t.tipe, pill: "neutral" };
                  return (
                    <tr key={t.id}>
                      <td className="mono" style={{ fontSize: 11, whiteSpace: "nowrap" }}>
                        {new Date(t.ts).toLocaleString("id-ID", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" })}
                      </td>
                      <td><span className={`pill ${m.pill}`}><span className="led"/>{m.label}</span></td>
                      <td><b>{t.komoditas}</b></td>
                      <td className="num">{t.tipe === "OPNAME" && t.qty > 0 ? "+" : ""}{t.qty} {t.satuan}</td>
                      <td style={{ fontSize: 11.5 }}>{t.oleh}</td>
                      <td style={{ fontSize: 11.5, color: "var(--ink-2)", maxWidth: 320 }}>{t.catatan}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {showOpname && <OpnameModal lokasi="ALC" stok={stokALC} onClose={() => setShowOpname(false)} onDone={refresh}/>}
      {wasteLot && <WasteModal lot={wasteLot} onClose={() => setWasteLot(null)} onDone={refresh}/>}
    </>
  );
}

window.AgroALC = AgroALC;

// =============================================================================
// Panduan (Tips Cepat) & Tutorial untuk halaman inventory + panduan yang
// sebelumnya kosong ("Tidak ada panduan untuk halaman ini")
// =============================================================================
(function registerInventoryGuides() {
  const G = window.IDSS?.FEATURE_GUIDES;
  if (!G) return;

  const invGuideDapur = {
    title: "Inventory dapur",
    sections: [
      { heading: "Stok & reorder", content: "Pantau stok tiap bahan vs Reorder Point (ROP). Status 'Pesan Ulang' atau 'Kritis' → klik tombol 'Minta' untuk otomatis membuat permintaan ke SAFCC sesuai jumlah rekomendasi." },
      { heading: "FEFO & kadaluarsa", content: "Tab 'Lot & Kadaluarsa' mengurutkan stok dari kadaluarsa terdekat. Gunakan bahan itu lebih dulu; bahan rusak/kadaluarsa dicatat sebagai Waste agar stok akurat." },
      { heading: "Catat pemakaian", content: "Setiap produksi menu, catat bahan yang dipakai. Sistem memotong stok secara FEFO dan menyinkronkan neraca komoditas otomatis." },
      { heading: "Stock opname", content: "Lakukan hitung fisik berkala (mis. tiap sore). Masukkan hasil hitung — selisih tercatat sebagai penyesuaian OPNAME untuk audit." }
    ]
  };
  const invGuideAgro = {
    title: "Inventory Gudang SAFCC",
    sections: [
      { heading: "Stok & reorder", content: "Pantau level gudang vs ROP dan Par. Item di bawah ROP menampilkan jumlah rekomendasi order — gunakan menu 'Pemilihan Supplier' untuk membuat request ke supplier." },
      { heading: "Transfer ke ALC", content: "Alur baku: hasil olahan/pembersihan SAFCC ditransfer ke Agro Logistic Center (ALC) — gudang distribusi sebelum dapur. Sistem mengambil lot kadaluarsa terdekat (FEFO); transfer langsung ke dapur hanya untuk darurat." },
      { heading: "Kadaluarsa & waste", content: "Alert merah muncul untuk lot ≤3 hari menuju kadaluarsa. Prioritaskan transfer/pakai lot tersebut, atau catat sebagai waste bila sudah tidak layak." },
      { heading: "Opname & riwayat", content: "Semua mutasi (masuk, transfer, waste, opname) tercatat di ledger dan bisa diexport CSV untuk kepatuhan." }
    ]
  };

  if (G.agro) {
    G.agro.inventory = invGuideAgro;
    G.agro.alc = {
      title: "Agro Logistic Center (ALC)",
      sections: [
        { heading: "Apa itu ALC", content: "Gudang distribusi bahan produksi. Hasil panen kawasan diolah/dibersihkan SAFCC, lalu disimpan di ALC (segar, frozen, olahan). Saat dapur SPPG meminta bahan, ALC yang mengirim langsung ke dapur." },
        { heading: "1 · Ambil stok dari SAFCC", content: "Langkah pertama: ambil hasil olahan dari Gudang SAFCC ke ALC. Pilih komoditas, jumlah, dan bentuk olahan (segar/frozen/olahan) — tanggal kadaluarsa ikut lot asal." },
        { heading: "2 · Kirim ke dapur", content: "Daftar semua permintaan aktif dari Dapur Induk/Satelit beserta stok ALC per komoditas. Klik 'Kirim' — stok dipotong FEFO, request jadi 'Dikirim', dan kiriman muncul di layar dapur pada menu 'Konfirmasi Penerimaan'. Panel bawah menunjukkan kiriman mana yang sudah/belum dikonfirmasi dapur." },
        { heading: "Stok, lot & riwayat", content: "Pantau level stok ALC vs ROP/Par, lot urut FEFO dengan alert kadaluarsa, waste, stock opname, dan ledger lengkap yang bisa diexport CSV." }
      ]
    };
    G.agro["bahan-baku"] = G.agro["bahan-baku"] || {
      title: "Barcode bahan baku",
      sections: [
        { heading: "Catat batch masuk", content: "Untuk setoran langsung petani/mitra di luar permintaan dapur — batch ber-barcode (B-xxx) dibuat dan stok Inventory Gudang bertambah. Kiriman supplier atas permintaan divalidasi di 'Penerimaan & Validasi' (batch dibuat otomatis di sana; jangan dicatat dua kali)." },
        { heading: "Cetak label QR", content: "Print label QR untuk ditempel di kemasan. Scan QR menampilkan detail traceability lengkap di device mana pun." },
        { heading: "Lineage", content: "Batch ini akan tertaut ke box makanan yang diproduksi dapur — traceability dari ladang sampai piring." }
      ]
    };
    G.agro.shipments = G.agro.shipments || {
      title: "Status pengiriman",
      sections: [
        { heading: "Pantau kiriman", content: "Lihat status seluruh pengiriman komoditas ke dapur: pending, dalam perjalanan, diterima." },
        { heading: "Diskrepansi", content: "Jika volume diterima ≠ dikirim, sistem mencatat selisih untuk rekonsiliasi dengan supplier." }
      ]
    };
  }

  ["induk", "satelit"].forEach(r => {
    if (!G[r]) return;
    G[r].inventory = invGuideDapur;
    G[r].requests = G[r].requests || {
      title: "Permintaan komoditas",
      sections: [
        { heading: "Buat permintaan", content: "Ajukan kebutuhan bahan baku ke SAFCC: pilih komoditas, jumlah, dan deadline. Status permintaan terpantau real-time." },
        { heading: "Filter status", content: "Gunakan kartu ringkasan di atas tabel untuk memfilter: Menunggu, Partial, Siap Kirim, Dikirim." }
      ]
    };
    G[r].penerimaan = G[r].penerimaan || {
      title: "Konfirmasi penerimaan",
      sections: [
        { heading: "Verifikasi fisik", content: "Saat barang tiba, masukkan volume aktual yang diterima dan catatan kualitas. Selisih volume tercatat otomatis." },
        { heading: "Efek ke stok", content: "Konfirmasi menambah Inventory Dapur (lot baru dengan kadaluarsa otomatis) dan memperbarui neraca." }
      ]
    };
    G[r]["meal-boxes"] = G[r]["meal-boxes"] || {
      title: "Barcode box makanan",
      sections: [
        { heading: "Buat box", content: "Setiap batch masakan dibuatkan barcode box (X-xxx) berisi menu, gizi, dan bahan baku yang dipakai." },
        { heading: "Cetak & kirim", content: "Print label QR, tempel di box, tandai 'dikirim' saat berangkat. Sekolah menerima dengan scan QR." }
      ]
    };
    G[r].feedback = G[r].feedback || {
      title: "Quality feedback",
      sections: [
        { heading: "Pantau penilaian", content: "Lihat hasil verifikasi 6 kriteria dan rating dari sekolah/posyandu terhadap makanan dapur Anda." },
        { heading: "Tindak lanjut", content: "Status MINOR/MAJOR menunjukkan aspek yang perlu diperbaiki — gunakan alasan detail untuk perbaikan proses." }
      ]
    };
    G[r].alerts = G[r].alerts || {
      title: "Alert inbox",
      sections: [
        { heading: "Alert dari penerima", content: "Saat sekolah/posyandu menemukan masalah serius (status MAJOR), alert otomatis masuk ke inbox ini untuk ditindaklanjuti dapur." },
        { heading: "Review & teruskan", content: "Periksa detail alert, tandai sudah dilihat, selesaikan setelah ditangani, atau teruskan ke SAFCC bila akar masalahnya di bahan baku." }
      ]
    };
  });

  // Tutorial langkah-demi-langkah
  const T = window.IDSS?.FEATURE_TUTORIALS;
  if (T) {
    const invTutorialDapur = {
      id: "inventory-dapur",
      title: "Mengelola inventory dapur",
      description: "Kontrol stok bahan: pemakaian FEFO, reorder otomatis ke SAFCC, dan stock opname",
      steps: [
        { num: 1, title: "Buka inventory dapur", content: "Klik menu 'Inventory Dapur' di sidebar. Empat kartu KPI menampilkan: jumlah komoditas, item perlu pesan ulang, lot mendekati kadaluarsa, dan pemakaian hari ini." },
        { num: 2, title: "Cek status stok", content: "Di tab 'Stok & Reorder', tiap bahan punya status:\n- Aman: stok di atas Reorder Point (ROP)\n- Pesan Ulang: stok di bawah ROP — segera minta ke SAFCC\n- Kritis: stok di bawah 50% ROP\n- Habis: stok 0" },
        { num: 3, title: "Minta bahan ke SAFCC", content: "Untuk item berstatus Pesan Ulang/Kritis, klik tombol 'Minta X kg'. Sistem otomatis membuat permintaan ke SAFCC sejumlah rekomendasi (Par Level − stok saat ini). Pantau statusnya di menu 'Permintaan Komoditas'." },
        { num: 4, title: "Catat pemakaian produksi", content: "Setiap kali memasak, buka tab 'Catat Pemakaian': pilih komoditas, isi jumlah, pilih keperluan, lalu simpan. Stok dipotong dari lot kadaluarsa terdekat (FEFO) dan neraca ikut ter-update." },
        { num: 5, title: "Kelola kadaluarsa", content: "Tab 'Lot & Kadaluarsa' menampilkan lot urut FEFO. Lot merah = kadaluarsa, kuning = ≤2 hari. Gunakan lot tersebut lebih dulu, atau klik 'Buang' untuk mencatat waste dengan alasan." },
        { num: 6, title: "Stock opname", content: "Klik tombol 'Stock Opname' di kanan atas. Pilih komoditas, masukkan hasil hitung fisik. Selisih (plus/minus) dicatat sebagai penyesuaian OPNAME di riwayat — penting untuk audit." },
        { num: 7, title: "Export riwayat", content: "Tab 'Riwayat Transaksi' berisi seluruh mutasi stok (masuk, pakai, waste, opname). Klik 'Export CSV' untuk laporan kepatuhan." }
      ]
    };
    const invTutorialAgro = {
      id: "inventory-gudang",
      title: "Mengelola inventory Gudang SAFCC",
      description: "Kontrol stok gudang: reorder point, transfer FEFO ke dapur, dan opname",
      steps: [
        { num: 1, title: "Buka inventory gudang", content: "Klik menu 'Inventory Gudang' di sidebar SAFCC. KPI menampilkan jumlah SKU, item perlu pesan ulang, lot mendekati kadaluarsa, dan barang masuk hari ini." },
        { num: 2, title: "Pantau reorder point", content: "Tab 'Stok & Reorder' menampilkan level stok vs ROP dan Par per komoditas. Item di bawah ROP menampilkan jumlah rekomendasi order — tindaklanjuti lewat menu 'Pemilihan Supplier'." },
        { num: 3, title: "Terima barang masuk", content: "Saat mencatat batch bahan baku di menu 'Barcode Bahan Baku', stok gudang otomatis bertambah sebagai lot baru dengan kadaluarsa sesuai umur simpan komoditas." },
        { num: 4, title: "Transfer ke ALC", content: "Tab 'Transfer ke ALC/Dapur': pilih komoditas, jumlah, dan tujuan. Alur baku pilih ALC (Agro Logistic Center) — gudang distribusi sebelum dapur; opsi langsung ke dapur hanya untuk darurat. Sistem mengambil lot kadaluarsa terdekat (FEFO)." },
        { num: 5, title: "Kelola kadaluarsa & waste", content: "Alert merah muncul bila ada lot ≤3 hari menuju kadaluarsa. Prioritaskan transfer lot itu, atau catat 'Buang' (waste) dengan alasan bila tidak layak." },
        { num: 6, title: "Opname & laporan", content: "Lakukan 'Stock Opname' berkala untuk menyamakan sistem dengan fisik gudang. Semua transaksi bisa diexport CSV dari tab 'Riwayat Transaksi'." }
      ]
    };
    const alcTutorial = {
      id: "alc-distribusi",
      title: "Distribusi via Agro Logistic Center (ALC)",
      description: "Alur lengkap: hasil olahan SAFCC → simpan di ALC → kirim ke dapur SPPG saat ada permintaan",
      steps: [
        { num: 1, title: "Pahami alur", content: "Panen kawasan → SAFCC (olah/bersihkan, validasi QC) → ALC (gudang distribusi) → Dapur SPPG. ALC adalah pintu terakhir bahan sebelum dapur — semua pengiriman ke dapur idealnya lewat sini." },
        { num: 2, title: "Isi stok ALC", content: "Buka menu 'Agro Logistic Center' → tab '1 · Ambil stok dari SAFCC'. Pilih komoditas dari stok Gudang SAFCC, isi jumlah dan bentuk olahan (segar/frozen/olahan setengah jadi), lalu 'Simpan ke ALC'. Stok berpindah FEFO — kadaluarsa ikut lot asal." },
        { num: 3, title: "Pantau permintaan dapur", content: "Tab '2 · Kirim ke dapur' menampilkan semua permintaan aktif dari Dapur Induk/Satelit: jumlah diminta, deadline, status, dan stok ALC yang tersedia untuk komoditas itu (✓ cukup / kurang / kosong)." },
        { num: 4, title: "Kirim ke dapur", content: "Sesuaikan jumlah kirim (default = jumlah diminta) lalu klik 'Kirim'. Sistem memotong stok ALC (FEFO), mengubah status request menjadi 'Dikirim', dan membuat kiriman berstatus menunggu konfirmasi di layar dapur." },
        { num: 5, title: "Dapur konfirmasi", content: "Di sisi dapur, kiriman ALC muncul di menu 'Konfirmasi Penerimaan' (pengirim: Agro Logistic Center). Setelah dapur verifikasi fisik (volume aktual + catatan kualitas), stok masuk Inventory Dapur — panel 'Kiriman ALC' di tab 2 berubah menjadi '✓ Diterima dapur'." },
        { num: 6, title: "Kelola gudang ALC", content: "Tab 'Stok & Lot ALC' untuk pantau level vs ROP/Par, alert kadaluarsa, waste, dan stock opname. Tab 'Riwayat ALC' berisi seluruh mutasi dan bisa diexport CSV." }
      ]
    };
    if (Array.isArray(T.agro) && !T.agro.some(t => t.id === "inventory-gudang")) T.agro.push(invTutorialAgro);
    if (Array.isArray(T.agro) && !T.agro.some(t => t.id === "alc-distribusi")) T.agro.push(alcTutorial);
    if (Array.isArray(T.dapur_induk) && !T.dapur_induk.some(t => t.id === "inventory-dapur")) T.dapur_induk.push(invTutorialDapur);
  }
})();
