// OM Group ERP — Opening Stock Management (v3 — Controlled Lock/Unlock)
// Per-row Edit / Delete / Add with audit trail and manual Lock/Unlock.
const { useState: osSt, useEffect: osEf, useMemo: osMemo, useContext: osCtx } = React;

// ── Lock State ──────────────────────────────────────────────────────────────
function osGetLock(stockyardId) {
  return (Store.all('openingStockLocks') || []).find(l => l.stockyardId === stockyardId) || null;
}
function osIsLocked(stockyardId) {
  if (!stockyardId) return false;
  const lock = osGetLock(stockyardId);
  if (lock) return lock.locked === true;
  // Backward compat: treat as locked if transactions already exist
  return (Store.all('stockMovements') || []).some(m => m.stockyardId === stockyardId && m.type !== 'Opening');
}
function osHasTransactions(stockyardId) {
  return (Store.all('stockMovements') || []).some(m => m.stockyardId === stockyardId && m.type !== 'Opening');
}
function osGetRecords(stockyardId) {
  if (!stockyardId) return [];
  return (Store.all('openingStocks') || []).filter(r => r.stockyardId === stockyardId);
}
function osGetRecord(stockyardId) {
  const recs = osGetRecords(stockyardId);
  return recs.length ? recs[0] : null;
}
window.osIsLocked   = osIsLocked;
window.osGetRecords = osGetRecords;
window.osGetRecord  = osGetRecord;

// ── Audit ────────────────────────────────────────────────────────────────────
function osAudit({ action, stockyardId, oldVal, newVal, user, reason, sessionId }) {
  Store.add('openingStockAuditLog', {
    action, stockyardId,
    oldValue: oldVal ? JSON.stringify(oldVal) : '',
    newValue: newVal ? JSON.stringify(newVal) : '',
    user: user || 'System',
    date: new Date().toISOString().slice(0, 10),
    time: new Date().toISOString().slice(11, 19),
    reason: reason || '',
    sessionId: sessionId || '',
  });
}

// ── Inventory recalculation for one row ─────────────────────────────────────
function osRecalcRow(rec) {
  (Store.all('stockMovements') || [])
    .filter(m => m.openingStockId === rec.id && m.type === 'Opening')
    .forEach(m => Store.del('stockMovements', m.id));
  Store.add('stockMovements', {
    date: rec.openingDate,
    stockyardId: rec.stockyardId,
    materialId:  rec.materialId,
    vendorId:    rec.vendorId,
    type:               'Opening',
    quantity:           rec.qty,
    netQuantity:        rec.qty,
    rate: 0, value: 0,
    movementSourceType: 'Opening Stock',
    isOpeningStock:     true,
    openingStockId:     rec.id,
    reference:          'Opening Balance',
    notes:              rec.remarks || '',
    companyId:          rec.companyId,
    createdBy:          rec.modifiedBy || rec.createdBy || 'System',
  });
  Store.ensureOpeningMovements?.();
}

// ── Opening Stock Modal ─────────────────────────────────────────────────────
function OpeningStockModal({ stockyards, materials, onClose, onSaved, defaultStockyardId }) {
  const { companyId, session } = osCtx(window.AppCtx);
  const isGroup   = companyId === 'group';
  const companies = Store.all('companies');
  const allVendors = Store.all('vendors') || [];
  const vendors    = osMemo(() => allVendors.filter(v => !v.status || v.status === 'Active'), [allVendors]);
  const activeMats = osMemo(() => (materials || []).filter(m => !m.status || m.status === 'Active'), [materials]);

  const role     = session?.role || '';
  const canUnlock = true;
  const userName = session?.userName || 'System';

  const [selSY,       setSelSY]       = osSt(defaultStockyardId || '');
  const [openingDate, setOpeningDate] = osSt(new Date().toISOString().slice(0, 10));
  const [rows,        setRows]        = osSt([]);
  const [locked,      setLocked]      = osSt(false);
  const [hasTxns,     setHasTxns]     = osSt(false);
  const [tick,        setTick]        = osSt(0);

  // Per-row edit state
  const [editingId,  setEditingId]  = osSt(null);
  const [editForm,   setEditForm]   = osSt({});
  const [editReason, setEditReason] = osSt('');

  // Add new rows state — array of pending rows, each with a unique _tempId
  const [pendingRows, setPendingRows] = osSt([]);

  // Delete confirm
  const [deleteConfirm, setDeleteConfirm] = osSt(null);
  const [deleteReason,  setDeleteReason]  = osSt('');

  // Lock / Unlock confirm
  const [showLockConfirm,   setShowLockConfirm]   = osSt(false);
  const [showUnlockConfirm, setShowUnlockConfirm] = osSt(false);
  const [lockReason,        setLockReason]        = osSt('');

  const [saving, setSaving] = osSt(false);
  const [showAuditLog,   setShowAuditLog]   = osSt(false);
  const [auditSessionId, setAuditSessionId] = osSt('');

  const availSY = osMemo(() => {
    const active = (stockyards || []).filter(s => s.status === 'Active' || !s.status);
    return isGroup ? active : active.filter(s => !s.companyId || s.companyId === companyId);
  }, [stockyards, companyId, isGroup]);

  const selSYObj  = osMemo(() => stockyards.find(s => s.id === selSY), [selSY, stockyards]);
  const syCompany = osMemo(() => selSYObj ? companies.find(c => c.id === selSYObj.companyId) : null, [selSYObj, companies]);
  const syCoId    = osMemo(() => selSYObj?.companyId || companyId, [selSYObj, companyId]);

  function refreshRows(syId) {
    const recs = osGetRecords(syId || selSY);
    setRows(recs);
    setLocked(osIsLocked(syId || selSY));
    setHasTxns(osHasTransactions(syId || selSY));
    if (recs.length > 0) setOpeningDate(recs[0].openingDate || new Date().toISOString().slice(0, 10));
  }

  osEf(() => {
    if (!selSY) { setRows([]); setLocked(false); setHasTxns(false); return; }
    refreshRows(selSY);
    setEditingId(null); setPendingRows([]);
  }, [selSY, tick]);

  const matUnit = id => (materials || []).find(m => m.id === id)?.unit || 'MT';
  const matName = id => (materials || []).find(m => m.id === id)?.name || id;
  const venName = id => (vendors   || []).find(v => v.id === id)?.name || id;

  const totalQty = rows.reduce((s, r) => s + (r.qty || 0), 0);

  // ── Lock / Unlock ─────────────────────────────────────────────────────────
  function doLock() {
    const lock = osGetLock(selSY);
    const payload = { stockyardId: selSY, locked: true, lockedBy: userName, lockedAt: new Date().toISOString() };
    if (lock) Store.update('openingStockLocks', lock.id, { ...lock, ...payload });
    else      Store.add('openingStockLocks', payload);
    osAudit({ action: 'Lock', stockyardId: selSY, user: userName, reason: lockReason, sessionId: auditSessionId });
    setAuditSessionId('');
    Store.addLog('UPDATE', 'Opening Stock', `Locked for ${selSYObj?.name || selSY}`);
    setShowLockConfirm(false); setLockReason('');
    setTick(t => t + 1);
    window.toast?.('Opening Stock locked', 'ok');
    onSaved?.();
  }
  function doUnlock() {
    if (!lockReason.trim()) { window.toast?.('Enter a reason for unlocking', 'er'); return; }
    const sid = 'SID-' + Date.now();
    const lock = osGetLock(selSY);
    const payload = { stockyardId: selSY, locked: false, unlockedBy: userName, unlockedAt: new Date().toISOString() };
    if (lock) Store.update('openingStockLocks', lock.id, { ...lock, ...payload });
    else      Store.add('openingStockLocks', payload);
    osAudit({ action: 'Unlock', stockyardId: selSY, user: userName, reason: lockReason, sessionId: sid });
    setAuditSessionId(sid);
    Store.addLog('UPDATE', 'Opening Stock', `Unlocked for ${selSYObj?.name || selSY}`);
    setShowUnlockConfirm(false); setLockReason('');
    setTick(t => t + 1);
    window.toast?.('Opening Stock unlocked — complete edits and lock when done', 'ok');
  }

  // ── Edit row ──────────────────────────────────────────────────────────────
  function startEdit(row) {
    setEditingId(row.id);
    setEditForm({ vendorId: row.vendorId, materialId: row.materialId, qty: String(row.qty || ''), remarks: row.remarks || '' });
    setEditReason('');
  }
  function cancelEdit() { setEditingId(null); setEditForm({}); setEditReason(''); }

  function saveEdit(row) {
    if (!editForm.vendorId || !editForm.materialId || !parseFloat(editForm.qty)) {
      window.toast?.('Vendor, Material and Quantity are required', 'er'); return;
    }
    if (!editReason.trim()) { window.toast?.('Enter a reason for this edit', 'er'); return; }
    const dup = rows.some(r => r.id !== row.id && r.vendorId === editForm.vendorId && r.materialId === editForm.materialId);
    if (dup) { window.toast?.('Duplicate Vendor + Material combination', 'er'); return; }
    setSaving(true);
    const q = parseFloat(editForm.qty) || 0;
    const now = new Date().toISOString().slice(0, 10);
    const updated = { ...row, vendorId: editForm.vendorId, materialId: editForm.materialId, qty: q, remarks: editForm.remarks, modifiedBy: userName, modifiedAt: now, editReason };
    osAudit({ action: 'Edit', stockyardId: selSY, oldVal: { vendorId: row.vendorId, materialId: row.materialId, qty: row.qty, remarks: row.remarks || '' }, newVal: { vendorId: editForm.vendorId, materialId: editForm.materialId, qty: q, remarks: editForm.remarks || '' }, user: userName, reason: editReason, sessionId: auditSessionId });
    Store.update('openingStocks', row.id, updated);
    osRecalcRow({ ...updated, id: row.id, stockyardId: selSY, companyId: syCoId, openingDate: row.openingDate || openingDate });
    Store.addLog('UPDATE', 'Opening Stock', `Edited row — ${selSYObj?.name || selSY}`);
    setSaving(false);
    cancelEdit();
    setTick(t => t + 1);
    window.toast?.('Row updated — inventory recalculated', 'ok');
    onSaved?.();
  }

  // ── Delete row ────────────────────────────────────────────────────────────
  function confirmDelete(row) { setDeleteConfirm({ id: row.id, row }); setDeleteReason(''); setEditingId(null); }
  function cancelDelete()     { setDeleteConfirm(null); setDeleteReason(''); }

  function doDelete() {
    if (!deleteReason.trim()) { window.toast?.('Enter a reason for deletion', 'er'); return; }
    const { id, row } = deleteConfirm;
    osAudit({ action: 'Delete', stockyardId: selSY, oldVal: { vendorId: row.vendorId, materialId: row.materialId, qty: row.qty, remarks: row.remarks || '' }, user: userName, reason: deleteReason, sessionId: auditSessionId });
    (Store.all('stockMovements') || []).filter(m => m.openingStockId === id && m.type === 'Opening').forEach(m => Store.del('stockMovements', m.id));
    Store.del('openingStocks', id);
    Store.ensureOpeningMovements?.();
    Store.addLog('DELETE', 'Opening Stock', `Deleted ${venName(row.vendorId)} / ${matName(row.materialId)} — ${selSYObj?.name || selSY}`);
    cancelDelete();
    setTick(t => t + 1);
    window.toast?.('Entry deleted — inventory recalculated', 'ok');
    onSaved?.();
  }

  // ── Add new rows (multi-pending) ─────────────────────────────────────────
  function startAddRow() {
    const tempId = 'tmp-' + Date.now() + '-' + Math.random().toString(36).slice(2);
    setPendingRows(prev => [...prev, { _tempId: tempId, vendorId: '', materialId: '', qty: '', remarks: '' }]);
  }
  function cancelPendingRow(tempId) {
    setPendingRows(prev => prev.filter(r => r._tempId !== tempId));
  }
  function updatePendingRow(tempId, field, value) {
    setPendingRows(prev => prev.map(r => r._tempId === tempId ? { ...r, [field]: value } : r));
  }
  function savePendingRow(tempRow) {
    if (!tempRow.vendorId || !tempRow.materialId || !parseFloat(tempRow.qty)) {
      window.toast?.('Vendor, Material and Quantity are required', 'er'); return;
    }
    const dupSaved = rows.some(r => r.vendorId === tempRow.vendorId && r.materialId === tempRow.materialId);
    const dupPending = pendingRows.some(r => r._tempId !== tempRow._tempId && r.vendorId === tempRow.vendorId && r.materialId === tempRow.materialId && r.vendorId && r.materialId);
    if (dupSaved || dupPending) { window.toast?.('Duplicate Vendor + Material combination', 'er'); return; }
    setSaving(true);
    const q   = parseFloat(tempRow.qty) || 0;
    const now = new Date().toISOString().slice(0, 10);
    const osRec = Store.add('openingStocks', {
      stockyardId: selSY, companyId: syCoId,
      vendorId: tempRow.vendorId, materialId: tempRow.materialId,
      qty: q, openingDate, remarks: tempRow.remarks,
      createdBy: userName, createdAt: now, modifiedBy: userName, modifiedAt: now,
    });
    Store.add('stockMovements', {
      date: openingDate, stockyardId: selSY,
      materialId: tempRow.materialId, vendorId: tempRow.vendorId,
      type: 'Opening', quantity: q, netQuantity: q,
      rate: 0, value: 0, movementSourceType: 'Opening Stock',
      isOpeningStock: true, openingStockId: osRec.id,
      reference: 'Opening Balance', notes: tempRow.remarks || '',
      companyId: syCoId, createdBy: userName,
    });
    Store.ensureOpeningMovements?.();
    osAudit({ action: 'Create', stockyardId: selSY, newVal: { vendorId: tempRow.vendorId, materialId: tempRow.materialId, qty: q, remarks: tempRow.remarks || '' }, user: userName, reason: 'New opening stock entry', sessionId: auditSessionId });
    Store.addLog('CREATE', 'Opening Stock', `Added row — ${selSYObj?.name || selSY}`);
    setSaving(false);
    setPendingRows(prev => prev.filter(r => r._tempId !== tempRow._tempId));
    setTick(t => t + 1);
    window.toast?.('Entry saved — add another or close when done', 'ok');
    onSaved?.();
  }

  // ── Styles ────────────────────────────────────────────────────────────────
  const inpSel = { width: '100%', border: '1.5px solid var(--bdr)', borderRadius: 7, padding: '3px 6px 3px 8px', fontSize: 12, fontFamily: 'var(--font)', outline: 'none', height: 30, cursor: 'pointer', background: '#fff', appearance: 'none' };
  const inpTxt = { width: '100%', border: '1.5px solid var(--bdr)', borderRadius: 7, padding: '3px 8px', fontSize: 12, fontFamily: 'var(--font)', outline: 'none', height: 30 };
  const inpNum = { ...inpTxt, fontVariantNumeric: 'tabular-nums' };
  const iconBtn = (col, bgHov) => ({
    width: 28, height: 28, border: '1.5px solid var(--bdr)', borderRadius: 6, background: '#fff',
    color: col, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', transition: 'all .12s',
  });

  // ── SVG icons (defined inline to avoid scope conflicts) ───────────────────
  const EditSvg = () => (
    <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
      <path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
    </svg>
  );
  const TrashSvg = () => (
    <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <polyline points="3 6 5 6 21 6"/>
      <path d="M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6"/>
      <path d="M10 11v6M14 11v6"/>
      <path d="M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2"/>
    </svg>
  );
  const CheckSvg = () => (
    <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><polyline points="20 6 9 17 4 12"/></svg>
  );

  // Column widths
  const colsUnlocked = ['4%','22%','20%','7%','12%','14%','21%'];
  const colsLocked   = ['4%','27%','25%','8%','16%','20%'];

  return (
    <div className="mbg">
      <div className="mod mod-xl" style={{ maxWidth: 1020 }}>

        {/* ── Header ──────────────────────────────────────────────────────── */}
        <div className="mod-hd">
          <div>
            <h2>Opening Stock Entry</h2>
            <div style={{ fontSize: 11.5, color: 'var(--txt2)', marginTop: 2 }}>
              Initialise inventory — Stockyard-wise and Vendor-wise. One entry per Vendor × Material combination.
            </div>
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            {selSY && (locked ? (
              <button type="button"
                onClick={() => { setShowUnlockConfirm(true); setLockReason(''); }}
                style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '5px 13px', borderRadius: 7, border: '1.5px solid var(--bdr)', background: '#fff', fontWeight: 600, fontSize: 12, cursor: 'pointer', color: 'var(--txt2)' }}>
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>
                Locked
                {canUnlock && <span style={{ fontWeight: 400, fontSize: 11, color: 'var(--or)', marginLeft: 2 }}>Unlock →</span>}
              </button>
            ) : (
              <button type="button" onClick={() => setShowLockConfirm(true)}
                style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '5px 13px', borderRadius: 7, border: '1.5px solid var(--or-bdr)', background: 'var(--or-lt)', fontWeight: 600, fontSize: 12, cursor: 'pointer', color: 'var(--or2)' }}>
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 019.9-1"/></svg>
                Unlocked
                <span style={{ fontWeight: 400, fontSize: 11, marginLeft: 2 }}>Lock →</span>
              </button>
            ))}
            {selSY && !locked && (
              <button type="button" onClick={() => setShowAuditLog(true)}
                style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '5px 11px', borderRadius: 7, border: '1.5px solid var(--bdr)', background: '#fff', fontWeight: 500, fontSize: 11.5, cursor: 'pointer', color: 'var(--txt2)' }}
                title="View complete audit trail for this stockyard">
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
                  <polyline points="14 2 14 8 20 8"/>
                  <line x1="16" y1="13" x2="8" y2="13"/>
                  <line x1="16" y1="17" x2="8" y2="17"/>
                  <polyline points="10 9 9 9 8 9"/>
                </svg>
                View Edit History
              </button>
            )}
            <button className="mod-x" onClick={onClose}>×</button>
          </div>
        </div>

        <div className="mod-bd">

          {/* ── Header fields ─────────────────────────────────────────────── */}
          <div className="fg3" style={{ marginBottom: 14 }}>
            <div className="fld">
              <label>Company</label>
              <input className="inp" readOnly
                value={syCompany?.name || (selSY ? '—' : isGroup ? 'Select stockyard' : (companies.find(c => c.id === companyId)?.name || '—'))}
                style={{ background: '#F9FAFB', cursor: 'default', color: 'var(--txt2)' }} />
            </div>
            <div className="fld">
              <label>Stockyard <span className="req">*</span></label>
              <window.FormSelect
                placeholder="Select Stockyard"
                value={selSY}
                onChange={v => setSelSY(v)}
                options={availSY.map(s => ({ value: s.id, label: s.name + (isGroup ? ' — ' + (companies.find(c => c.id === s.companyId)?.name || '') : '') }))}
              />
            </div>
            <div className="fld">
              <label>Opening Date</label>
              <input className="inp" type="date" value={openingDate}
                onChange={e => setOpeningDate(e.target.value)}
                disabled={locked || rows.length > 0} />
            </div>
          </div>

          {/* ── Warning banner — unlocked + transactions ───────────────────── */}
          {selSY && !locked && hasTxns && (
            <div style={{ background: '#FFFBEB', border: '1.5px solid #FDE68A', borderRadius: 8, padding: '10px 14px', marginBottom: 14, display: 'flex', gap: 8, alignItems: 'flex-start' }}>
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#92400E" strokeWidth="2" style={{ flexShrink: 0, marginTop: 1 }}>
                <path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/>
                <line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>
              </svg>
              <div>
                <div style={{ fontWeight: 700, fontSize: 12, color: '#92400E' }}>Opening Stock is currently unlocked</div>
                <div style={{ fontSize: 11, color: '#78350F', marginTop: 2 }}>
                  Changes made here will recalculate inventory balances across the ERP.
                  Complete your changes and lock the Opening Stock again.
                </div>
              </div>
            </div>
          )}

          {/* ── Locked notice ─────────────────────────────────────────────── */}
          {selSY && locked && (
            <div style={{ background: '#FEF9C3', border: '1px solid #FDE68A', borderRadius: 8, padding: '10px 14px', marginBottom: 14, display: 'flex', gap: 8, alignItems: 'center' }}>
              <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#92400E" strokeWidth="2" style={{ flexShrink: 0 }}>
                <rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/>
              </svg>
              <div style={{ fontSize: 11.5, color: '#92400E' }}>
                <strong>Opening Stock Locked.</strong>{' '}
                {'Click "Unlocked → Unlock" above to enable editing.'}
              </div>
            </div>
          )}

          {/* ── Inventory lines ───────────────────────────────────────────── */}
          {selSY ? (
            <div>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
                <div style={{ fontWeight: 700, fontSize: 12.5 }}>
                  Inventory Lines
                  <span style={{ fontWeight: 400, color: 'var(--txt2)', marginLeft: 6 }}>
                    {rows.length} line{rows.length !== 1 ? 's' : ''}
                    {rows.length > 0 ? ` — ${totalQty.toFixed(3)} MT total` : ''}
                  </span>
                </div>
                {!locked && (
                  <button type="button" className="btn btn-wh btn-sm"
                    style={{ borderColor: 'var(--ok)', color: 'var(--ok)' }} onClick={startAddRow}>
                    <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
                      <line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
                    </svg>
                    + Add New
                  </button>
                )}
              </div>

              <div className="ig">
                <table style={{ width: '100%', borderCollapse: 'collapse', tableLayout: 'fixed' }}>
                  <colgroup>
                    {(locked ? colsLocked : colsUnlocked).map((w, i) => <col key={i} style={{ width: w }} />)}
                  </colgroup>
                  <thead>
                    <tr>
                      <th style={{ textAlign: 'center' }}>#</th>
                      <th>VENDOR</th>
                      <th>MATERIAL</th>
                      <th style={{ textAlign: 'center' }}>UNIT</th>
                      <th>OPENING QTY</th>
                      <th>REMARKS</th>
                      {!locked && <th style={{ textAlign: 'center' }}>ACTION</th>}
                    </tr>
                  </thead>
                  <tbody>
                    {rows.length === 0 && pendingRows.length === 0 ? (
                      <tr>
                        <td colSpan={locked ? 6 : 7} style={{ textAlign: 'center', padding: 28, color: 'var(--txt3)', fontSize: 12 }}>
                          {locked ? 'No opening stock entries for this stockyard.' : 'No entries yet. Click "Add Row" to begin.'}
                        </td>
                      </tr>
                    ) : rows.map((row, idx) => {
                      const isEditingThis = editingId === row.id;
                      return (
                        <tr key={row.id} style={{ background: isEditingThis ? '#FFF7ED' : '' }}>
                          <td style={{ textAlign: 'center', fontSize: 11, color: 'var(--txt3)', padding: '4px 2px' }}>{idx + 1}</td>

                          {/* Vendor */}
                          <td style={{ padding: '4px 6px' }}>
                            {isEditingThis ? (
                              <window.FormSelect
                                placeholder="Select Vendor"
                                value={editForm.vendorId}
                                onChange={v => setEditForm(p => ({ ...p, vendorId: v }))}
                                options={vendors.map(v => ({ value: v.id, label: v.name }))}
                                style={{ minWidth: 0 }}
                              />
                            ) : <span style={{ fontSize: 12, fontWeight: 500 }}>{venName(row.vendorId)}</span>}
                          </td>

                          {/* Material */}
                          <td style={{ padding: '4px 6px' }}>
                            {isEditingThis ? (
                              <window.FormSelect
                                placeholder="Select Material"
                                value={editForm.materialId}
                                onChange={v => setEditForm(p => ({ ...p, materialId: v }))}
                                options={activeMats.map(m => ({ value: m.id, label: m.name }))}
                                style={{ minWidth: 0 }}
                              />
                            ) : <span style={{ fontSize: 12, fontWeight: 500 }}>{matName(row.materialId)}</span>}
                          </td>

                          {/* Unit */}
                          <td style={{ padding: '4px 8px', color: 'var(--txt2)', fontSize: 11.5, textAlign: 'center', fontWeight: 500 }}>
                            {(isEditingThis ? editForm.materialId : row.materialId) ? matUnit(isEditingThis ? editForm.materialId : row.materialId) : '—'}
                          </td>

                          {/* Qty */}
                          <td style={{ padding: '4px 6px' }}>
                            {isEditingThis ? (
                              <input type="number" min="0" step="0.001" placeholder="0.000"
                                value={editForm.qty} onChange={e => setEditForm(p => ({ ...p, qty: e.target.value }))}
                                style={inpNum} />
                            ) : <span style={{ fontSize: 12, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{Number(row.qty || 0).toFixed(3)}</span>}
                          </td>

                          {/* Remarks */}
                          <td style={{ padding: '4px 6px' }}>
                            {isEditingThis ? (
                              <input placeholder="Remarks…" value={editForm.remarks}
                                onChange={e => setEditForm(p => ({ ...p, remarks: e.target.value }))}
                                style={inpTxt} />
                            ) : <span style={{ fontSize: 11, color: 'var(--txt2)' }}>{row.remarks || '—'}</span>}
                          </td>

                          {/* Action */}
                          {!locked && (
                            <td style={{ padding: '4px 6px' }}>
                              {isEditingThis ? (
                                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                                  <input placeholder="Reason for edit *" value={editReason}
                                    onChange={e => setEditReason(e.target.value)}
                                    style={{ ...inpTxt, fontSize: 11, borderColor: editReason ? 'var(--bdr)' : '#FCD34D', background: '#FFFBEB' }} />
                                  <div style={{ display: 'flex', gap: 4 }}>
                                    <button type="button" onClick={() => saveEdit(row)} disabled={saving}
                                      style={{ flex: 1, height: 26, border: '1.5px solid var(--ok)', borderRadius: 6, background: '#F0FDF4', color: 'var(--ok)', cursor: 'pointer', fontSize: 11, fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 3 }}>
                                      <CheckSvg /> Save
                                    </button>
                                    <button type="button" onClick={cancelEdit}
                                      style={{ width: 26, height: 26, border: '1.5px solid var(--bdr)', borderRadius: 6, background: '#fff', color: 'var(--txt2)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 15 }}>×</button>
                                  </div>
                                </div>
                              ) : (
                                <div style={{ display: 'flex', gap: 4, justifyContent: 'center' }}>
                                  <button type="button" onClick={() => startEdit(row)} title="Edit"
                                    style={iconBtn('var(--info)')}
                                    onMouseEnter={e => { e.currentTarget.style.background = '#EFF6FF'; e.currentTarget.style.borderColor = 'var(--info)'; }}
                                    onMouseLeave={e => { e.currentTarget.style.background = '#fff'; e.currentTarget.style.borderColor = 'var(--bdr)'; }}>
                                    <EditSvg />
                                  </button>
                                  <button type="button" onClick={() => confirmDelete(row)} title="Delete"
                                    style={iconBtn('var(--err)')}
                                    onMouseEnter={e => { e.currentTarget.style.background = '#FEE2E2'; e.currentTarget.style.borderColor = 'var(--err)'; }}
                                    onMouseLeave={e => { e.currentTarget.style.background = '#fff'; e.currentTarget.style.borderColor = 'var(--bdr)'; }}>
                                    <TrashSvg />
                                  </button>
                                </div>
                              )}
                            </td>
                          )}
                        </tr>
                      );
                    })}

                    {/* ── Pending new rows ─────────────────────────────────── */}
                    {pendingRows.map((tempRow, pi) => (
                      <tr key={tempRow._tempId} style={{ background: '#F0FDF4' }}>
                        <td style={{ textAlign: 'center', fontSize: 10, color: 'var(--ok)', fontWeight: 700, padding: '4px 2px' }}>NEW</td>
                        <td style={{ padding: '4px 6px' }}>
                          <window.FormSelect
                            placeholder="Select Vendor"
                            value={tempRow.vendorId}
                            onChange={v => updatePendingRow(tempRow._tempId, 'vendorId', v)}
                            options={vendors.map(v => ({ value: v.id, label: v.name }))}
                            style={{ minWidth: 0 }}
                          />
                        </td>
                        <td style={{ padding: '4px 6px' }}>
                          <window.FormSelect
                            placeholder="Select Material"
                            value={tempRow.materialId}
                            onChange={v => updatePendingRow(tempRow._tempId, 'materialId', v)}
                            options={activeMats.map(m => ({ value: m.id, label: m.name }))}
                            style={{ minWidth: 0 }}
                          />
                        </td>
                        <td style={{ padding: '4px 8px', color: 'var(--txt2)', fontSize: 11.5, textAlign: 'center', fontWeight: 500 }}>
                          {tempRow.materialId ? matUnit(tempRow.materialId) : '—'}
                        </td>
                        <td style={{ padding: '4px 6px' }}>
                          <input type="number" min="0" step="0.001" placeholder="0.000"
                            value={tempRow.qty} onChange={e => updatePendingRow(tempRow._tempId, 'qty', e.target.value)}
                            style={{ ...inpNum, borderColor: 'var(--ok)' }} />
                        </td>
                        <td style={{ padding: '4px 6px' }}>
                          <input placeholder="Remarks…" value={tempRow.remarks}
                            onChange={e => updatePendingRow(tempRow._tempId, 'remarks', e.target.value)}
                            style={{ ...inpTxt, borderColor: 'var(--ok)' }} />
                        </td>
                        <td style={{ padding: '4px 6px' }}>
                          <div style={{ display: 'flex', gap: 4 }}>
                            <button type="button" onClick={() => savePendingRow(tempRow)} disabled={saving}
                              style={{ flex: 1, height: 28, border: '1.5px solid var(--ok)', borderRadius: 6, background: '#F0FDF4', color: 'var(--ok)', cursor: 'pointer', fontSize: 11, fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 3 }}>
                              <CheckSvg /> Save
                            </button>
                            <button type="button" onClick={() => cancelPendingRow(tempRow._tempId)}
                              style={{ width: 28, height: 28, border: '1.5px solid var(--bdr)', borderRadius: 6, background: '#fff', color: 'var(--txt2)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 15 }}>×</button>
                          </div>
                        </td>
                      </tr>
                    ))}
                  </tbody>

                  {rows.length > 0 && (
                    <tfoot>
                      <tr>
                        <td colSpan={4} style={{ padding: '7px 8px', fontWeight: 700, fontSize: 11, color: 'var(--txt2)' }}>
                          TOTAL — {rows.length} line{rows.length !== 1 ? 's' : ''}
                        </td>
                        <td style={{ padding: '7px 8px', fontWeight: 700, color: 'var(--or)', fontSize: 12, fontVariantNumeric: 'tabular-nums' }}>
                          {totalQty.toFixed(3)}
                        </td>
                        <td></td>
                        {!locked && <td></td>}
                      </tr>
                    </tfoot>
                  )}
                </table>
              </div>
            </div>
          ) : (
            <div style={{ textAlign: 'center', padding: 32, background: '#F9FAFB', borderRadius: 8, border: '1px dashed var(--bdr)', color: 'var(--txt3)', fontSize: 12 }}>
              Select a stockyard above to view or enter opening stock entries.
            </div>
          )}

        </div>

        <div className="mod-ft">
          <button type="button" className="btn btn-wh" onClick={onClose}>Close</button>
        </div>
      </div>

      {/* ── Unlock Confirmation ────────────────────────────────────────────── */}
      {showUnlockConfirm && (
        <div className="mbg" style={{ zIndex: 10001 }}>
          <div className="mod mod-sm">
            <div className="mod-hd">
              <h2>Unlock Opening Stock</h2>
              <button className="mod-x" onClick={() => setShowUnlockConfirm(false)}>×</button>
            </div>
            <div className="mod-bd">
              <div style={{ background: '#FFF7ED', border: '1px solid var(--or-bdr)', borderRadius: 7, padding: '10px 14px', marginBottom: 14, fontSize: 12.5, color: '#92400E', lineHeight: 1.7 }}>
                Opening Stock contains inventory affecting current stock balances.<br />
                Unlocking will allow modifications.<br />
                All inventory balances will be recalculated after saving.<br />
                <strong>Do you want to continue?</strong>
              </div>
              <div className="fld">
                <label>Reason for Unlock <span className="req">*</span></label>
                <input className="inp" value={lockReason} onChange={e => setLockReason(e.target.value)} placeholder="Why are you unlocking?" autoFocus />
              </div>
            </div>
            <div className="mod-ft">
              <button className="btn btn-wh" onClick={() => setShowUnlockConfirm(false)}>Cancel</button>
              <button className="btn btn-or" onClick={doUnlock} disabled={!lockReason.trim()}>Unlock Opening Stock</button>
            </div>
          </div>
        </div>
      )}

      {/* ── Lock Confirmation ──────────────────────────────────────────────── */}
      {showLockConfirm && (
        <div className="mbg" style={{ zIndex: 10001 }}>
          <div className="mod mod-sm">
            <div className="mod-hd">
              <h2>Lock Opening Stock</h2>
              <button className="mod-x" onClick={() => setShowLockConfirm(false)}>×</button>
            </div>
            <div className="mod-bd">
              <p style={{ fontSize: 12.5, lineHeight: 1.7, color: 'var(--txt)' }}>
                Locking Opening Stock will prevent further modifications until it is unlocked again.<br />
                <strong>Continue?</strong>
              </p>
            </div>
            <div className="mod-ft">
              <button className="btn btn-wh" onClick={() => setShowLockConfirm(false)}>Cancel</button>
              <button className="btn btn-or" onClick={doLock}>Lock Opening Stock</button>
            </div>
          </div>
        </div>
      )}

      {/* ── Delete Confirmation ────────────────────────────────────────────── */}
      {deleteConfirm && (
        <div className="mbg" style={{ zIndex: 10001 }}>
          <div className="mod mod-sm">
            <div className="mod-hd">
              <h2>Delete Opening Stock Entry</h2>
              <button className="mod-x" onClick={cancelDelete}>×</button>
            </div>
            <div className="mod-bd">
              <div style={{ background: '#FEE2E2', border: '1px solid #FECACA', borderRadius: 7, padding: '10px 14px', marginBottom: 14, fontSize: 12.5, color: '#991B1B', lineHeight: 1.7 }}>
                This will permanently remove the selected Opening Stock entry:<br />
                <strong>{venName(deleteConfirm.row.vendorId)} / {matName(deleteConfirm.row.materialId)} — {Number(deleteConfirm.row.qty || 0).toFixed(3)} MT</strong><br />
                All downstream inventory balances will be recalculated.<br />
                <strong>Do you want to continue?</strong>
              </div>
              <div className="fld">
                <label>Reason for Deletion <span className="req">*</span></label>
                <input className="inp" value={deleteReason} onChange={e => setDeleteReason(e.target.value)} placeholder="Required" autoFocus />
              </div>
            </div>
            <div className="mod-ft">
              <button className="btn btn-wh" onClick={cancelDelete}>Cancel</button>
              <button className="btn btn-rd" onClick={doDelete} disabled={!deleteReason.trim()}>Delete Entry</button>
            </div>
          </div>
        </div>
      )}

      {/* ── Audit Log Modal ─────────────────────────────────────────────── */}
      {showAuditLog && (() => {
        const auditLogs = (Store.all('openingStockAuditLog') || [])
          .filter(l => l.stockyardId === selSY)
          .sort((a, b) => (b.date + b.time).localeCompare(a.date + a.time));

        function parseAV(str) { try { return str ? JSON.parse(str) : null; } catch { return null; } }

        const AC = {
          Unlock: { bg: '#FFF7ED', cl: '#C2410C', bd: '#FED7AA' },
          Lock:   { bg: '#F0FDF4', cl: '#166534', bd: '#BBF7D0' },
          Create: { bg: '#EFF6FF', cl: '#1D4ED8', bd: '#BFDBFE' },
          Edit:   { bg: '#FEFCE8', cl: '#854D0E', bd: '#FDE68A' },
          Delete: { bg: '#FEF2F2', cl: '#991B1B', bd: '#FECACA' },
        };

        return (
          <div className="mbg" style={{ zIndex: 10002 }}>
            <div className="mod mod-xl" style={{ maxWidth: 1140 }}>
              <div className="mod-hd">
                <div>
                  <h2 style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
                      <polyline points="14 2 14 8 20 8"/>
                      <line x1="16" y1="13" x2="8" y2="13"/>
                      <line x1="16" y1="17" x2="8" y2="17"/>
                      <polyline points="10 9 9 9 8 9"/>
                    </svg>
                    Opening Stock Edit History
                  </h2>
                  <div style={{ fontSize: 11.5, color: 'var(--txt2)', marginTop: 2 }}>
                    {selSYObj?.name}{syCompany ? ` — ${syCompany.name}` : ''}
                    {' · '}{auditLogs.length} audit entr{auditLogs.length !== 1 ? 'ies' : 'y'} · All sessions preserved
                  </div>
                </div>
                <button className="mod-x" onClick={() => setShowAuditLog(false)}>×</button>
              </div>
              <div className="mod-bd" style={{ padding: 0 }}>
                {auditLogs.length === 0 ? (
                  <div style={{ textAlign: 'center', padding: 48, color: 'var(--txt3)', fontSize: 13 }}>
                    No audit entries have been recorded for this stockyard yet.
                  </div>
                ) : (
                  <div className="tbl-w">
                    <table className="tbl" style={{ fontSize: 11 }}>
                      <thead>
                        <tr>
                          <th style={{ whiteSpace: 'nowrap' }}>DATE</th>
                          <th style={{ whiteSpace: 'nowrap' }}>TIME</th>
                          <th>USER</th>
                          <th>ACTION</th>
                          <th>MATERIAL</th>
                          <th>VENDOR</th>
                          <th style={{ textAlign: 'right', whiteSpace: 'nowrap' }}>PREV QTY</th>
                          <th style={{ textAlign: 'right', whiteSpace: 'nowrap' }}>NEW QTY</th>
                          <th style={{ whiteSpace: 'nowrap' }}>PREV REMARKS</th>
                          <th style={{ whiteSpace: 'nowrap' }}>NEW REMARKS</th>
                          <th>REASON</th>
                          <th style={{ whiteSpace: 'nowrap' }}>SESSION ID</th>
                        </tr>
                      </thead>
                      <tbody>
                        {auditLogs.map((log, i) => {
                          const oldV = parseAV(log.oldValue);
                          const newV = parseAV(log.newValue);
                          const matId = newV?.materialId || oldV?.materialId;
                          const venId = newV?.vendorId   || oldV?.vendorId;
                          const ac = AC[log.action] || { bg: '#F9FAFB', cl: '#374151', bd: '#E5E7EB' };
                          return (
                            <tr key={log.id || i}>
                              <td style={{ whiteSpace: 'nowrap', color: 'var(--txt2)', fontVariantNumeric: 'tabular-nums' }}>{log.date}</td>
                              <td style={{ whiteSpace: 'nowrap', color: 'var(--txt2)', fontVariantNumeric: 'tabular-nums' }}>{log.time}</td>
                              <td style={{ fontWeight: 500, whiteSpace: 'nowrap' }}>{log.user || '—'}</td>
                              <td>
                                <span style={{ display: 'inline-block', padding: '2px 7px', borderRadius: 5, fontSize: 10, fontWeight: 700, background: ac.bg, color: ac.cl, border: `1px solid ${ac.bd}`, letterSpacing: '0.04em', whiteSpace: 'nowrap' }}>
                                  {log.action ? log.action.toUpperCase() : '—'}
                                </span>
                              </td>
                              <td style={{ fontWeight: 500 }}>{matId ? matName(matId) : '—'}</td>
                              <td style={{ fontWeight: 500 }}>{venId ? venName(venId) : '—'}</td>
                              <td style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: oldV?.qty != null ? '#991B1B' : 'var(--txt3)' }}>
                                {oldV?.qty != null ? Number(oldV.qty).toFixed(3) : '—'}
                              </td>
                              <td style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', color: newV?.qty != null ? '#166534' : 'var(--txt3)' }}>
                                {newV?.qty != null ? Number(newV.qty).toFixed(3) : '—'}
                              </td>
                              <td style={{ color: 'var(--txt2)', fontSize: 10.5, maxWidth: 120, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={oldV?.remarks}>{oldV?.remarks || '—'}</td>
                              <td style={{ color: 'var(--txt2)', fontSize: 10.5, maxWidth: 120, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={newV?.remarks}>{newV?.remarks || '—'}</td>
                              <td style={{ color: 'var(--txt)', fontSize: 10.5, maxWidth: 180, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={log.reason}>{log.reason || '—'}</td>
                              <td style={{ fontFamily: 'monospace', fontSize: 9.5, color: 'var(--txt3)', whiteSpace: 'nowrap' }}>{log.sessionId || '—'}</td>
                            </tr>
                          );
                        })}
                      </tbody>
                    </table>
                  </div>
                )}
              </div>
              <div className="mod-ft">
                <span style={{ fontSize: 11, color: 'var(--txt3)', marginRight: 'auto' }}>
                  Showing all sessions — records are never overwritten
                </span>
                <button className="btn btn-wh" onClick={() => setShowAuditLog(false)}>Close</button>
              </div>
            </div>
          </div>
        );
      })()}
    </div>
  );
}
window.OpeningStockModal = OpeningStockModal;

// ── Opening Stock List ───────────────────────────────────────────────────────
function OpeningStockList({ stockyards, materials, companyId, onOpenSetup }) {
  const isGroup   = companyId === 'group';
  const companies = Store.all('companies');
  const records   = Store.all('openingStocks') || [];

  const visibleSY = isGroup
    ? stockyards
    : stockyards.filter(s => !s.companyId || s.companyId === companyId);

  const rows = visibleSY.map(sy => {
    const recs      = records.filter(r => r.stockyardId === sy.id);
    const locked    = osIsLocked(sy.id);
    const vendorSet = new Set(recs.map(r => r.vendorId).filter(Boolean));
    const matSet    = new Set(recs.map(r => r.materialId).filter(Boolean));
    const totalQty  = recs.reduce((s, r) => s + (r.qty || 0), 0);
    return { sy, recs, locked, vendorCount: vendorSet.size, matCount: matSet.size, lineCount: recs.length, totalQty, hasRec: recs.length > 0 };
  });

  return (
    <div className="card">
      <div className="card-hd">
        <h3>Opening Stock Records</h3>
        <span style={{ fontSize: 11.5, color: 'var(--txt2)' }}>
          {rows.filter(r => r.hasRec).length} of {rows.length} stockyards initialised
        </span>
      </div>
      <div className="tbl-w">
        <table className="tbl">
          <thead>
            <tr>
              {isGroup && <th>COMPANY</th>}
              <th>STOCKYARD</th>
              <th style={{ textAlign: 'center' }}>VENDORS</th>
              <th style={{ textAlign: 'center' }}>MATERIALS</th>
              <th style={{ textAlign: 'center' }}>LINES</th>
              <th>TOTAL QTY</th>
              <th>STATUS</th>
              <th>ACTIONS</th>
            </tr>
          </thead>
          <tbody>
            {rows.length === 0 ? (
              <tr className="empty">
                <td colSpan={isGroup ? 8 : 7} style={{ textAlign: 'center', padding: 36, color: 'var(--txt2)' }}>No stockyards found.</td>
              </tr>
            ) : rows.map(({ sy, locked, vendorCount, matCount, lineCount, totalQty, hasRec }) => (
              <tr key={sy.id}>
                {isGroup && <td style={{ fontSize: 11.5, color: 'var(--txt2)' }}>{companies.find(c => c.id === sy.companyId)?.name || '—'}</td>}
                <td style={{ fontWeight: 500 }}>{sy.name}</td>
                <td style={{ textAlign: 'center', fontWeight: 600, color: hasRec ? 'var(--info)' : 'var(--txt3)' }}>{hasRec ? vendorCount : '—'}</td>
                <td style={{ textAlign: 'center', fontWeight: 600 }}>{hasRec ? matCount : '—'}</td>
                <td style={{ textAlign: 'center', fontWeight: 600 }}>{hasRec ? lineCount : '—'}</td>
                <td style={{ fontWeight: 600, color: hasRec ? 'var(--or)' : 'var(--txt3)' }}>{hasRec ? window.formatQuantity(totalQty) + ' MT' : '—'}</td>
                <td>
                  {!hasRec ? (
                    <span className="bdg bg-gy">Not Set</span>
                  ) : locked ? (
                    <span className="bdg bg-yw" style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                      <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>
                      Locked
                    </span>
                  ) : (
                    <span className="bdg bg-gn">Unlocked</span>
                  )}
                </td>
                <td>
                  <button className="btn btn-wh btn-sm" onClick={() => onOpenSetup(sy.id)}>
                    {hasRec ? (locked ? 'View / Edit' : 'Edit') : 'Setup'}
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
window.OpeningStockList = OpeningStockList;
