// ============================================================
// Inventory — warehouse stock (packed / unpacked) per SKU.
// Printing a label auto-deducts "packed" stock (see api/print.php); this
// screen is for opening balances, manual corrections, bulk CSV updates and
// a printable brand-wise reconciliation report.
// ============================================================
(function () {
  const { Icon, Badge, BrandDot, Btn, Field, Modal, fmtNum } = window;
  const { useState, useMemo, useRef, useEffect } = React;
  const SHEET_SYNC_INTERVAL_MS = 45000;

  // Quote-aware CSV parser (product names can contain commas) — same approach
  // as the Products CSV importer, so a "title" column here is safe to add
  // for readability without corrupting the sku/packed/unpacked columns.
  function parseCsv(text) {
    if (text.charCodeAt(0) === 0xFEFF) text = text.slice(1); // strip UTF-8 BOM if present
    const table = [];
    let row = [], field = '', inQuotes = false;
    for (let i = 0; i < text.length; i++) {
      const c = text[i];
      if (inQuotes) {
        if (c === '"') { if (text[i + 1] === '"') { field += '"'; i++; } else inQuotes = false; }
        else field += c;
      } else if (c === '"') inQuotes = true;
      else if (c === ',') { row.push(field); field = ''; }
      else if (c === '\n' || c === '\r') {
        if (c === '\r' && text[i + 1] === '\n') i++;
        row.push(field); field = '';
        if (row.some(f => f !== '')) table.push(row);
        row = [];
      } else field += c;
    }
    if (field !== '' || row.length) { row.push(field); if (row.some(f => f !== '')) table.push(row); }
    if (!table.length) return [];

    const header = table[0].map(h => h.trim().toLowerCase());
    const skuIdx = header.indexOf('sku');
    const packedIdx = header.findIndex(h => h === 'packed' || h === 'packed_change');
    const unpackedIdx = header.findIndex(h => h === 'unpacked' || h === 'unpacked_change');
    if (skuIdx === -1) return [];
    return table.slice(1).map(cols => ({
      sku: (cols[skuIdx] || '').trim(),
      packed: packedIdx > -1 ? (parseInt(cols[packedIdx], 10) || 0) : 0,
      unpacked: unpackedIdx > -1 ? (parseInt(cols[unpackedIdx], 10) || 0) : 0,
    })).filter(r => r.sku && (r.packed || r.unpacked));
  }

  function csvField(v) { return '"' + String(v == null ? '' : v).replace(/"/g, '""') + '"'; }

  function downloadCsv(lines, filename) {
    const blob = new Blob([String.fromCharCode(0xFEFF) + lines.join('\n')], { type: 'text/csv;charset=utf-8;' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob); a.download = filename; a.click();
  }

  function Inventory({ inventory, onSetInventory, onImportInventory, onLoadMoves, sheetUrl, onSaveSheetUrl, onSyncSheet, toast }) {
    const [q, setQ] = useState('');
    const [brand, setBrand] = useState('All');
    const [editing, setEditing] = useState(null);
    const [saving, setSaving] = useState(false);
    const [movesFor, setMovesFor] = useState(null);
    const [moves, setMoves] = useState([]);
    const [movesLoading, setMovesLoading] = useState(false);
    const [importBusy, setImportBusy] = useState(false);
    const fileRef = useRef(null);
    const [sheetUrlDraft, setSheetUrlDraft] = useState(sheetUrl || '');
    const [savingUrl, setSavingUrl] = useState(false);
    const [syncing, setSyncing] = useState(false);
    const [syncError, setSyncError] = useState(null);
    const [lastSynced, setLastSynced] = useState(null);

    const filtered = useMemo(() => inventory.filter(it =>
      (brand === 'All' || it.brand === brand) &&
      (!q || (it.title + it.sku).toLowerCase().includes(q.toLowerCase()))
    ), [inventory, brand, q]);

    const totals = filtered.reduce((s, it) => ({
      packed: s.packed + (+it.packed_qty || 0), unpacked: s.unpacked + (+it.unpacked_qty || 0)
    }), { packed: 0, unpacked: 0 });

    const brandGroups = useMemo(() => {
      const g = {};
      inventory.forEach(it => { (g[it.brand] = g[it.brand] || []).push(it); });
      return g;
    }, [inventory]);

    const openEdit = (it) => setEditing({ sku: it.sku, title: it.title, brand: it.brand, packed: String(it.packed_qty || 0), unpacked: String(it.unpacked_qty || 0), note: '' });

    const saveEdit = async () => {
      setSaving(true);
      try {
        await onSetInventory(editing.sku, +editing.packed || 0, +editing.unpacked || 0, editing.note);
        toast('Stock updated · ' + editing.sku);
        setEditing(null);
      } catch (e) { toast(e.message || 'Update failed', 'err'); }
      setSaving(false);
    };

    const openMoves = async (sku) => {
      setMovesFor(sku); setMoves([]); setMovesLoading(true);
      try { setMoves(await onLoadMoves(sku)); } catch (e) { toast(e.message || 'Could not load history', 'err'); }
      setMovesLoading(false);
    };

    const downloadTemplate = () => {
      // "title" is here purely so you can tell SKUs apart while filling the sheet
      // in Excel — it's ignored on import, only sku/packed_change/unpacked_change matter.
      const lines = ['sku,title,packed_change,unpacked_change'];
      inventory.forEach(it => lines.push([it.sku, csvField((it.title || '').replace(it.brand, '').trim()), 0, 0].join(',')));
      downloadCsv(lines, 'inventory-template.csv');
      toast('Template downloaded — fill in +in / -out and re-upload');
    };

    const exportCurrent = () => {
      const lines = ['sku,brand,title,packed,unpacked,total'];
      inventory.forEach(it => lines.push([it.sku, it.brand, csvField(it.title), it.packed_qty, it.unpacked_qty, (+it.packed_qty || 0) + (+it.unpacked_qty || 0)].join(',')));
      downloadCsv(lines, 'inventory-stock.csv');
    };

    const handleFile = async (e) => {
      const file = e.target.files[0];
      e.target.value = '';
      if (!file) return;
      const rows = parseCsv(await file.text());
      if (!rows.length) { toast('No valid rows found — expected columns: sku, packed_change, unpacked_change', 'err'); return; }
      setImportBusy(true);
      try {
        const r = await onImportInventory(rows);
        toast('Applied ' + fmtNum(r.rows || rows.length) + ' stock change' + ((r.rows || rows.length) === 1 ? '' : 's') + ' from ' + rows.length + ' row' + (rows.length === 1 ? '' : 's'));
      } catch (e) { toast(e.message || 'Import failed', 'err'); }
      setImportBusy(false);
    };

    const saveSheetUrl = async () => {
      setSavingUrl(true);
      try { await onSaveSheetUrl(sheetUrlDraft.trim()); toast('Sheet link saved'); }
      catch (e) { toast(e.message || 'Could not save the link', 'err'); }
      setSavingUrl(false);
    };

    // SET semantics, not add/subtract — the sheet's numbers are the true
    // current stock, so re-syncing unchanged rows is always a safe no-op
    // (that's what makes the 45s auto-poll below safe to leave running).
    const syncNow = async (silent) => {
      setSyncing(true); setSyncError(null);
      try {
        const r = await onSyncSheet();
        setLastSynced(new Date().toLocaleTimeString('en-IN'));
        if (!silent) toast(fmtNum(r.changed) + ' SKU' + (r.changed === 1 ? '' : 's') + ' updated · ' + fmtNum(r.unchanged) + ' already matched');
      } catch (e) {
        setSyncError(e.message || 'Sync failed');
        if (!silent) toast(e.message || 'Sync failed', 'err');
      }
      setSyncing(false);
    };

    // While this screen is open, keep pulling the sheet automatically — this
    // is the "near real-time" part; edits stop syncing the moment you leave
    // the screen (no server-side cron here), so hit "Sync now" for anything urgent.
    useEffect(() => {
      if (!sheetUrl) return;
      const iv = setInterval(() => syncNow(true), SHEET_SYNC_INTERVAL_MS);
      return () => clearInterval(iv);
    }, [sheetUrl]);

    return React.createElement('div', { className: 'screen' },
      React.createElement('div', { className: 'screen-head' },
        React.createElement('div', null,
          React.createElement('h1', null, 'Inventory'),
          React.createElement('p', { className: 'screen-sub' }, fmtNum(filtered.length), ' SKUs · ', React.createElement('b', { style: { color: 'var(--amber)' } }, fmtNum(totals.packed)), ' packed · ', React.createElement('b', null, fmtNum(totals.unpacked)), ' unpacked')
        ),
        React.createElement('div', { className: 'btn-row' },
          React.createElement('input', { type: 'file', accept: '.csv,text/csv', ref: fileRef, style: { display: 'none' }, onChange: handleFile }),
          React.createElement(Btn, { variant: 'ghost', icon: 'download', onClick: downloadTemplate }, 'CSV template'),
          React.createElement(Btn, { variant: 'ghost', icon: 'layers', onClick: () => fileRef.current && fileRef.current.click(), disabled: importBusy }, importBusy ? 'Importing…' : 'Import CSV'),
          React.createElement(Btn, { variant: 'ghost', icon: 'download', onClick: exportCurrent }, 'Export CSV'),
          React.createElement(Btn, { variant: 'primary', icon: 'print', onClick: () => window.print() }, 'Print report')
        )
      ),
      React.createElement('div', { className: 'panel sheet-sync-panel' },
        React.createElement('div', { className: 'panel-head' },
          React.createElement('h3', null, React.createElement(Icon, { name: 'refresh', size: 14, style: { marginRight: 6, verticalAlign: -2 } }), 'Google Sheet live sync'),
          React.createElement('span', { className: 'conn-pill ' + (sheetUrl ? 'on' : 'off') },
            React.createElement('span', { className: 'pulse-dot ' + (sheetUrl ? 'live' : 'off') }),
            sheetUrl ? ('Auto-syncing every ' + (SHEET_SYNC_INTERVAL_MS / 1000) + 's') : 'Not linked')
        ),
        React.createElement('div', { className: 'sheet-sync-row' },
          React.createElement('input', { className: 'input mono sm', value: sheetUrlDraft, onChange: e => setSheetUrlDraft(e.target.value), placeholder: 'Paste Google Sheet share link…' }),
          React.createElement(Btn, { size: 'sm', icon: 'check', onClick: saveSheetUrl, disabled: savingUrl || sheetUrlDraft.trim() === (sheetUrl || '') }, savingUrl ? 'Saving…' : 'Save link'),
          React.createElement(Btn, { variant: 'primary', size: 'sm', icon: 'refresh', onClick: () => syncNow(false), disabled: syncing || !sheetUrl }, syncing ? 'Syncing…' : 'Sync now')
        ),
        lastSynced && !syncError && React.createElement('div', { className: 'test-result ok' }, React.createElement(Icon, { name: 'check', size: 15, stroke: 2.2 }), React.createElement('span', null, 'Last synced ', lastSynced)),
        syncError && React.createElement('div', { className: 'test-result bad' }, React.createElement(Icon, { name: 'alert', size: 15, stroke: 2.2 }), React.createElement('span', null, syncError)),
        React.createElement('div', { className: 'hint-box' },
          React.createElement('b', null, 'How: '),
          'Make a Google Sheet with columns ', React.createElement('code', { className: 'mono' }, 'sku, packed, unpacked'),
          ' — one row per SKU, each number is the true current stock count (not a change). Share it as "Anyone with the link — Viewer" (or File → Share → Publish to web), paste the link above and Save. While this screen stays open it re-syncs automatically; "Sync now" pulls it immediately.')
      ),
      React.createElement('div', { className: 'toolbar' },
        React.createElement('div', { className: 'search' },
          React.createElement(Icon, { name: 'search', size: 17, color: 'var(--txt-mut)' }),
          React.createElement('input', { value: q, onChange: e => setQ(e.target.value), placeholder: 'Search SKU, product…' })
        ),
        React.createElement('div', { className: 'seg' },
          ['All', 'LUXURIATE', 'VITMINVEDA'].map(b => React.createElement('button', { key: b, className: 'seg-btn' + (brand === b ? ' on' : ''), onClick: () => setBrand(b) }, b !== 'All' && React.createElement(BrandDot, { brand: b }), b === 'All' ? 'All' : b === 'LUXURIATE' ? 'LUX' : 'VMV'))
        )
      ),
      React.createElement('div', { className: 'panel table-panel' },
        React.createElement('div', { className: 'table inv' },
          React.createElement('div', { className: 'tr th' },
            React.createElement('span', null, 'Product'),
            React.createElement('span', { className: 'mono-h' }, 'SKU'),
            React.createElement('span', null, 'Packed'),
            React.createElement('span', null, 'Unpacked'),
            React.createElement('span', null, 'Total'),
            React.createElement('span', null, 'Updated'),
            React.createElement('span', null, '')
          ),
          filtered.length === 0 && React.createElement('div', { className: 'empty' }, React.createElement(Icon, { name: 'layers', size: 28, color: 'var(--txt-mut)' }), React.createElement('p', null, 'No products match')),
          filtered.map(it => {
            const total = (+it.packed_qty || 0) + (+it.unpacked_qty || 0);
            return React.createElement('div', { key: it.sku, className: 'tr' },
              React.createElement('span', { className: 'h-prod' }, React.createElement(BrandDot, { brand: it.brand, size: 9 }), React.createElement('div', null, React.createElement('b', null, (it.title || '').replace(it.brand, '').trim()))),
              React.createElement('span', { className: 'mono c-sku' }, it.sku),
              React.createElement('span', { className: 'mono' + ((+it.packed_qty || 0) < 0 ? ' inv-neg' : '') }, fmtNum(+it.packed_qty || 0)),
              React.createElement('span', { className: 'mono' }, fmtNum(+it.unpacked_qty || 0)),
              React.createElement('span', null, React.createElement('b', { className: 'qty-pill' }, fmtNum(total))),
              React.createElement('span', { className: 'h-op' }, it.updated_at ? it.updated_at.slice(0, 10) : '—'),
              React.createElement('span', { className: 'c-act' },
                React.createElement('button', { className: 'icon-btn-sm', title: 'Movement history', onClick: () => openMoves(it.sku) }, React.createElement(Icon, { name: 'history', size: 15 })),
                React.createElement('button', { className: 'icon-btn-sm', title: 'Edit stock', onClick: () => openEdit(it) }, React.createElement(Icon, { name: 'edit', size: 15 }))
              )
            );
          })
        )
      ),

      React.createElement(Modal, {
        open: !!editing, onClose: () => !saving && setEditing(null), title: editing ? 'Edit stock · ' + editing.sku : '',
        footer: React.createElement(React.Fragment, null,
          React.createElement(Btn, { variant: 'ghost', onClick: () => setEditing(null), disabled: saving }, 'Cancel'),
          React.createElement(Btn, { variant: 'primary', icon: 'check', onClick: saveEdit, disabled: saving }, saving ? 'Saving…' : 'Save')
        )
      }, editing && React.createElement('div', { className: 'editor-fields' },
        React.createElement('p', { className: 'confirm-txt' }, (editing.title || '').replace(editing.brand, '').trim()),
        React.createElement('div', { className: 'frow' },
          React.createElement(Field, { label: 'Packed qty' }, React.createElement('input', { className: 'input mono', value: editing.packed, onChange: e => setEditing(o => ({ ...o, packed: e.target.value.replace(/[^\d-]/g, '') })) })),
          React.createElement(Field, { label: 'Unpacked qty' }, React.createElement('input', { className: 'input mono', value: editing.unpacked, onChange: e => setEditing(o => ({ ...o, unpacked: e.target.value.replace(/[^\d-]/g, '') })) }))
        ),
        React.createElement(Field, { label: 'Note (optional)', hint: 'Why the count changed — e.g. "physical recount", "opening stock"' },
          React.createElement('input', { className: 'input', value: editing.note, onChange: e => setEditing(o => ({ ...o, note: e.target.value })) }))
      )),

      React.createElement(Modal, { open: !!movesFor, onClose: () => setMovesFor(null), title: 'Movement history · ' + movesFor, width: 620 },
        movesLoading ? React.createElement('div', { className: 'mini-empty' }, 'Loading…')
          : moves.length === 0 ? React.createElement('div', { className: 'mini-empty' }, 'No stock movements yet')
            : React.createElement('div', { className: 'moves-list' },
              moves.map(m => React.createElement('div', { key: m.id, className: 'move-row' },
                React.createElement('span', { className: 'move-when' }, (m.created_at || '').replace('T', ' ').slice(0, 16)),
                React.createElement('span', { className: 'move-pool' }, m.pool),
                React.createElement('span', { className: 'mono move-delta' + (+m.delta < 0 ? ' neg' : ' pos') }, (+m.delta > 0 ? '+' : ''), m.delta),
                React.createElement('span', { className: 'move-reason' }, m.reason, m.channel ? ' · ' + m.channel : ''),
                React.createElement('span', { className: 'move-note' }, m.note || m.user_name || '')
              ))
            )
      ),

      // Print-only brand-wise reconciliation report (see @media print rules) —
      // hidden on screen, becomes the whole page when "Print report" is used.
      React.createElement('div', { className: 'inv-report' },
        React.createElement('h1', null, 'Inventory Reconciliation Report'),
        React.createElement('p', { className: 'report-meta' }, 'Generated ', new Date().toLocaleString('en-IN')),
        Object.keys(brandGroups).sort().map(b => {
          const rows = brandGroups[b];
          const pTot = rows.reduce((s, it) => s + (+it.packed_qty || 0), 0);
          const uTot = rows.reduce((s, it) => s + (+it.unpacked_qty || 0), 0);
          return React.createElement('div', { key: b, className: 'report-brand' },
            React.createElement('h2', null, b),
            React.createElement('table', { className: 'report-table' },
              React.createElement('thead', null, React.createElement('tr', null,
                ['SKU', 'Product', 'Packed', 'Unpacked', 'Total'].map(h => React.createElement('th', { key: h }, h)))),
              React.createElement('tbody', null,
                rows.map(it => React.createElement('tr', { key: it.sku },
                  React.createElement('td', null, it.sku),
                  React.createElement('td', null, (it.title || '').replace(it.brand, '').trim()),
                  React.createElement('td', null, it.packed_qty),
                  React.createElement('td', null, it.unpacked_qty),
                  React.createElement('td', null, (+it.packed_qty || 0) + (+it.unpacked_qty || 0))
                )),
                React.createElement('tr', { className: 'report-total-row' },
                  React.createElement('td', { colSpan: 2 }, 'Brand total'),
                  React.createElement('td', null, pTot),
                  React.createElement('td', null, uTot),
                  React.createElement('td', null, pTot + uTot)
                )
              )
            )
          );
        })
      )
    );
  }

  Object.assign(window, { Inventory });
})();
