// ─── Savuki Drilling — Stock Module ──────────────────────────────────────
import { getTeams } from '../api.js';
import { showToast, openModal, closeModal, navigate } from '../app.js';
import { richSelect, teamItems } from './rich-select.js';

const BASE = '/api/stock';
function token() { return localStorage.getItem('sd_token') || ''; }

async function apiFetch(path, params = {}) {
  const qs = new URLSearchParams({ ...params, token: token() });
  const res = await fetch(`${BASE}/${path}?${qs}`);
  const json = await res.json();
  if (!json.success) throw new Error(json.message);
  return json.data;
}

async function apiPost(path, data) {
  const body = new URLSearchParams({ ...data, token: token() });
  const res = await fetch(`${BASE}/${path}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body,
  });
  const json = await res.json();
  if (!json.success) throw new Error(json.message);
  return json.data;
}

let _teams = [];
let _types = [];
let _suppliers = [];
let _pumpCodes = [];
let _isAdmin = false;
let _canSeePrice = false;

async function loadLookups() {
  try {
    [_teams] = await Promise.all([getTeams().catch(() => [])]);
    const lk = await apiFetch('lookups.php');
    _types = lk.types || [];
    _suppliers = lk.suppliers || [];
    _pumpCodes = lk.pump_codes || [];
  } catch { }
}

// ═════════════════════════════════════════════════════════════════════════
// CURRENT STOCK
// ═════════════════════════════════════════════════════════════════════════
export async function initStock(role) {
  _isAdmin = ['admin', 'dev', 'test', 'dispatch', 'workshop'].includes(role);
  _canSeePrice = ['admin', 'dispatch', 'dev', 'test'].includes(role);
  const c = document.getElementById('view-content');
  c.innerHTML = `
  <div class="page-header">
    <div><h1>Current Stock</h1></div>
    ${_isAdmin ? `<button class="btn btn-accent" id="btn-add-stock">+ Add Stock</button>` : ''}
  </div>

  <!-- ── Stat cards ────────────────────────────────────────────────── -->
  <div class="stat-grid" id="stock-stats" style="margin-bottom:1.25rem">
    <div class="stat-card navy" style="animation:none">
      <div class="stat-label">Total Items</div>
      <div class="stat-value" id="sc-total">—</div>
      <div class="stat-sub">stock lines</div>
    </div>
    ${_canSeePrice ? `<div class="stat-card orange">
      <div class="stat-label">Total Stock Value</div>
      <div class="stat-value" id="sc-value" style="font-size:1.4rem">—</div>
      <div class="stat-sub">based on qty × price</div>
    </div>` : ''}
    <div class="stat-card red">
      <div class="stat-label">Out of Stock</div>
      <div class="stat-value" id="sc-out">—</div>
      <div class="stat-sub">balance ≤ 0</div>
    </div>
    <div class="stat-card" style="--before-bg:var(--warning)">
      <div class="stat-label">Low Stock</div>
      <div class="stat-value" id="sc-low">—</div>
      <div class="stat-sub">balance 1–2</div>
    </div>
  </div>

  <div class="toolbar" style="margin-bottom:1rem">
    <div class="toolbar-filters">
      <input class="form-control" id="s-search" placeholder="Search items…" style="width:200px" />
      <select class="form-control" id="s-type" style="width:160px">
        <option value="">All Types</option>
      </select>
  ${_isAdmin || _canSeePrice ? `<button class="btn btn-ghost btn-sm" id="btn-stock-report">
        📊 Reports
      </button>` : ''}
    </div>
  </div>

  <div id="stock-wrap">
    <div class="page-loader"><div class="spinner"></div></div>
  </div>`;

  await loadLookups();

  // Populate type filter
  const typeSelect = document.getElementById('s-type');
  _types.forEach(t => {
    const o1 = document.createElement('option');
    o1.value = t.record_id; o1.textContent = t.name;
    typeSelect?.appendChild(o1);
  });

  const load = async () => {
    const wrap = document.getElementById('stock-wrap');
    if (!wrap) return;
    wrap.innerHTML = `<div class="page-loader"><div class="spinner"></div></div>`;
    try {
      const data = await apiFetch('list.php', {
        search: document.getElementById('s-search')?.value || '',
        type: document.getElementById('s-type')?.value || '',
      });
      wrap.innerHTML = renderStockTable(data.stock);
      wrap.querySelectorAll('.s-edit').forEach(b =>
        b.addEventListener('click', () => openEditStockModal(JSON.parse(decodeURIComponent(b.dataset.item)), load))
      );
      bindShowMore(wrap);
    } catch (err) {
      wrap.innerHTML = `<div class="empty-state"><p>${err.message}</p></div>`;
    }
  };

  // Load stat cards (unfiltered, always full picture)
  const loadStats = async () => {
    try {
      const s = await apiFetch('stats.php');
      const el = (id, val) => { const e = document.getElementById(id); if (e) e.textContent = val; };
      el('sc-total', s.total_items.toLocaleString());
      el('sc-out', s.out_of_stock.toLocaleString());
      el('sc-low', s.low_stock.toLocaleString());
      if (_canSeePrice) el('sc-value', `R ${(+s.total_value).toLocaleString('en-ZA', { minimumFractionDigits: 2 })}`);
    } catch { }
  };

  document.getElementById('s-search')?.addEventListener('input', debounce(load, 350));
  document.getElementById('s-type')?.addEventListener('change', load);
  document.getElementById('btn-add-stock')?.addEventListener('click', () => openAddStockModal(load));
  document.getElementById('btn-stock-report')?.addEventListener('click', () => openReportModal());

  await Promise.all([load(), loadStats()]);
}

function renderStockTable(rows) {
  if (!rows?.length) return `<div class="empty-state" style="padding:2rem"><p>No stock items found.</p></div>`;

  // Group by type
  const groups = {};
  rows.forEach(r => {
    const key = r.type_name || 'Other';
    if (!groups[key]) groups[key] = [];
    groups[key].push(r);
  });

  return Object.entries(groups).map(([typeName, items]) => `
    <div class="card" style="margin-bottom:1rem">
      <div class="card-header">
        <span class="card-title">${typeName}</span>
        <span class="badge badge-navy">${items.length} items</span>
      </div>
      <div class="card-body" style="padding:0">
        <div class="table-wrap"><table>
          <thead><tr>
            <th>Stock No</th><th>Item</th><th>Type/Size</th>
            <th>Supplier</th>${_canSeePrice ? '<th>Price</th>' : ''}<th>Balance</th>
            ${_isAdmin ? '<th></th>' : ''}
          </tr></thead>
          <tbody>
            ${items.map(r => {
    const low = +r.balance <= 2;
    const zero = +r.balance <= 0;
    const rowStyle = zero ? 'style="background:var(--danger-bg)"'
      : low ? 'style="background:var(--warning-bg)"' : '';
    return `<tr ${rowStyle}>
                <td data-label="Stock No"><strong>${r.stock_no}</strong></td>
                <td data-label="Item">${r.item_name}</td>
                <td data-label="Type/Size" style="color:var(--text-muted);font-size:0.82rem">${[r.type, r.size].filter(Boolean).join(' ') || '—'}</td>
                <td data-label="Supplier" style="color:var(--text-muted);font-size:0.82rem">${r.supplier_name || '—'}</td>
                ${_canSeePrice ? `<td data-label="Price" style="font-size:0.82rem">${r.item_price ? `R ${(+r.item_price).toFixed(2)}` : '—'}</td>` : ''}
                <td data-label="Balance">
                  <strong style="color:${zero ? 'var(--danger)' : low ? 'var(--warning)' : 'var(--success)'}">${r.balance}</strong>
                  ${r.unit_of_measure ? `<span style="font-size:0.75rem;color:var(--text-muted)"> ${r.unit_of_measure}</span>` : ''}
                  ${zero ? `<span class="badge badge-drilling" style="margin-left:.4rem">OUT</span>` : ''}
                  ${low && !zero ? `<span class="badge badge-pending" style="margin-left:.4rem">LOW</span>` : ''}
                </td>
                ${_isAdmin ? `<td data-label=""><button class="btn btn-ghost btn-sm s-edit"
                  data-item="${encodeURIComponent(JSON.stringify(r))}">Edit</button></td>` : ''}
              </tr>`;
  }).join('')}
          </tbody>
        </table></div>
      </div>
    </div>`).join('');
}

// ═════════════════════════════════════════════════════════════════════════
// ADD / EDIT STOCK MODALS
// ═════════════════════════════════════════════════════════════════════════
// ── Stock type name → category key ───────────────────────────────
function stockCategory(typeName) {
  const n = (typeName || '').toUpperCase();
  if (n.includes('OIL')) return 'OILS';
  if (n.includes('HYDRO')) return 'HYDRO';
  if (n.includes('PUMP')) return 'PUMPS';
  if (n.includes('HAMMER') || n.includes('BYTEL') || n.includes('RIEMER')) return 'HBR';
  if (n.includes('BOLT') || n.includes('NUT')) return 'BOLTS';
  if (n.includes('CONSUMABLE')) return 'CONSUMABLES';
  return 'OTHER';
}

function stockFormFields(item = {}) {
  const typeOpts = _types.map(t =>
    `<option value="${t.record_id}" ${item.stock_type_id == t.record_id ? 'selected' : ''}>${t.name}</option>`
  ).join('');
  const suppOpts = _suppliers.map(s =>
    `<option value="${s.record_id}" ${item.supplier_id == s.record_id ? 'selected' : ''}>${s.name}</option>`
  ).join('');

  // Determine initial category from existing item type
  const initType = _types.find(t => t.record_id == item.stock_type_id);
  const initCat = stockCategory(initType?.name || '');

  const uomOpts = ['', 'each', 'liters', 'meters', 'ml'].map(u =>
    `<option value="${u}" ${item.unit_of_measure === u ? 'selected' : ''}>${u || '— Select —'}</option>`
  ).join('');

  return `
    <!-- Always visible: item name, supplier, stock type -->
    <div class="form-row">
      <div class="form-group">
        <label class="form-label">Item Name <span style="color:var(--danger)">*</span></label>
        <input class="form-control" id="si-name" value="${esc(item.item_name)}" />
      </div>
      <div class="form-group">
        <label class="form-label">Supplier</label>
        <select class="form-control" id="si-supplier">
          <option value="">— Select —</option>${suppOpts}
        </select>
      </div>
    </div>
    <div class="form-group">
      <label class="form-label">Stock Type <span style="color:var(--danger)">*</span></label>
      <select class="form-control" id="si-type">
        <option value="">— Select Type —</option>${typeOpts}
      </select>
    </div>

    <!-- OILS fields -->
    <div id="sf-oils" style="display:${initCat === 'OILS' ? 'block' : 'none'}">
      <div class="form-row">
        <div class="form-group">
          <label class="form-label">Stock Quantity</label>
          <input class="form-control" id="si-oils-qty" type="number" min="0" value="${item.quantity || ''}" />
        </div>
        <div class="form-group">
          <label class="form-label">Unit Type</label>
          <select class="form-control" id="si-oils-uom">${uomOpts}</select>
        </div>
      </div>
      <div class="form-row">
        ${_canSeePrice ? `<div class="form-group">
          <label class="form-label">Cost (R)</label>
          <input class="form-control" id="si-oils-price" type="number" step="0.01" value="${item.item_price || ''}" />
        </div>`: '<div class="form-group"></div>'}
        <div class="form-group">
          <label class="form-label">Vehicle Type</label>
          <select class="form-control" id="si-vehicle">
            <option value="">— Select —</option>
            ${['ALL', 'TRUCK', 'DONKIE', 'COMP', 'COMP TRUCK', 'OTHER'].map(v =>
    `<option value="${v}" ${item.vehicle_type === v ? 'selected' : ''}>${v}</option>`
  ).join('')}
          </select>
        </div>
      </div>
    </div>

    <!-- HYDRO fields -->
    <div id="sf-hydro" style="display:${initCat === 'HYDRO' ? 'block' : 'none'}">
      <div class="form-row">
        <div class="form-group">
          <label class="form-label">Type</label>
          <select class="form-control" id="si-hydro-type">
            <option value="">— Select —</option>
            <option value="PIPE" ${item.size_type === 'PIPE' ? 'selected' : ''}>Pipe</option>
            <option value="FITTING" ${item.size_type === 'FITTING' ? 'selected' : ''}>Fitting</option>
          </select>
        </div>
        <div class="form-group" id="sf-hydro-size-wrap"
             style="display:${item.size_type === 'PIPE' ? 'block' : 'none'}">
          <label class="form-label">Pipe Size</label>
          <select class="form-control" id="si-hydro-size">
            <option value="">— Select —</option>
            ${['2"', '1 1/2"', '1" p.m 2 wire', '1" p.m 4 wire', '1/2" p.m', '3/4" p.m', '3/8" p.m', '5/8" p.m'].map(s =>
    `<option value="${s}" ${item.size === s ? 'selected' : ''}>${s}</option>`
  ).join('')}
          </select>
        </div>
        <div class="form-group" id="sf-hydro-fitting-wrap"
             style="display:${item.size_type === 'FITTING' ? 'block' : 'none'}">
          <label class="form-label">Fitting Description</label>
          <input class="form-control" id="si-hydro-fitting"
                 placeholder="e.g. 2&quot; Female Elbow, 3/4 p.m Collar"
                 value="${esc(item.size_type === 'FITTING' ? (item.size || '') : '')}" />
        </div>
      </div>
      <div class="form-row">
        <div class="form-group">
          <label class="form-label">Stock Quantity</label>
          <input class="form-control" id="si-hydro-qty" type="number" min="0" value="${item.quantity || ''}" />
        </div>
        <div class="form-group">
          <label class="form-label">Unit Type</label>
          <select class="form-control" id="si-hydro-uom">${uomOpts}</select>
        </div>
      </div>
      ${_canSeePrice ? `<div class="form-group">
        <label class="form-label">Cost (R)</label>
        <input class="form-control" id="si-hydro-price" type="number" step="0.01" value="${item.item_price || ''}" />
      </div>`: ''}
    </div>

    <!-- PUMPS fields -->
    <div id="sf-pumps" style="display:${initCat === 'PUMPS' ? 'block' : 'none'}">
      <div class="form-group">
        <label class="form-label">Pump Code</label>
        <datalist id="pump-code-list">
          ${_pumpCodes.map(p => `<option value="${esc(p)}">`).join('')}
        </datalist>
        <input class="form-control" id="si-pump-code" list="pump-code-list"
               value="${esc(item.pump_code)}" placeholder="e.g. BY2ZER7" />
      </div>
    </div>

    <!-- HAMMER / BYTEL / RIEMER fields -->
    <div id="sf-hbr" style="display:${initCat === 'HBR' ? 'block' : 'none'}">
      <div class="form-group">
        <label class="form-label">Serial Number</label>
        <input class="form-control" id="si-serial" value="${esc(item.serial_number || item.size || '')}" />
      </div>
      <div class="form-row">
        <div class="form-group">
          <label class="form-label">Stock Quantity</label>
          <input class="form-control" id="si-hbr-qty" type="number" min="0" value="${item.quantity || ''}" />
        </div>
        <div class="form-group">
          <label class="form-label">Unit Type</label>
          <select class="form-control" id="si-hbr-uom">${uomOpts}</select>
        </div>
      </div>
      ${_canSeePrice ? `<div class="form-group">
        <label class="form-label">Cost (R)</label>
        <input class="form-control" id="si-hbr-price" type="number" step="0.01" value="${item.item_price || ''}" />
      </div>`: ''}
    </div>

    <!-- BOLTS & NUTS fields -->
    <div id="sf-bolts" style="display:${initCat === 'BOLTS' ? 'block' : 'none'}">
      <div class="form-row">
        <div class="form-group">
          <label class="form-label">Size</label>
          <select class="form-control" id="si-bolt-size">
            <option value="">— Select —</option>
            ${['M6', 'M8', 'M10', 'M12', 'M16'].map(s =>
    `<option value="${s}" ${item.size === s ? 'selected' : ''}>${s}</option>`
  ).join('')}
          </select>
        </div>
        <div class="form-group">
          <label class="form-label">Type</label>
          <select class="form-control" id="si-bolt-type">
            <option value="">— Select —</option>
            ${['25', '45', '70', '100', 'Nuts', 'Lock Nuts', 'Flat Washers', 'Spring Washers'].map(t =>
    `<option value="${t}" ${item.size_type === t ? 'selected' : ''}>${t}</option>`
  ).join('')}
          </select>
        </div>
      </div>
      <div class="form-row">
        <div class="form-group">
          <label class="form-label">Stock Quantity</label>
          <input class="form-control" id="si-bolts-qty" type="number" min="0" value="${item.quantity || ''}" />
        </div>
        <div class="form-group">
          <label class="form-label">Unit Type</label>
          <select class="form-control" id="si-bolts-uom">${uomOpts}</select>
        </div>
      </div>
      ${_canSeePrice ? `<div class="form-group">
        <label class="form-label">Cost (R)</label>
        <input class="form-control" id="si-bolts-price" type="number" step="0.01" value="${item.item_price || ''}" />
      </div>`: ''}
    </div>

    <!-- CONSUMABLES fields -->
    <div id="sf-cons" style="display:${initCat === 'CONSUMABLES' ? 'block' : 'none'}">
      <div class="form-row">
        <div class="form-group">
          <label class="form-label">Stock Quantity</label>
          <input class="form-control" id="si-cons-qty" type="number" min="0" value="${item.quantity || ''}" />
        </div>
        <div class="form-group">
          <label class="form-label">Unit Type</label>
          <select class="form-control" id="si-cons-uom">${uomOpts}</select>
        </div>
      </div>
      ${_canSeePrice ? `<div class="form-group">
        <label class="form-label">Cost (R)</label>
        <input class="form-control" id="si-cons-price" type="number" step="0.01" value="${item.item_price || ''}" />
      </div>`: ''}
    </div>`;
}

// Wire type-change show/hide — called after modal is in DOM
function wireStockTypeToggle() {
  const typeEl = document.getElementById('si-type');
  if (!typeEl) return;

  const showSection = (cat) => {
    ['oils', 'hydro', 'pumps', 'hbr', 'bolts', 'cons'].forEach(s => {
      const el = document.getElementById('sf-' + s);
      if (el) el.style.display = 'none';
    });
    const map = { OILS: 'oils', HYDRO: 'hydro', PUMPS: 'pumps', HBR: 'hbr', BOLTS: 'bolts', CONSUMABLES: 'cons' };
    const key = map[cat];
    if (key) {
      const el = document.getElementById('sf-' + key);
      if (el) el.style.display = 'block';
    }
  };

  typeEl.addEventListener('change', () => {
    const selected = _types.find(t => t.record_id == typeEl.value);
    // Clear all section-specific fields first
    const clearIds = [
      'si-name',
      'si-oils-qty', 'si-oils-uom', 'si-oils-price', 'si-vehicle',
      'si-hydro-type', 'si-hydro-size', 'si-hydro-fitting', 'si-hydro-qty', 'si-hydro-uom', 'si-hydro-price',
      'si-pump-code',
      'si-serial', 'si-hbr-qty', 'si-hbr-uom', 'si-hbr-price',
      'si-bolt-size', 'si-bolt-type', 'si-bolts-qty', 'si-bolts-uom', 'si-bolts-price',
      'si-cons-qty', 'si-cons-uom', 'si-cons-price',
    ];
    clearIds.forEach(id => {
      const el = document.getElementById(id);
      if (!el) return;
      if (el.tagName === 'SELECT') el.selectedIndex = 0;
      else el.value = '';
    });
    // Hide hydro sub-sections
    const sizeWrap = document.getElementById('sf-hydro-size-wrap');
    const fittingWrap = document.getElementById('sf-hydro-fitting-wrap');
    if (sizeWrap) sizeWrap.style.display = 'none';
    if (fittingWrap) fittingWrap.style.display = 'none';
    showSection(stockCategory(selected?.name || ''));
  });

  // Wire hydro type → show/hide pipe size + auto-name
  document.getElementById('si-hydro-type')?.addEventListener('change', e => {
    const isPipe = e.target.value === 'PIPE';
    const sizeWrap = document.getElementById('sf-hydro-size-wrap');
    const fittingWrap = document.getElementById('sf-hydro-fitting-wrap');
    if (sizeWrap) sizeWrap.style.display = isPipe ? 'block' : 'none';
    if (fittingWrap) fittingWrap.style.display = isPipe ? 'none' : 'block';
    if (!isPipe) {
      const sizeEl = document.getElementById('si-hydro-size');
      if (sizeEl) sizeEl.value = '';
    } else {
      const fitEl = document.getElementById('si-hydro-fitting');
      if (fitEl) fitEl.value = '';
    }
    _autoNameHydro();
  });
  document.getElementById('si-hydro-size')?.addEventListener('change', _autoNameHydro);
  document.getElementById('si-hydro-fitting')?.addEventListener('input', _autoNameHydroFitting);

  // Wire bolts → auto-name
  document.getElementById('si-bolt-size')?.addEventListener('change', _autoNameBolts);
  document.getElementById('si-bolt-type')?.addEventListener('change', _autoNameBolts);
}

function _autoNameHydro() {
  const nameEl = document.getElementById('si-name');
  if (!nameEl) return;
  const hType = document.getElementById('si-hydro-type')?.value || '';
  const hSize = document.getElementById('si-hydro-size')?.value || '';
  if (hType === 'PIPE' && hSize) {
    nameEl.value = `${hSize} Pipe`;
  } else if (hType === 'FITTING') {
    if (nameEl.value.endsWith(' Pipe')) nameEl.value = '';
  }
}

function _autoNameHydroFitting() {
  const nameEl = document.getElementById('si-name');
  const fitVal = document.getElementById('si-hydro-fitting')?.value || '';
  if (nameEl && fitVal) nameEl.value = fitVal;
}

function _autoNameBolts() {
  const nameEl = document.getElementById('si-name');
  if (!nameEl) return;
  const size = document.getElementById('si-bolt-size')?.value || '';
  const type = document.getElementById('si-bolt-type')?.value || '';
  if (size && type) {
    // Numeric types = bolt length: M8 X 100
    // Text types = nut/washer types: M8 Nuts
    const isLength = /^\d+$/.test(type);
    nameEl.value = isLength ? `${size} X ${type}` : `${size} ${type}`;
  } else if (size) {
    nameEl.value = size;
  } else if (type) {
    nameEl.value = type;
  }
}

function collectStockForm() {
  const typeEl = document.getElementById('si-type');
  const selected = _types.find(t => t.record_id == typeEl?.value);
  const cat = stockCategory(selected?.name || '');

  const g = id => document.getElementById(id)?.value || '';

  const base = {
    item_name: g('si-name').trim(),
    stock_type_id: g('si-type'),
    supplier_id: g('si-supplier'),
  };

  if (cat === 'OILS') {
    return {
      ...base,
      quantity: g('si-oils-qty'),
      unit_of_measure: g('si-oils-uom'),
      item_price: _canSeePrice ? g('si-oils-price') : undefined,
      vehicle_type: g('si-vehicle'),
    };
  }
  if (cat === 'HYDRO') {
    const ht = g('si-hydro-type');
    const sz = ht === 'PIPE' ? g('si-hydro-size') : g('si-hydro-fitting');
    return {
      ...base,
      size_type: ht,
      size: sz,
      quantity: g('si-hydro-qty'),
      unit_of_measure: g('si-hydro-uom'),
      item_price: _canSeePrice ? g('si-hydro-price') : undefined,
    };
  }
  if (cat === 'PUMPS') {
    return { ...base, pump_code: g('si-pump-code') };
  }
  if (cat === 'HBR') {
    return {
      ...base,
      size: g('si-serial'),
      quantity: g('si-hbr-qty'),
      unit_of_measure: g('si-hbr-uom'),
      item_price: _canSeePrice ? g('si-hbr-price') : undefined,
    };
  }
  if (cat === 'BOLTS') {
    return {
      ...base,
      size: g('si-bolt-size'),
      size_type: g('si-bolt-type'),
      quantity: g('si-bolts-qty'),
      unit_of_measure: g('si-bolts-uom'),
      item_price: _canSeePrice ? g('si-bolts-price') : undefined,
    };
  }
  if (cat === 'CONSUMABLES') {
    return {
      ...base,
      quantity: g('si-cons-qty'),
      unit_of_measure: g('si-cons-uom'),
      item_price: _canSeePrice ? g('si-cons-price') : undefined,
    };
  }
  // Fallback — return base only
  return base;
}

function openAddStockModal(reload) {
  openModal('Add Stock Item', `
    ${stockFormFields()}
    <div class="form-group">
      <label class="form-label">Initial Quantity</label>
      <input class="form-control" id="si-qty" type="number" min="0" value="0" />
    </div>
    <div id="si-err" class="login-error"></div>
  `, async () => {
    const errEl = document.getElementById('si-err');
    errEl.classList.remove('visible');
    const data = collectStockForm();
    if (!data.item_name) { errEl.textContent = 'Item name is required.'; errEl.classList.add('visible'); return; }
    if (!data.stock_type_id) { errEl.textContent = 'Type is required.'; errEl.classList.add('visible'); return; }
    try {
      const res = await apiPost('create.php', { ...data, quantity: document.getElementById('si-qty').value });
      closeModal();
      showToast(`${res.stock_no} created.`, 'success');
      reload();
    } catch (err) { errEl.textContent = err.message; errEl.classList.add('visible'); }
  }, { confirmLabel: 'Add Item', confirmClass: 'btn-accent' });
  wireStockTypeToggle();
}

function openEditStockModal(item, reload) {
  openModal(`Edit ${item.stock_no} — ${item.item_name}`, `
    ${stockFormFields(item)}
    <hr style="border:none;border-top:1px solid var(--border);margin:.75rem 0">
    <div class="form-group">
      <label class="form-label">Receive Additional Stock</label>
      <input class="form-control" id="si-qty" type="number" min="0" value="0"
             placeholder="Current balance: ${item.balance}" />
      <div style="font-size:0.75rem;color:var(--text-muted);margin-top:.25rem">
        Enter qty to add to current balance of <strong>${item.balance}</strong>. Leave 0 for no change.
      </div>
    </div>
    <div id="si-err" class="login-error"></div>
  `, async () => {
    const errEl = document.getElementById('si-err');
    errEl.classList.remove('visible');
    const data = collectStockForm();
    if (!data.item_name) { errEl.textContent = 'Item name is required.'; errEl.classList.add('visible'); return; }
    try {
      await apiPost('update.php', {
        id: item.record_id, ...data,
        receive_qty: document.getElementById('si-qty').value
      });
      closeModal();
      showToast('Stock item updated.', 'success');
      reload();
    } catch (err) { errEl.textContent = err.message; errEl.classList.add('visible'); }
  }, { confirmLabel: 'Save', confirmClass: 'btn-primary' });
  wireStockTypeToggle();
}

// ═════════════════════════════════════════════════════════════════════════
// ASSIGN STOCK (BOOK OUT)
// ═════════════════════════════════════════════════════════════════════════
export async function initAssignStock(role) {
  _isAdmin = ['admin', 'dev', 'test', 'dispatch', 'workshop'].includes(role);
  const c = document.getElementById('view-content');
  c.innerHTML = `
  <div class="page-header"><div><h1>Assign Stock</h1></div></div>
  <div class="card">
    <div class="card-body" id="assign-body">
      <div class="page-loader"><div class="spinner"></div></div>
    </div>
  </div>`;

  await loadLookups();

  // Fetch stock for the item rows
  let allStock = [];
  try {
    const data = await apiFetch('list.php', {});
    allStock = data.stock || [];
  } catch { }

  const body = document.getElementById('assign-body');
  if (!body) return;

  let rowCount = 1;
  let teamRs = null;
  const rowSelects = {}; // track richSelect instances per row

  // Build stock items list for rich select
  const stockItems = allStock.map(s => ({
    value: s.stock_no,
    label: `${s.stock_no} — ${s.item_name}`,
    sub: [s.type_name, s.size, s.unit_of_measure].filter(Boolean).join(' · '),
    badge: `Bal: ${s.balance}`,
    badge2: +s.balance <= 0 ? 'OUT' : +s.balance <= 2 ? 'LOW' : '',
    _balance: s.balance,
    _type_id: s.stock_type_id,
  }));

  function makeRow(i) {
    return `
    <div id="row-${i}" style="border:1px solid var(--border-light);border-radius:var(--radius);
         padding:.85rem 1rem;margin-bottom:.5rem;background:var(--surface-2)">
      <div style="display:flex;gap:.75rem;align-items:flex-start;flex-wrap:wrap">
        <div style="flex:1;min-width:200px">
          <div class="form-label" style="margin-bottom:.3rem">Stock Item</div>
          <div id="row-rs-${i}"></div>
        </div>
        <div style="width:80px">
          <div class="form-label" style="margin-bottom:.3rem">Balance</div>
          <div id="row-bal-${i}" style="font-weight:700;color:var(--primary);padding:.6rem 0">—</div>
        </div>
        <div style="width:100px">
          <div class="form-label" style="margin-bottom:.3rem">Qty</div>
          <input class="form-control" id="row-qty-${i}" type="number" min="1" value="1" />
        </div>
        <div style="padding-top:1.6rem">
          <button class="btn btn-ghost btn-sm" onclick="
            document.getElementById('row-${i}').remove();
            delete window._rowSelects['${i}'];
          " style="color:var(--danger)">✕</button>
        </div>
      </div>
    </div>`;
  }

  // Use window to share rowSelects across onclick handlers
  window._rowSelects = rowSelects;

  function initRowSelect(i) {
    const rs = richSelect(`row-rs-${i}`, {
      placeholder: 'Search stock items…',
      items: stockItems,
      onSelect: (val, item) => {
        const balEl = document.getElementById(`row-bal-${i}`);
        const qtyEl = document.getElementById(`row-qty-${i}`);
        const bal = item?._balance ?? 0;
        if (balEl) {
          balEl.textContent = bal;
          balEl.style.color = +bal <= 0 ? 'var(--danger)' : +bal <= 2 ? 'var(--warning)' : 'var(--primary)';
        }
        // Set max on qty input and warn if out of stock
        if (qtyEl) {
          qtyEl.max = bal;
          if (+bal <= 0) {
            qtyEl.value = 0;
            qtyEl.disabled = true;
            qtyEl.style.borderColor = 'var(--danger)';
          } else {
            qtyEl.disabled = false;
            qtyEl.style.borderColor = '';
            if (parseInt(qtyEl.value) > bal) qtyEl.value = bal;
          }
        }
      },
    });
    // Live cap on qty change
    const qtyEl = document.getElementById(`row-qty-${i}`);
    qtyEl?.addEventListener('change', () => {
      const item = stockItems.find(s => s.value === rs.getValue());
      const bal = parseFloat(item?._balance || 0);
      if (bal <= 0) { qtyEl.value = 0; return; }
      if (parseInt(qtyEl.value) > bal) qtyEl.value = bal;
      if (parseInt(qtyEl.value) < 1) qtyEl.value = 1;
    });
    rowSelects[i] = rs;
  }

  body.innerHTML = `
    <div class="form-row" style="margin-bottom:1rem">
      <div class="form-group">
        <label class="form-label">Team <span style="color:var(--danger)">*</span></label>
        <div id="assign-team-rs"></div>
      </div>
      <div class="form-group">
        <label class="form-label">Booking Date <span style="color:var(--danger)">*</span></label>
        <input class="form-control" id="assign-date" type="datetime-local"
               value="${new Date().toISOString().slice(0, 16)}" />
      </div>
    </div>
    <div class="form-row" style="margin-bottom:1rem">
      <div class="form-group">
        <label class="form-label">Registration No</label>
        <input class="form-control" id="assign-reg" placeholder="Vehicle reg (optional)" />
      </div>
      <div class="form-group">
        <label class="form-label">Pump Code</label>
        <input class="form-control" id="assign-pump" placeholder="Pump code (optional)" />
      </div>
    </div>

    <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:.75rem">
      <div class="card-title">Stock Items</div>
      <button class="btn btn-ghost btn-sm" id="btn-add-row">+ Add Item</button>
    </div>

    <div id="assign-rows">${makeRow(1)}</div>

    <div id="assign-err" class="login-error" style="margin-bottom:.75rem"></div>
    <button class="btn btn-accent" id="btn-submit-assign" style="width:100%;padding:.75rem">
      Book Out Stock
    </button>`;

  teamRs = richSelect('assign-team-rs', { placeholder: 'Search teams…', items: teamItems(_teams) });
  initRowSelect(1);

  // Add item row
  document.getElementById('btn-add-row')?.addEventListener('click', () => {
    rowCount++;
    document.getElementById('assign-rows').insertAdjacentHTML('beforeend', makeRow(rowCount));
    initRowSelect(rowCount);
  });

  // Submit
  document.getElementById('btn-submit-assign')?.addEventListener('click', async () => {
    const errEl = document.getElementById('assign-err');
    errEl.classList.remove('visible');
    const teamId = teamRs?.getValue();
    const date = document.getElementById('assign-date')?.value;
    if (!teamId) { errEl.textContent = 'Please select a team.'; errEl.classList.add('visible'); return; }
    if (!date) { errEl.textContent = 'Booking date is required.'; errEl.classList.add('visible'); return; }

    const items = [];
    let validationError = '';

    Object.entries(rowSelects).forEach(([i, rs]) => {
      const rowEl = document.getElementById(`row-${i}`);
      if (!rowEl) return;
      const stockNo = rs.getValue();
      const qty = parseInt(document.getElementById(`row-qty-${i}`)?.value || 0);
      const stockItem = stockItems.find(s => s.value === stockNo);
      const balance = parseFloat(stockItem?._balance || 0);

      if (!stockNo || qty <= 0) return;

      // Prevent booking out of stock items
      if (balance <= 0) {
        validationError = `"${stockItem?.label || stockNo}" is out of stock (balance: ${balance}).`;
        return;
      }

      // Prevent booking more than available
      if (qty > balance) {
        validationError = `Cannot book ${qty} of "${stockItem?.label || stockNo}" — only ${balance} available.`;
        return;
      }

      items.push({
        stock_no: stockNo,
        quantity: qty,
        type_id: stockItem?._type_id || '',
        open_balance: balance,
        close_balance: balance - qty,
      });
    });

    if (validationError) { errEl.textContent = validationError; errEl.classList.add('visible'); return; }
    if (!items.length) { errEl.textContent = 'Add at least one stock item with a quantity.'; errEl.classList.add('visible'); return; }

    const btn = document.getElementById('btn-submit-assign');
    btn.disabled = true; btn.textContent = 'Booking…';

    try {
      const res = await apiPost('assign.php', {
        team_id: teamId,
        booking_date: date,
        registration_no: document.getElementById('assign-reg')?.value || '',
        pump_code: document.getElementById('assign-pump')?.value || '',
        items: JSON.stringify(items),
      });
      showToast(`Order ${res.order_no} booked successfully.`, 'success');
      navigate('stock-booked');
    } catch (err) {
      errEl.textContent = err.message; errEl.classList.add('visible');
      btn.disabled = false; btn.textContent = 'Book Out Stock';
    }
  });
}

// ═════════════════════════════════════════════════════════════════════════
// RETURN STOCK — open orders only
// ═════════════════════════════════════════════════════════════════════════
export async function initReturnStock(role) {
  _isAdmin = ['admin', 'dev', 'test', 'dispatch', 'workshop'].includes(role);
  const c = document.getElementById('view-content');
  c.innerHTML = `
  <div class="page-header">
    <div><h1>Return Stock</h1><div class="sub">Open bookings with outstanding items</div></div>
  </div>
  <div class="toolbar" style="margin-bottom:1rem">
    <div class="toolbar-filters">
      <input class="form-control" id="rs-search" placeholder="Search order, team, item…" style="width:240px" />
    </div>
  </div>
  <div id="return-wrap"><div class="page-loader"><div class="spinner"></div></div></div>`;

  let _openOrders = [];

  const render = () => {
    const q = (document.getElementById('rs-search')?.value || '').toLowerCase().trim();
    let filtered = _openOrders;
    if (q) {
      filtered = filtered.filter(o =>
        o.order_no.toLowerCase().includes(q) ||
        (o.team_name || '').toLowerCase().includes(q) ||
        o.items.some(i =>
          i.item_name.toLowerCase().includes(q) ||
          i.stock_no.toLowerCase().includes(q)
        )
      );
    }
    const wrap = document.getElementById('return-wrap');
    if (!wrap) return;
    if (!filtered.length) {
      wrap.innerHTML = `<div class="empty-state" style="padding:3rem"><p>No open orders match.</p></div>`;
      return;
    }
    wrap.innerHTML = filtered.map(o => renderBookedOrder(o, false)).join('');
    bindOrderButtons(wrap);
  };

  try {
    const all = await apiFetch('booked-list.php');
    _openOrders = all.filter(o => !o.fully_returned);
  } catch { }

  document.getElementById('rs-search')?.addEventListener('input', debounce(render, 250));
  render();
}

// ═════════════════════════════════════════════════════════════════════════
// BOOKED STOCK — all orders, collapsed, searchable
// ═════════════════════════════════════════════════════════════════════════
export async function initBookedStock(role) {
  _isAdmin = ['admin', 'dev', 'test', 'dispatch', 'workshop'].includes(role);
  _canSeePrice = ['admin', 'dispatch', 'dev', 'test'].includes(role);
  const c = document.getElementById('view-content');
  c.innerHTML = `
  <div class="page-header">
    <div><h1>Booked Stock</h1><div class="sub">All booking orders</div></div>
    ${_canSeePrice ? `<button class="btn btn-ghost btn-sm" id="btn-booking-report">📊 Reports</button>` : ''}
  </div>
  <div class="toolbar" style="margin-bottom:1rem">
    <div class="toolbar-filters">
      <input class="form-control" id="bs-search" placeholder="Search order, team, item…" style="width:240px" />
      <select class="form-control" id="bs-status" style="width:150px">
        <option value="open">Open Orders</option>
        <option value="closed">Closed Orders</option>
        <option value="">All Orders</option>
      </select>
    </div>
  </div>
  <div id="booked-wrap"><div class="page-loader"><div class="spinner"></div></div></div>`;

  let _allOrders = [];

  const render = () => {
    const q = (document.getElementById('bs-search')?.value || '').toLowerCase().trim();
    const status = document.getElementById('bs-status')?.value || '';
    let filtered = _allOrders;

    if (status === 'open') filtered = filtered.filter(o => !o.fully_returned);
    if (status === 'closed') filtered = filtered.filter(o => o.fully_returned);

    if (q) {
      filtered = filtered.filter(o =>
        o.order_no.toLowerCase().includes(q) ||
        (o.team_name || '').toLowerCase().includes(q) ||
        o.items.some(i =>
          i.item_name.toLowerCase().includes(q) ||
          i.stock_no.toLowerCase().includes(q)
        )
      );
    }

    const wrap = document.getElementById('booked-wrap');
    if (!wrap) return;
    if (!filtered.length) {
      wrap.innerHTML = `<div class="empty-state" style="padding:3rem"><p>No orders match your search.</p></div>`;
      return;
    }
    wrap.innerHTML = filtered.map(o => renderBookedOrder(o, true)).join('');
    bindOrderButtons(wrap);

    // Wire collapse toggles
    wrap.querySelectorAll('.bs-toggle').forEach(btn => {
      btn.addEventListener('click', () => {
        const card = btn.closest('.booked-card');
        const body = card?.querySelector('.booked-card-body');
        const isCollapsed = body?.style.display === 'none';
        if (body) body.style.display = isCollapsed ? '' : 'none';
        btn.textContent = isCollapsed ? '▲' : '▼';
      });
    });
  };

  // Load all orders once, filter client-side
  await loadLookups();
  try {
    _allOrders = await apiFetch('booked-list.php');
  } catch { }

  document.getElementById('bs-search')?.addEventListener('input', debounce(render, 250));
  document.getElementById('bs-status')?.addEventListener('change', render);
  document.getElementById('btn-booking-report')?.addEventListener('click', () => openBookingReportModal(_teams));

  render();
}

// ── Shared loader ─────────────────────────────────────────────────────────
async function loadOrdersInto(wrapId, { openOnly = false, collapsed = true } = {}) {
  const wrap = document.getElementById(wrapId);
  if (!wrap) return;
  wrap.innerHTML = `<div class="page-loader"><div class="spinner"></div></div>`;
  try {
    let orders = await apiFetch('booked-list.php');
    if (openOnly) orders = orders.filter(o => !o.fully_returned);
    if (!orders.length) {
      wrap.innerHTML = `<div class="empty-state" style="padding:3rem"><p>${openOnly ? 'No open stock orders.' : 'No booked orders.'}</p></div>`;
      return;
    }
    wrap.innerHTML = orders.map(o => renderBookedOrder(o, collapsed)).join('');
    bindOrderButtons(wrap);
  } catch (err) {
    wrap.innerHTML = `<div class="empty-state"><p>${err.message}</p></div>`;
  }
}

// Shared: keep reference so return/close can reload the correct view
function loadBookedStock() { loadOrdersInto('booked-wrap', { openOnly: false, collapsed: true }); }
function loadReturnStock() { loadOrdersInto('return-wrap', { openOnly: true, collapsed: false }); }

function bindOrderButtons(wrap) {
  wrap.querySelectorAll('.btn-return-line').forEach(btn => {
    btn.addEventListener('click', () => openLineReturnModal(
      JSON.parse(decodeURIComponent(btn.dataset.order)),
      JSON.parse(decodeURIComponent(btn.dataset.item))
    ));
  });
  wrap.querySelectorAll('.btn-close-order').forEach(btn => {
    btn.addEventListener('click', () => openCloseOrderModal(
      JSON.parse(decodeURIComponent(btn.dataset.order))
    ));
  });
}

function renderBookedOrder(order, collapsed = false) {
  const allDone = order.fully_returned;
  const statusBadge = allDone
    ? `<span class="badge badge-active">Closed</span>`
    : `<span class="badge badge-pending">Open</span>`;

  const rows = order.items.map(item => {
    const done = item.outstanding <= 0;
    return `<tr style="${done ? 'opacity:.6' : ''}">
      <td data-label="Stock No">${item.stock_no}</td>
      <td data-label="Item"><strong>${item.item_name}</strong></td>
      <td data-label="Booked">${item.amount}</td>
      <td data-label="Returned" style="color:var(--success)">${item.returned_qty}</td>
      <td data-label="Used" style="color:var(--warning)">${item.used_qty}</td>
      <td data-label="Outstanding">
        <strong style="color:${item.outstanding > 0 ? 'var(--danger)' : 'var(--success)'}">
          ${item.outstanding > 0 ? item.outstanding : '✓'}
        </strong>
      </td>
      <td data-label="">
        ${!done && !allDone
        ? `<button class="btn btn-ghost btn-sm btn-return-line"
               data-order="${encodeURIComponent(JSON.stringify(order))}"
               data-item="${encodeURIComponent(JSON.stringify(item))}">Return</button>`
        : ''}
      </td>
    </tr>`;
  }).join('');

  return `
  <div class="card booked-card" style="margin-bottom:.75rem">
    <div class="card-header" style="cursor:pointer" onclick="this.nextElementSibling.style.display=this.nextElementSibling.style.display==='none'?'':'none';this.querySelector('.bs-toggle').textContent=this.nextElementSibling.style.display===''?'▲':'▼'">
      <div>
        <span class="card-title">${order.order_no}</span>
        <span style="font-size:.8rem;color:var(--text-muted);margin-left:.5rem">${(order.booking_date || '').slice(0, 16)}</span>
      </div>
      <div style="display:flex;align-items:center;gap:.5rem;margin-left:auto" onclick="event.stopPropagation()">
        <span class="badge badge-navy">${order.team_name || '—'}</span>
        ${_canSeePrice && order.used_value > 0 ? `<span class="badge badge-orange" style="background:var(--accent);color:#fff">R ${(+order.used_value).toLocaleString('en-ZA', { minimumFractionDigits: 2 })} used</span>` : ''}
        ${statusBadge}
        ${!allDone
      ? `<button class="btn btn-danger btn-sm btn-close-order"
               data-order="${encodeURIComponent(JSON.stringify(order))}"
               style="background:var(--danger);color:#fff">Complete & Close</button>`
      : ''}
        <span class="bs-toggle" style="padding:.25rem .4rem;border-radius:4px;background:var(--surface-2);font-size:.75rem;cursor:pointer">${collapsed ? '▼' : '▲'}</span>
      </div>
    </div>
    <div class="booked-card-body" style="display:${collapsed ? 'none' : ''}">
      <div class="card-body" style="padding:0">
        <div class="table-wrap"><table>
          <thead><tr>
            <th>Stock No</th><th>Item</th><th>Booked</th>
            <th>Returned</th><th>Used</th><th>Outstanding</th><th></th>
          </tr></thead>
          <tbody>${rows}</tbody>
        </table></div>
      </div>
    </div>
  </div>`;
}

// ── Per-line return modal ─────────────────────────────────────────────────
function openLineReturnModal(order, item) {
  openModal(`Return — ${item.item_name}`, `
    <div style="background:var(--surface-2);border:1px solid var(--border);border-radius:var(--radius);
                padding:.75rem 1rem;margin-bottom:1rem;font-size:.875rem">
      <div><strong>Order:</strong> ${order.order_no} · <strong>Team:</strong> ${order.team_name}</div>
      <div style="margin-top:.25rem">
        <span style="margin-right:1rem">Booked: <strong>${item.amount}</strong></span>
        <span style="margin-right:1rem;color:var(--success)">Returned: <strong>${item.returned_qty}</strong></span>
        <span style="color:var(--warning)">Used: <strong>${item.used_qty}</strong></span>
      </div>
    </div>

    <div style="background:var(--info-bg);border:1px solid var(--info);border-radius:var(--radius);
                padding:.6rem .85rem;font-size:.8rem;margin-bottom:1rem;color:var(--info)">
      Outstanding: <strong>${item.outstanding}</strong> — Return + Used must equal <strong>${item.outstanding}</strong>
    </div>

    <input type="hidden" id="rl-sno"  value="${esc(item.stock_no)}" />
    <input type="hidden" id="rl-name" value="${esc(item.item_name)}" />
    <input type="hidden" id="rl-out"  value="${item.outstanding}" />

    <div class="form-row">
      <div class="form-group">
        <label class="form-label">Return Qty</label>
        <input class="form-control" id="rl-ret" type="number" min="0"
               max="${item.outstanding}" value="${item.outstanding}" />
      </div>
      <div class="form-group">
        <label class="form-label">Used Qty</label>
        <input class="form-control" id="rl-used" type="number" min="0"
               max="${item.outstanding}" value="0" />
      </div>
    </div>
    <div id="rl-total" style="font-size:.8rem;margin-top:.25rem;color:var(--success)">
      Total: ${item.outstanding} / ${item.outstanding} ✓
    </div>
    <div id="rl-err" class="login-error"></div>
  `, async () => {
    const errEl = document.getElementById('rl-err');
    errEl.classList.remove('visible');
    const retQty = parseInt(document.getElementById('rl-ret')?.value || 0);
    const usedQty = parseInt(document.getElementById('rl-used')?.value || 0);
    const total = retQty + usedQty;

    if (total !== item.outstanding) {
      errEl.textContent = `Return (${retQty}) + Used (${usedQty}) = ${total}, must equal ${item.outstanding}.`;
      errEl.classList.add('visible');
      return;
    }
    if (retQty < 0 || usedQty < 0) {
      errEl.textContent = 'Quantities cannot be negative.';
      errEl.classList.add('visible');
      return;
    }

    try {
      await apiPost('return.php', {
        order_no: order.order_no,
        items: JSON.stringify([{
          stock_no: item.stock_no,
          item_name: item.item_name,
          outstanding: item.outstanding,
          return_qty: retQty,
          used_qty: usedQty,
        }]),
      });
      closeModal();
      showToast(`${item.item_name} return saved.`, 'success');
      // Reload whichever page is visible
      if (document.getElementById('return-wrap')) loadReturnStock();
      else loadBookedStock();
    } catch (err) { errEl.textContent = err.message; errEl.classList.add('visible'); }
  }, { confirmLabel: 'Save Return', confirmClass: 'btn-primary' });

  // Live total display
  setTimeout(() => {
    ['rl-ret', 'rl-used'].forEach(id => {
      document.getElementById(id)?.addEventListener('input', () => {
        const out = parseInt(document.getElementById('rl-out')?.value || 0);
        const ret = parseInt(document.getElementById('rl-ret')?.value || 0);
        const used = parseInt(document.getElementById('rl-used')?.value || 0);
        const tot = ret + used;
        const el = document.getElementById('rl-total');
        if (!el) return;
        if (tot === out) {
          el.textContent = `Total: ${tot} / ${out} ✓`;
          el.style.color = 'var(--success)';
        } else if (tot > out) {
          el.textContent = `Total: ${tot} / ${out} — exceeds outstanding`;
          el.style.color = 'var(--danger)';
        } else {
          el.textContent = `Total: ${tot} / ${out} — ${out - tot} still unaccounted`;
          el.style.color = 'var(--warning)';
        }
      });
    });
  }, 100);
}

// ── Complete & Close order ────────────────────────────────────────────────
function openCloseOrderModal(order) {
  const outstanding = order.items.filter(i => i.outstanding > 0);
  const allAccountedFor = outstanding.length === 0;

  const confirmMsg = allAccountedFor
    ? `All items have been returned or used. This will close order <strong>${order.order_no}</strong>.`
    : `<span style="color:var(--danger)">
        ${outstanding.length} item(s) still have outstanding quantities.
        Closing will mark them all as <strong>USED</strong>:
       </span>
       <ul style="margin:.5rem 0 0 1rem;font-size:.85rem">
         ${outstanding.map(i => `<li>${i.item_name} — ${i.outstanding} outstanding</li>`).join('')}
       </ul>`;

  openModal(`Complete & Close — ${order.order_no}`, `
    <div style="background:${allAccountedFor ? 'var(--success-bg)' : 'var(--warning-bg)'};
                border:1px solid ${allAccountedFor ? 'var(--success)' : 'var(--warning)'};
                border-radius:var(--radius);padding:.85rem 1rem;margin-bottom:1rem;font-size:.875rem">
      ${confirmMsg}
    </div>
    <p style="font-size:.875rem;color:var(--text-muted)">
      This action cannot be undone. The order will be marked as <strong>Closed</strong>.
    </p>
    <div id="co-err" class="login-error"></div>
  `, async () => {
    const errEl = document.getElementById('co-err');
    errEl.classList.remove('visible');
    try {
      await apiPost('close-order.php', { order_no: order.order_no });
      closeModal();
      showToast(`Order ${order.order_no} closed.`, 'success');
      if (document.getElementById('return-wrap')) loadReturnStock();
      else loadBookedStock();
    } catch (err) { errEl.textContent = err.message; errEl.classList.add('visible'); }
  }, {
    confirmLabel: 'Yes, Close Order',
    confirmClass: allAccountedFor ? 'btn-primary' : 'btn-accent',
  });
}

// ═════════════════════════════════════════════════════════════════════════
// USED STOCK
// ═════════════════════════════════════════════════════════════════════════
export async function initUsedStock(role) {
  const c = document.getElementById('view-content');
  c.innerHTML = `
  <div class="page-header"><div><h1>Used Stock</h1></div></div>
  <div class="toolbar" style="margin-bottom:1rem">
    <div class="toolbar-filters">
      <select class="form-control" id="used-period" style="width:150px">
        <option value="today">Today</option>
        <option value="week">This Week</option>
        <option value="month" selected>This Month</option>
      </select>
    </div>
  </div>
  <div class="card" id="used-wrap">
    <div class="card-body" style="padding:0"><div class="page-loader"><div class="spinner"></div></div></div>
  </div>`;

  const load = async () => {
    const wrap = document.getElementById('used-wrap');
    if (!wrap) return;
    wrap.innerHTML = `<div class="card-body" style="padding:0"><div class="page-loader"><div class="spinner"></div></div></div>`;
    try {
      const data = await apiFetch('used.php', { period: document.getElementById('used-period')?.value || 'month' });
      const rows = data.rows || [];
      if (!rows.length) { wrap.innerHTML = `<div class="card-body"><div class="empty-state"><p>No used stock for this period.</p></div></div>`; return; }
      wrap.innerHTML = `<div class="card-body" style="padding:0"><div class="table-wrap"><table>
        <thead><tr><th>Date</th><th>Order</th><th>Team</th><th>Type</th><th>Stock No</th><th>Item</th><th>Qty</th></tr></thead>
        <tbody>
          ${rows.map(r => `<tr>
            <td data-label="Date" style="color:var(--text-muted);font-size:.8rem">${(r.datetime_created || '').slice(0, 16)}</td>
            <td data-label="Order">${r.order_no || '—'}</td>
            <td data-label="Team"><span class="badge badge-navy">${r.team_name || '—'}</span></td>
            <td data-label="Type" style="color:var(--text-muted)">${r.type_name || '—'}</td>
            <td data-label="Stock No">${r.stock_no}</td>
            <td data-label="Item"><strong>${r.item_name}</strong></td>
            <td data-label="Qty"><strong style="color:var(--accent)">${r.quantity}</strong></td>
          </tr>`).join('')}
        </tbody>
      </table></div></div>`;
    } catch (err) {
      wrap.innerHTML = `<div class="card-body"><div class="empty-state"><p>${err.message}</p></div></div>`;
    }
  };

  document.getElementById('used-period')?.addEventListener('change', load);
  await load();
}

// ── Booking Report Modal ──────────────────────────────────────────────────
function openBookingReportModal(teams) {
  const teamOpts = (teams || []).map(t =>
    `<option value="${t.record_id}">${t.name}</option>`
  ).join('');

  openModal('Booking Report', `
    <div class="form-row">
      <div class="form-group">
        <label class="form-label">Status</label>
        <select class="form-control" id="brpt-status">
          <option value="all">All Orders</option>
          <option value="open">Open Only</option>
          <option value="closed">Closed Only</option>
        </select>
      </div>
      <div class="form-group">
        <label class="form-label">Team</label>
        <select class="form-control" id="brpt-team">
          <option value="">All Teams</option>
          ${teamOpts}
        </select>
      </div>
    </div>
    <div class="form-row">
      <div class="form-group">
        <label class="form-label">Booking Date From</label>
        <input class="form-control" id="brpt-from" type="date" />
      </div>
      <div class="form-group">
        <label class="form-label">Booking Date To</label>
        <input class="form-control" id="brpt-to" type="date"
               value="${new Date().toISOString().slice(0, 10)}" />
      </div>
    </div>
    <div style="display:flex;gap:.75rem;flex-wrap:wrap;margin-top:.75rem">
      <button class="btn btn-primary" id="btn-brpt-pdf">⬇ Download PDF</button>
      <button class="btn btn-ghost"   id="btn-brpt-excel">⬇ Download Excel</button>
    </div>
    <div id="brpt-msg" style="font-size:.82rem;min-height:1.4rem;margin-top:.5rem"></div>
  `, closeModal, { confirmLabel: 'Close', confirmClass: 'btn-ghost' });

  setTimeout(() => {
    document.getElementById('modal-cancel-btn')?.remove();
    document.getElementById('btn-brpt-pdf')?.addEventListener('click', () => generateBookingReport('pdf'));
    document.getElementById('btn-brpt-excel')?.addEventListener('click', () => generateBookingReport('excel'));
  }, 50);
}

async function generateBookingReport(format) {
  const msg = document.getElementById('brpt-msg');
  if (msg) { msg.textContent = 'Fetching data…'; msg.style.color = 'var(--text-muted)'; }

  let data;
  try {
    data = await apiFetch('booking-report.php', {
      status: document.getElementById('brpt-status')?.value || 'all',
      team_id: document.getElementById('brpt-team')?.value || '',
      date_from: document.getElementById('brpt-from')?.value || '',
      date_to: document.getElementById('brpt-to')?.value || '',
    });
  } catch (err) {
    if (msg) { msg.textContent = 'Error: ' + err.message; msg.style.color = 'var(--danger)'; }
    return;
  }

  const orders = data.orders || [];
  const generated = data.generated || new Date().toLocaleString();
  const COMPANY = 'Savuki Drilling';
  const TITLE = 'Booking Report';

  if (msg) msg.textContent = `Generating ${format.toUpperCase()}…`;

  try {
    if (format === 'pdf') await generateBookingPDF({ orders, data, generated, COMPANY, TITLE });
    else await generateBookingExcel({ orders, data, generated, COMPANY, TITLE });
    if (msg) { msg.textContent = `✓ Downloaded — ${orders.length} orders`; msg.style.color = 'var(--success)'; }
  } catch (err) {
    console.error(err);
    if (msg) { msg.textContent = 'Export failed: ' + err.message; msg.style.color = 'var(--danger)'; }
  }
}

async function generateBookingPDF({ orders, data, generated, COMPANY, TITLE }) {
  await loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js', 'jspdf');
  await loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js', null);

  const jsPDFCtor = window.jspdf?.jsPDF || window.jsPDF;
  if (!jsPDFCtor) throw new Error('jsPDF failed to load.');
  const doc = new jsPDFCtor({ orientation: 'landscape', unit: 'mm', format: 'a4' });
  if (typeof doc.autoTable !== 'function') throw new Error('jsPDF-autoTable failed to load.');

  const NAVY = [40, 60, 140];
  const ORANGE = [240, 120, 40];
  const LIGHT = [245, 247, 250];
  const W = doc.internal.pageSize.getWidth();

  // Header
  doc.setFillColor(...NAVY);
  doc.rect(0, 0, W, 22, 'F');
  doc.setTextColor(255, 255, 255);
  doc.setFont('helvetica', 'bold'); doc.setFontSize(16);
  doc.text(COMPANY, 14, 10);
  doc.setFontSize(10); doc.setFont('helvetica', 'normal');
  doc.text(TITLE, 14, 16);
  doc.setFontSize(8);
  doc.text(`Generated: ${generated}`, W - 14, 10, { align: 'right' });

  // Summary strip
  doc.setFillColor(...LIGHT);
  doc.rect(0, 22, W, 10, 'F');
  doc.setTextColor(...NAVY); doc.setFont('helvetica', 'bold'); doc.setFontSize(9);
  doc.text(`Total Orders: ${data.total_orders}`, 14, 29);
  doc.text(`Total Used Value: R ${(+data.total_used_value).toLocaleString('en-ZA', { minimumFractionDigits: 2 })}`, 70, 29);

  // Flatten all line items across orders
  const head = [['Order No', 'Booking Date', 'Team', 'Stock No', 'Item', 'Booked', 'Returned', 'Used', 'Outstanding', 'Used Value (R)']];
  const body = [];

  for (const o of orders) {
    for (const item of o.items) {
      const uv = (+(item.item_price || 0) * +(item.used_qty || 0)).toFixed(2);
      body.push([
        o.order_no, (o.booking_date || '').slice(0, 10), o.team_name || '—',
        item.stock_no, item.item_name,
        item.amount, item.returned_qty, item.used_qty, item.outstanding,
        +uv > 0 ? uv : '—',
      ]);
    }
    // Sub-total row per order
    body.push(['', '', '', '', '', '', '', '', 'Used Total:', `R ${(+o.used_value).toFixed(2)}`]);
  }

  // Grand total
  body.push(['', '', '', '', '', '', '', '', 'GRAND TOTAL:', `R ${(+data.total_used_value).toFixed(2)}`]);

  doc.autoTable({
    head, body, startY: 35,
    theme: 'grid',
    styles: { fontSize: 7.5, cellPadding: 1.8, textColor: [30, 30, 30] },
    headStyles: { fillColor: NAVY, textColor: [255, 255, 255], fontStyle: 'bold' },
    alternateRowStyles: { fillColor: LIGHT },
    didParseCell(d) {
      // Sub-total rows
      const row = d.row.raw;
      if (row[3] === '' && row[9]?.startsWith('R ')) {
        d.cell.styles.fontStyle = 'bold';
        d.cell.styles.fillColor = [220, 225, 255];
      }
      // Grand total
      if (row[8] === 'GRAND TOTAL:') {
        d.cell.styles.fontStyle = 'bold';
        d.cell.styles.fillColor = [...ORANGE];
        d.cell.styles.textColor = [255, 255, 255];
      }
    },
    didDrawPage(d) {
      const n = doc.internal.getNumberOfPages();
      doc.setFontSize(7); doc.setTextColor(150);
      doc.text(`Page ${d.pageNumber} of ${n}  |  ${COMPANY} — Confidential`, W / 2, doc.internal.pageSize.getHeight() - 5, { align: 'center' });
    },
  });

  doc.save(`${COMPANY}_BookingReport_${new Date().toISOString().slice(0, 10)}.pdf`);
}

async function generateBookingExcel({ orders, data, generated, COMPANY, TITLE }) {
  await loadScript('https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js', 'XLSX');
  const XLSX = window.XLSX;
  if (!XLSX) throw new Error('SheetJS failed to load.');

  const wb = XLSX.utils.book_new();

  // Orders sheet
  const header = ['Order No', 'Booking Date', 'Team', 'Status', 'Stock No', 'Item', 'Booked', 'Returned', 'Used', 'Outstanding', 'Used Value (R)'];
  const rows = [];
  for (const o of orders) {
    for (const item of o.items) {
      const uv = +(item.item_price || 0) * +(item.used_qty || 0);
      rows.push([
        o.order_no, (o.booking_date || '').slice(0, 16), o.team_name || '—',
        o.fully_returned ? 'Closed' : 'Open',
        item.stock_no, item.item_name,
        +item.amount, +item.returned_qty, +item.used_qty, +item.outstanding,
        uv > 0 ? +uv.toFixed(2) : null,
      ]);
    }
    rows.push(['', '', '', '', '', 'Order Total', '', '', +o.items.reduce((s, i) => s + (+i.used_qty || 0), 0), '', +o.used_value || null]);
  }
  rows.push([]);
  rows.push(['', '', '', '', '', 'GRAND TOTAL', '', '', data.total_orders, '', +(data.total_used_value) || null]);

  const ws = XLSX.utils.aoa_to_sheet([
    [COMPANY], [TITLE], [`Generated: ${generated}`], [],
    header, ...rows,
  ]);
  ws['!cols'] = [12, 14, 18, 10, 12, 30, 9, 10, 9, 12, 14].map(w => ({ wch: w }));
  XLSX.utils.book_append_sheet(wb, ws, 'Bookings');

  // Summary sheet
  const summary = [
    [COMPANY], [TITLE], [`Generated: ${generated}`], [],
    ['Total Orders', data.total_orders],
    ['Total Used Value (R)', +(data.total_used_value || 0).toFixed(2)],
    ['Total Booked Value (R)', +(data.total_booked_value || 0).toFixed(2)],
    [], ['By Team'],
  ];
  const byTeam = {};
  orders.forEach(o => {
    if (!byTeam[o.team_name]) byTeam[o.team_name] = { orders: 0, used: 0 };
    byTeam[o.team_name].orders++;
    byTeam[o.team_name].used += +o.used_value || 0;
  });
  Object.entries(byTeam).forEach(([name, d]) => {
    summary.push([name, `${d.orders} orders`, `R ${d.used.toFixed(2)} used`]);
  });
  const wsSummary = XLSX.utils.aoa_to_sheet(summary);
  wsSummary['!cols'] = [{ wch: 22 }, { wch: 16 }, { wch: 22 }];
  XLSX.utils.book_append_sheet(wb, wsSummary, 'Summary');

  XLSX.writeFile(wb, `${COMPANY}_BookingReport_${new Date().toISOString().slice(0, 10)}.xlsx`);
}


function openReportModal() {
  const typeOpts = _types.map(t =>
    `<option value="${t.record_id}">${t.name}</option>`
  ).join('');

  openModal('Stock Report', `
    <div class="form-row">
      <div class="form-group">
        <label class="form-label">Stock Type</label>
        <select class="form-control" id="rpt-type">
          <option value="">All Types</option>
          ${typeOpts}
        </select>
      </div>
      <div class="form-group">
        <label class="form-label">Status</label>
        <select class="form-control" id="rpt-status">
          <option value="all">All Items</option>
          <option value="in_stock">In Stock Only</option>
          <option value="out_of_stock">Out of Stock Only</option>
          <option value="low_stock">Low Stock Only (≤2)</option>
        </select>
      </div>
    </div>
    <div class="form-row">
      <div class="form-group">
        <label class="form-label">Date Created From</label>
        <input class="form-control" id="rpt-from" type="date" />
      </div>
      <div class="form-group">
        <label class="form-label">Date Created To</label>
        <input class="form-control" id="rpt-to" type="date"
               value="${new Date().toISOString().slice(0, 10)}" />
      </div>
    </div>
    <div style="display:flex;gap:.75rem;flex-wrap:wrap;margin-top:.75rem">
      <button class="btn btn-primary" id="btn-rpt-pdf">⬇ Download PDF</button>
      <button class="btn btn-ghost"   id="btn-rpt-excel">⬇ Download Excel</button>
    </div>
    <div id="rpt-msg" style="font-size:.82rem;min-height:1.4rem;margin-top:.5rem"></div>
  `, closeModal, { confirmLabel: 'Close', confirmClass: 'btn-ghost' });

  // Hide the cancel button — only Close needed
  setTimeout(() => {
    document.getElementById('modal-cancel-btn')?.remove();
    document.getElementById('btn-rpt-pdf')?.addEventListener('click', () => generateReport('pdf'));
    document.getElementById('btn-rpt-excel')?.addEventListener('click', () => generateReport('excel'));
  }, 50);
}

// ═════════════════════════════════════════════════════════════════════════
// REPORT GENERATION
// ═════════════════════════════════════════════════════════════════════════
async function generateReport(format) {
  const statusMsg = document.getElementById('rpt-msg');
  if (statusMsg) { statusMsg.textContent = 'Fetching data…'; statusMsg.style.color = 'var(--text-muted)'; }

  let data;
  try {
    data = await apiFetch('report.php', {
      type_id: document.getElementById('rpt-type')?.value || '',
      status: document.getElementById('rpt-status')?.value || 'all',
      date_from: document.getElementById('rpt-from')?.value || '',
      date_to: document.getElementById('rpt-to')?.value || '',
    });
  } catch (err) {
    if (statusMsg) { statusMsg.textContent = 'Error: ' + err.message; statusMsg.style.color = 'var(--danger)'; }
    return;
  }

  const rows = data.rows || [];
  const totalValue = data.total_value || 0;
  const generated = data.generated || new Date().toLocaleString();
  const statusLabel = { all: 'All Items', in_stock: 'In Stock', out_of_stock: 'Out of Stock', low_stock: 'Low Stock' }[document.getElementById('rpt-status')?.value || 'all'];
  const typeName = document.getElementById('rpt-type')?.options[document.getElementById('rpt-type')?.selectedIndex]?.text || 'All Types';
  const dateFrom = document.getElementById('rpt-from')?.value || '—';
  const dateTo = document.getElementById('rpt-to')?.value || '—';

  const COMPANY = 'Savuki Drilling';
  const REPORT_TITLE = 'Stock Report';
  const ctx = { rows, totalValue, generated, statusLabel, typeName, dateFrom, dateTo, COMPANY, REPORT_TITLE };

  if (statusMsg) statusMsg.textContent = `Generating ${format.toUpperCase()}…`;

  try {
    if (format === 'pdf') await generatePDF(ctx);
    else await generateExcel(ctx);
    if (statusMsg) { statusMsg.textContent = `✓ Downloaded — ${rows.length} items`; statusMsg.style.color = 'var(--success)'; }
  } catch (err) {
    console.error(err);
    if (statusMsg) { statusMsg.textContent = 'Export failed: ' + err.message; statusMsg.style.color = 'var(--danger)'; }
  }
}

// ── PDF via jsPDF + autoTable ─────────────────────────────────────────────
async function generatePDF({ rows, totalValue, generated, statusLabel, typeName, dateFrom, dateTo, COMPANY, REPORT_TITLE }) {
  await loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js', 'jspdf');
  await loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js', null);

  // jsPDF UMD exposes via window.jspdf
  const jsPDFCtor = window.jspdf?.jsPDF || window.jsPDF;
  if (!jsPDFCtor) throw new Error('jsPDF failed to load. Please try again.');

  const doc = new jsPDFCtor({ orientation: 'landscape', unit: 'mm', format: 'a4' });

  const NAVY = [40, 60, 140];
  const ORANGE = [240, 120, 40];
  const LIGHT = [245, 247, 250];
  const W = doc.internal.pageSize.getWidth();

  // ── Header bar
  doc.setFillColor(...NAVY);
  doc.rect(0, 0, W, 22, 'F');
  doc.setTextColor(255, 255, 255);
  doc.setFont('helvetica', 'bold');
  doc.setFontSize(16);
  doc.text(COMPANY, 14, 10);
  doc.setFontSize(10);
  doc.setFont('helvetica', 'normal');
  doc.text(REPORT_TITLE, 14, 16);
  doc.setFontSize(8);
  doc.text(`Generated: ${generated}`, W - 14, 10, { align: 'right' });
  doc.text(`Status: ${statusLabel}  |  Type: ${typeName}  |  Date: ${dateFrom} – ${dateTo}`, W - 14, 16, { align: 'right' });

  // ── Summary strip
  doc.setFillColor(...LIGHT);
  doc.rect(0, 22, W, 10, 'F');
  doc.setTextColor(40, 60, 140);
  doc.setFont('helvetica', 'bold');
  doc.setFontSize(9);
  doc.text(`Total Items: ${rows.length}`, 14, 29);
  doc.text(`In Stock: ${rows.filter(r => +r.balance > 0).length}`, 55, 29);
  doc.text(`Out of Stock: ${rows.filter(r => +r.balance <= 0).length}`, 96, 29);
  if (_canSeePrice) doc.text(`Total Value: R ${(+totalValue).toLocaleString('en-ZA', { minimumFractionDigits: 2 })}`, 145, 29);

  // ── Table
  const head = _canSeePrice
    ? [['Stock No', 'Item Name', 'Type', 'Size', 'Supplier', 'UOM', 'Price (R)', 'Balance', 'Value (R)']]
    : [['Stock No', 'Item Name', 'Type', 'Size', 'Supplier', 'UOM', 'Balance']];

  const body = rows.map(r => {
    const bal = +r.balance;
    const base = [
      r.stock_no,
      r.item_name,
      r.type_name || '—',
      [r.type, r.size].filter(Boolean).join(' ') || '—',
      r.supplier_name || '—',
      r.unit_of_measure || '—',
    ];
    if (_canSeePrice) {
      const price = +r.item_price || 0;
      base.push(price ? price.toFixed(2) : '—');
      base.push(bal);
      base.push(price && bal > 0 ? (price * bal).toFixed(2) : '—');
    } else {
      base.push(bal);
    }
    return base;
  });

  // Totals row
  if (_canSeePrice) {
    body.push(['', 'TOTALS', '', '', '', '', '', rows.reduce((s, r) => s + (+r.balance || 0), 0), totalValue.toFixed(2)]);
  } else {
    body.push(['', 'TOTALS', '', '', '', '', rows.reduce((s, r) => s + (+r.balance || 0), 0)]);
  }

  if (typeof doc.autoTable !== 'function') throw new Error('jsPDF-autoTable failed to load. Please try again.');

  doc.autoTable({
    head,
    body,
    startY: 35,
    theme: 'grid',
    styles: { fontSize: 8, cellPadding: 2, textColor: [30, 30, 30] },
    headStyles: { fillColor: NAVY, textColor: [255, 255, 255], fontStyle: 'bold' },
    alternateRowStyles: { fillColor: LIGHT },
    footStyles: { fillColor: ORANGE, textColor: [255, 255, 255], fontStyle: 'bold' },
    didParseCell(data) {
      // Highlight out-of-stock rows
      if (data.section === 'body' && data.row.index < rows.length) {
        const bal = +rows[data.row.index]?.balance;
        if (bal <= 0) data.cell.styles.textColor = [180, 30, 30];
        else if (bal <= 2) data.cell.styles.textColor = [160, 100, 0];
      }
      // Bold totals row
      if (data.section === 'body' && data.row.index === rows.length) {
        data.cell.styles.fontStyle = 'bold';
        data.cell.styles.fillColor = [230, 235, 255];
      }
    },
    didDrawPage(data) {
      // Footer on each page
      const pageCount = doc.internal.getNumberOfPages();
      doc.setFontSize(7);
      doc.setTextColor(150);
      doc.text(`Page ${data.pageNumber} of ${pageCount}  |  ${COMPANY} — Confidential`, W / 2, doc.internal.pageSize.getHeight() - 5, { align: 'center' });
    },
  });

  doc.save(`${COMPANY}_StockReport_${new Date().toISOString().slice(0, 10)}.pdf`);
}

// ── Excel via SheetJS ─────────────────────────────────────────────────────
async function generateExcel({ rows, totalValue, generated, statusLabel, typeName, dateFrom, dateTo, COMPANY, REPORT_TITLE }) {
  await loadScript('https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js', 'XLSX');

  const XLSX = window.XLSX;
  if (!XLSX) throw new Error('SheetJS failed to load. Please try again.');
  const wb = XLSX.utils.book_new();

  // ── Build worksheet data
  const meta = [
    [COMPANY],
    [REPORT_TITLE],
    [`Generated: ${generated}`],
    [`Filter: ${statusLabel}  |  Type: ${typeName}  |  Date: ${dateFrom} – ${dateTo}`],
    [],
  ];

  const header = _canSeePrice
    ? ['Stock No', 'Item Name', 'Category', 'Type/Size', 'Supplier', 'Unit', 'Price (R)', 'Balance', 'Value (R)', 'Status', 'Date Created']
    : ['Stock No', 'Item Name', 'Category', 'Type/Size', 'Supplier', 'Unit', 'Balance', 'Status', 'Date Created'];

  const dataRows = rows.map(r => {
    const bal = +r.balance;
    const price = +r.item_price || 0;
    const status = bal <= 0 ? 'OUT OF STOCK' : bal <= 2 ? 'LOW STOCK' : 'IN STOCK';
    const base = [
      r.stock_no,
      r.item_name,
      r.type_name || '',
      [r.type, r.size].filter(Boolean).join(' ') || '',
      r.supplier_name || '',
      r.unit_of_measure || '',
    ];
    if (_canSeePrice) {
      base.push(price || null);
      base.push(bal);
      base.push(price && bal > 0 ? +(price * bal).toFixed(2) : null);
    } else {
      base.push(bal);
    }
    base.push(status);
    base.push((r.date_time || '').slice(0, 10));
    return base;
  });

  // Totals row
  const totalsRow = _canSeePrice
    ? ['', 'TOTALS', '', '', '', '', '', rows.reduce((s, r) => s + (+r.balance || 0), 0), +totalValue.toFixed(2), '', '']
    : ['', 'TOTALS', '', '', '', '', rows.reduce((s, r) => s + (+r.balance || 0), 0), '', ''];

  const wsData = [...meta, header, ...dataRows, [], totalsRow];
  const ws = XLSX.utils.aoa_to_sheet(wsData);

  // Column widths
  const colWidths = _canSeePrice
    ? [12, 32, 16, 16, 20, 8, 12, 10, 14, 14, 14]
    : [12, 32, 16, 16, 20, 8, 10, 14, 14];
  ws['!cols'] = colWidths.map(w => ({ wch: w }));

  XLSX.utils.book_append_sheet(wb, ws, 'Stock Report');

  // Summary sheet
  const summaryData = [
    ['STOCK REPORT SUMMARY'],
    [],
    ['Company', COMPANY],
    ['Report', REPORT_TITLE],
    ['Generated', generated],
    ['Filter', statusLabel],
    ['Type', typeName],
    ['Date From', dateFrom],
    ['Date To', dateTo],
    [],
    ['TOTALS'],
    ['Total Items', rows.length],
    ['In Stock', rows.filter(r => +r.balance > 0).length],
    ['Out of Stock', rows.filter(r => +r.balance <= 0).length],
    ['Low Stock', rows.filter(r => +r.balance > 0 && +r.balance <= 2).length],
    ..._canSeePrice ? [['Total Value (R)', +totalValue.toFixed(2)]] : [],
  ];
  const wsSummary = XLSX.utils.aoa_to_sheet(summaryData);
  wsSummary['!cols'] = [{ wch: 20 }, { wch: 30 }];
  XLSX.utils.book_append_sheet(wb, wsSummary, 'Summary');

  XLSX.writeFile(wb, `${COMPANY}_StockReport_${new Date().toISOString().slice(0, 10)}.xlsx`);
}

function loadScript(src, globalCheck) {
  return new Promise((resolve, reject) => {
    if (globalCheck && window[globalCheck]) { resolve(); return; }
    if (document.querySelector(`script[src="${src}"]`)) {
      // Script tag exists — wait for global
      if (!globalCheck) { resolve(); return; }
      let tries = 0;
      const poll = setInterval(() => {
        if (window[globalCheck] || ++tries > 40) { clearInterval(poll); resolve(); }
      }, 100);
      return;
    }
    const s = document.createElement('script');
    s.src = src;
    s.onload = () => {
      if (!globalCheck) { resolve(); return; }
      let tries = 0;
      const poll = setInterval(() => {
        if (window[globalCheck] || ++tries > 40) { clearInterval(poll); resolve(); }
      }, 100);
    };
    s.onerror = () => reject(new Error(`Failed to load ${src}`));
    document.head.appendChild(s);
  });
}

// ═════════════════════════════════════════════════════════════════════════
// Helpers
// ═════════════════════════════════════════════════════════════════════════
function bindShowMore(wrap) {
  wrap.querySelectorAll('.show-more-btn').forEach(btn => {
    btn.addEventListener('click', () => {
      const tbody = btn.closest('tbody');
      const hidden = tbody.querySelectorAll('tr.extra-row');
      const exp = btn.dataset.expanded === 'true';
      hidden.forEach(r => r.style.display = exp ? 'none' : '');
      btn.dataset.expanded = exp ? 'false' : 'true';
      btn.textContent = exp ? `Show all ${btn.dataset.total}` : 'Show less';
    });
  });
}

function esc(v) { return (v || '').toString().replace(/"/g, '&quot;').replace(/</g, '&lt;'); }
function debounce(fn, ms) { let t; return (...a) => { clearTimeout(t); t = setTimeout(() => fn(...a), ms); }; }