/* global window */
// Shared API client. Same-origin: backend serves these HTML files,
// so cookies (Better Auth session) flow naturally without CORS.

const BASE = '';

async function request(path, opts = {}) {
  const res = await fetch(BASE + path, {
    credentials: 'include',
    ...opts,
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      ...(opts.headers || {}),
    },
    body: opts.body && typeof opts.body !== 'string'
      ? JSON.stringify(opts.body)
      : opts.body,
  });
  const text = await res.text();
  let body;
  try { body = text ? JSON.parse(text) : null; } catch { body = text; }
  if (!res.ok) {
    const err = new Error(
      (body && (body.error || body.message)) || `HTTP ${res.status}`
    );
    err.status = res.status;
    err.body = body;
    throw err;
  }
  return body;
}

const Api = {
  request,
  get: (p) => request(p),
  post: (p, body) => request(p, { method: 'POST', body }),
  patch: (p, body) => request(p, { method: 'PATCH', body }),
  del: (p) => request(p, { method: 'DELETE' }),

  auth: {
    me: () => request('/api/auth/get-session'),
    signIn: (email, password) =>
      request('/api/auth/sign-in/email', {
        method: 'POST',
        body: { email, password },
      }),
    signUp: (payload) =>
      request('/api/auth/sign-up/email', { method: 'POST', body: payload }),
    signOut: () => request('/api/auth/sign-out', { method: 'POST', body: {} }),
  },
};

window.Api = Api;

// =====================================================================
// Transforms: API response shapes -> shapes the existing components
// expect via window.MOCK (compat layer).
// =====================================================================

function fmtRelative(iso) {
  if (!iso) return '—';
  const ms = Date.now() - new Date(iso).getTime();
  const min = Math.round(ms / 60000);
  if (min < 1) return 'baru saja';
  if (min < 60) return `${min} mnt lalu`;
  const h = Math.round(min / 60);
  if (h < 24) return `${h} jam lalu`;
  if (h < 48) return 'kemarin';
  const d = Math.round(h / 24);
  return `${d} hari lalu`;
}

function fmtDateShort(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  const m = ['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agu','Sep','Okt','Nov','Des'];
  return `${d.getDate()} ${m[d.getMonth()]} ${d.getFullYear()}`;
}

function transformOrder(o) {
  const itemsCount = (o.items || []).reduce((s, i) => s + (i.qty || 0), 0);
  return {
    id: o.id,
    mp: o.source,
    buyer: o.buyerName,
    items: itemsCount || 1,
    total: Number(o.totalAmount),
    status: o.status,
    date: fmtRelative(o.createdAt),
    sla: '—',
    sku: o.items?.[0]?.sku || '—',
    store: o.store?.name || '—',
    _raw: o,
  };
}

function transformProductWithInventory(invRow) {
  return {
    sku: invRow.sku,
    name: invRow.name,
    cat: invRow.category,
    stock: invRow.physicalStock,
    locked: invRow.lockedStock,
    price: Number(invRow.price),
    cogs: Number(invRow.cogs),
    matCost: Number(invRow.matCost),
    sold30: invRow.sold30,
    mps: [],
    low: invRow.physicalStock > 0 && invRow.physicalStock <= 10,
    oos: invRow.physicalStock <= 0,
    productId: invRow.productId,
    warehouseId: invRow.warehouseId,
  };
}

function transformMaterial(m) {
  return {
    id: m.id,
    sku: m.sku,
    name: m.name,
    unit: m.unit,
    stock: m.stock,
    reorder: m.reorder,
    cost: Number(m.cost),
    vendor: m.vendor || '—',
    used30: m.used30,
    lastIn: fmtRelative(m.lastInAt),
    lastInAt: m.lastInAt,
    low: m.stock <= m.reorder,
  };
}

function transformMatPo(po) {
  return {
    id: po.id,
    date: fmtDateShort(po.poDate),
    poDate: po.poDate,
    dueDate: po.dueDate,
    vendor: po.vendor,
    items: (po.items || []).length,
    total: Number(po.totalAmount),
    status: po.status === 'in_transit' ? 'in-transit' : po.status,
    paid: po.paid,
    due: po.dueDate ? fmtDateShort(po.dueDate) : '—',
  };
}

function transformInbound(inb) {
  const dateLabel = inb.receivedAt
    ? fmtRelative(inb.receivedAt)
    : inb.scheduledAt
      ? `Dijadwalkan · ${fmtDateShort(inb.scheduledAt)}`
      : '—';
  // server status: scheduled | receiving | matched | diff
  // mock UI uses: ok (matched) | diff | scheduled | receiving
  const statusMap = { matched: 'ok', diff: 'diff', scheduled: 'scheduled', receiving: 'receiving' };
  return {
    id: inb.id,
    date: dateLabel,
    warehouse: inb.warehouse?.name || '—',
    courier: inb.courier || '—',
    suratJalan: inb.suratJalan || '—',
    expected: inb.expectedTotal,
    received: inb.receivedTotal,
    status: statusMap[inb.status] || inb.status,
    items: (inb.items || []).map(it => ({
      sku: it.sku,
      name: it.name,
      expected: it.expected,
      received: it.received,
      diff: it.received - it.expected,
      note: it.diffNote,
    })),
    _raw: inb,
  };
}

function transformStore(s) {
  return {
    id: s.id,
    name: s.name,
    mp: s.marketplace,
    status: s.status,
    products: 0,
    orders30: 0,
    lastSync: s.lastSyncAt ? fmtRelative(s.lastSyncAt) : 'belum sinkron',
    warn: s.warning || undefined,
  };
}

function transformReturn(r) {
  return {
    id: r.id,
    order: r.orderId || '—',
    buyer: r.buyerName || '—',
    item: r.itemName || '—',
    reason: r.reason || '—',
    status: r.status,
    amount: Number(r.amount || 0),
    mp: r.source || 'manual',
    _raw: r,
  };
}

/**
 * Boot: confirm session, fetch core data, populate window.MOCK in place
 * so the existing components keep reading MOCK.X but get real data.
 */
async function loadAppData() {
  // session gate
  let session;
  try {
    session = await Api.auth.me();
  } catch (e) {
    if (e.status === 401 || !session) {
      window.location.href = 'login.html';
      throw new Error('unauthenticated');
    }
    throw e;
  }
  if (!session || !session.user) {
    window.location.href = 'login.html';
    throw new Error('unauthenticated');
  }
  window.__user = session.user;

  const [orders, inventory, materials, mpos, stores, returns, dashboard, opname, inboundResp] =
    await Promise.all([
      Api.get('/api/orders').catch(() => ({ data: [] })),
      Api.get('/api/inventory').catch(() => ({ data: [] })),
      Api.get('/api/materials').catch(() => ({ data: [] })),
      Api.get('/api/materials/po/list').catch(() => ({ data: [] })),
      Api.get('/api/stores').catch(() => ({ data: [] })),
      Api.get('/api/returns').catch(() => ({ data: [] })),
      Api.get('/api/dashboard').catch(() => ({ data: null })),
      Api.get('/api/stock-opname').catch(() => ({ data: [] })),
      Api.get('/api/inbound').catch(() => ({ data: [] })),
    ]);

  // Mutate the existing window.MOCK arrays in place so any reference held
  // elsewhere stays valid; if MOCK is missing yet, create it.
  const M = (window.MOCK = window.MOCK || {
    ORDERS: [], PRODUCTS: [], STORES: [], RETURNS: [], MATERIALS: [], MAT_POS: [], STOCK_OPNAME: [], INBOUND: [],
  });
  if (!M.STOCK_OPNAME) M.STOCK_OPNAME = [];
  if (!M.INBOUND) M.INBOUND = [];
  const replace = (arr, items) => {
    arr.length = 0;
    items.forEach((it) => arr.push(it));
  };
  replace(M.ORDERS, (orders.data || []).map(transformOrder));
  replace(M.PRODUCTS, (inventory.data || []).map(transformProductWithInventory));
  replace(M.MATERIALS, (materials.data || []).map(transformMaterial));
  replace(M.MAT_POS, (mpos.data || []).map(transformMatPo));
  replace(M.STORES, (stores.data || []).map(transformStore));
  replace(M.RETURNS, (returns.data || []).map(transformReturn));
  replace(M.STOCK_OPNAME, opname.data || []);
  replace(M.INBOUND, (inboundResp.data || []).map(transformInbound));
  window.__dashboard = dashboard?.data;
  window.__user = session.user;
  return session.user;
}

window.Api.loadAppData = loadAppData;

// =====================================================================
// Date Range Filter — Notion-style popover.
// Two trigger buttons ("Tanggal mulai" / "Sampai dengan"). Clicking opens
// a popover with a shortcut list on the left and a month calendar on the
// right. onChange({ from, to }) — each side is YYYY-MM-DD or ''.
// =====================================================================

const ID_DAY_SHORT = ['Min','Sen','Sel','Rab','Kam','Jum','Sab'];
const ID_MONTH_SHORT = ['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agu','Sep','Okt','Nov','Des'];
const ID_MONTH_LONG = ['Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'];

function _toISO(d) {
  if (!d) return '';
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const dd = String(d.getDate()).padStart(2, '0');
  return `${y}-${m}-${dd}`;
}
function _parseISO(iso) {
  if (!iso) return null;
  const [y, m, d] = iso.split('-').map(Number);
  return new Date(y, m - 1, d);
}
function _fmtBtn(iso) {
  if (!iso) return '';
  const d = _parseISO(iso);
  return `${d.getDate()} ${ID_MONTH_SHORT[d.getMonth()]} ${d.getFullYear()}`;
}

function inRange(iso, from, to) {
  if (!iso) return true;
  const d = (typeof iso === 'string' ? iso : new Date(iso).toISOString()).slice(0, 10);
  if (from && d < from) return false;
  if (to && d > to) return false;
  return true;
}

function DateRangeFilter({ from, to, onChange }) {
  const [open, setOpen] = React.useState(null); // 'start' | 'due' | null
  const wrapRef = React.useRef(null);

  React.useEffect(() => {
    if (!open) return;
    const onDoc = (e) => {
      if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(null);
    };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  const select = (iso) => {
    if (open === 'start') {
      const newFrom = iso;
      const newTo = to && newFrom > to ? newFrom : (to || '');
      onChange({ from: newFrom, to: newTo });
    } else if (open === 'due') {
      const newTo = iso;
      const newFrom = from && newTo < from ? newTo : (from || '');
      onChange({ from: newFrom, to: newTo });
    }
    setOpen(null);
  };

  const clearSide = (side) => {
    if (side === 'start') onChange({ from: '', to: to || '' });
    else onChange({ from: from || '', to: '' });
    setOpen(null);
  };

  const active = from || to;

  return (
    <div ref={wrapRef} style={{ position:'relative', display:'inline-flex', gap:6, alignItems:'center' }}>
      <DateButton
        value={from}
        placeholder="Tanggal mulai"
        active={open === 'start'}
        highlighted={!!from}
        onClick={() => setOpen(open === 'start' ? null : 'start')}
      />
      <DateButton
        value={to}
        placeholder="Sampai dengan"
        active={open === 'due'}
        highlighted={!!to}
        onClick={() => setOpen(open === 'due' ? null : 'due')}
      />
      {active && (
        <button
          type="button"
          onClick={() => onChange({ from:'', to:'' })}
          title="Hapus filter tanggal"
          style={{
            border:'none', background:'transparent', cursor:'pointer',
            color:'var(--ink-500, #888)', padding:'4px 6px', fontSize:13,
          }}
        >×</button>
      )}

      {open && (
        <DatePopover
          side={open}
          initial={open === 'start' ? from : to}
          onSelect={select}
          onClear={() => clearSide(open)}
        />
      )}
    </div>
  );
}

function DateButton({ value, placeholder, active, highlighted, onClick }) {
  // Compensate for the 2px focused border so the layout doesn't jump on focus.
  const padX = active ? 13 : 14;
  const padY = active ? 7 : 8;
  return (
    <button
      type="button"
      onClick={onClick}
      style={{
        display:'inline-flex', alignItems:'center', gap:8,
        padding:`${padY}px ${padX}px`,
        border: active
          ? '2px solid var(--brand-500, #ed3a1a)'
          : '1px solid var(--border, #e5e5e5)',
        borderRadius: 10,
        background: highlighted
          ? 'var(--brand-50, #fef0ed)'
          : active
            ? 'var(--brand-50, #fef0ed)'
            : 'white',
        cursor:'pointer',
        fontSize:13, fontFamily:'inherit',
        color: value ? 'var(--brand-700, #a82210)' : 'var(--ink-500, #888)',
        fontWeight: value ? 600 : 500,
        minWidth: 160, textAlign:'left',
        boxShadow: active ? '0 0 0 4px rgba(237, 58, 26, 0.08)' : 'none',
        transition:'all .12s',
      }}
    >
      <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
        style={{
          opacity: highlighted || active ? 0.85 : 0.5,
          color: highlighted || active ? 'var(--brand-500, #ed3a1a)' : 'currentColor',
          flexShrink:0,
        }}>
        <rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/>
      </svg>
      <span style={{ flex:1 }}>{value ? _fmtBtn(value) : placeholder}</span>
    </button>
  );
}

function DatePopover({ side, initial, onSelect, onClear }) {
  const today = new Date(); today.setHours(0,0,0,0);
  const initialDate = _parseISO(initial) || today;

  const [view, setView] = React.useState(() => new Date(initialDate.getFullYear(), initialDate.getMonth(), 1));

  const monthLabel = `${ID_MONTH_LONG[view.getMonth()]} ${view.getFullYear()}`;

  // Build 6-week grid starting Sunday.
  const firstOfMonth = new Date(view.getFullYear(), view.getMonth(), 1);
  const startSunday = new Date(firstOfMonth);
  startSunday.setDate(firstOfMonth.getDate() - firstOfMonth.getDay());
  const grid = Array.from({ length: 42 }, (_, i) => {
    const d = new Date(startSunday);
    d.setDate(startSunday.getDate() + i);
    return d;
  });

  const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1);
  const offset = (n) => { const d = new Date(today); d.setDate(today.getDate() + n); return d; };
  const nextMon = (() => { const d = new Date(today); const diff = ((1 + 7 - d.getDay()) % 7) || 7; d.setDate(d.getDate() + diff); return d; })();
  const nextSat = (() => { const d = new Date(today); const diff = ((6 + 7 - d.getDay()) % 7) || 7; d.setDate(d.getDate() + diff); return d; })();

  const fmtSh = (d) => `${d.getDate()} ${ID_MONTH_SHORT[d.getMonth()]}`;
  const fmtClk = () => {
    const d = new Date();
    return `${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
  };

  const shortcuts = [
    { label: 'Hari ini',     iso: _toISO(today),     hint: ID_DAY_SHORT[today.getDay()] },
    { label: 'Nanti',        iso: _toISO(today),     hint: fmtClk() },
    { label: 'Besok',        iso: _toISO(tomorrow),  hint: ID_DAY_SHORT[tomorrow.getDay()] },
    { label: 'Minggu depan', iso: _toISO(nextMon),   hint: ID_DAY_SHORT[nextMon.getDay()] },
    { label: 'Akhir pekan',  iso: _toISO(nextSat),   hint: fmtSh(nextSat) },
    { label: '2 minggu',     iso: _toISO(offset(14)),hint: fmtSh(offset(14)) },
    { label: '4 minggu',     iso: _toISO(offset(28)),hint: fmtSh(offset(28)) },
    { label: '8 minggu',     iso: _toISO(offset(56)),hint: fmtSh(offset(56)) },
  ];

  const todayISOStr = _toISO(today);
  const initialISOStr = initial || '';

  return (
    <div
      role="dialog"
      style={{
        position:'absolute', top:'calc(100% + 6px)',
        left: side === 'start' ? 0 : 'auto',
        right: side === 'due' ? 0 : 'auto',
        background:'white',
        border:'1px solid var(--border, #e5e5e5)',
        borderRadius: 12,
        boxShadow:'0 12px 32px rgba(15, 15, 15, .12), 0 2px 4px rgba(15, 15, 15, .04)',
        display:'flex',
        zIndex: 100,
        fontFamily:'inherit',
        userSelect:'none',
      }}
    >
      {/* Shortcuts column */}
      <div style={{
        minWidth: 240, padding:'10px 0',
        borderRight:'1px solid var(--border, #eee)',
      }}>
        {shortcuts.map((s, idx) => (
          <button
            key={idx}
            type="button"
            onClick={() => onSelect(s.iso)}
            style={{
              display:'flex', alignItems:'center', justifyContent:'space-between',
              width:'100%', padding:'8px 18px',
              border:'none', background:'transparent', cursor:'pointer',
              fontSize:13.5, fontFamily:'inherit',
              color:'var(--ink-900, #1a1614)',
              transition:'all .1s',
            }}
            onMouseEnter={(e) => {
              e.currentTarget.style.background = 'var(--brand-50, #fef0ed)';
              e.currentTarget.style.color = 'var(--brand-700, #a82210)';
            }}
            onMouseLeave={(e) => {
              e.currentTarget.style.background = 'transparent';
              e.currentTarget.style.color = 'var(--ink-900, #1a1614)';
            }}
          >
            <span style={{ fontWeight: 500 }}>{s.label}</span>
            <span style={{ color:'var(--ink-400, #999)', fontSize: 12.5 }}>{s.hint}</span>
          </button>
        ))}
        {initial && (
          <>
            <div style={{ borderTop:'1px solid var(--border, #eee)', margin:'8px 0' }}/>
            <button
              type="button"
              onClick={onClear}
              style={{
                display:'flex', width:'100%', padding:'8px 18px',
                border:'none', background:'transparent', cursor:'pointer',
                fontSize:13.5, color:'var(--rose, #c11)', fontFamily:'inherit',
                transition:'background .1s',
              }}
              onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--rose-bg, #fef0f0)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}
            >Hapus tanggal</button>
          </>
        )}
      </div>

      {/* Calendar column */}
      <div style={{ padding:'12px 16px', minWidth: 320 }}>
        {/* Header */}
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom: 10 }}>
          <strong style={{ fontSize:14, color:'var(--ink-900, #1a1614)' }}>{monthLabel}</strong>
          <div style={{ display:'flex', alignItems:'center', gap:4 }}>
            <button
              type="button"
              onClick={() => setView(new Date(today.getFullYear(), today.getMonth(), 1))}
              style={{
                background:'transparent', border:'none', cursor:'pointer',
                fontSize:13, color:'var(--brand-600, #c41f0a)',
                padding:'4px 8px', fontWeight:600, fontFamily:'inherit',
                borderRadius:6, transition:'background .1s',
              }}
              onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--brand-50, #fef0ed)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}
            >Hari ini</button>
            <button
              type="button"
              onClick={() => setView(new Date(view.getFullYear(), view.getMonth() - 1, 1))}
              style={iconBtnStyle()}
              aria-label="Bulan sebelumnya"
              onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--brand-50, #fef0ed)'; e.currentTarget.style.color = 'var(--brand-600, #c41f0a)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--ink-700, #444)'; }}
            >
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
            </button>
            <button
              type="button"
              onClick={() => setView(new Date(view.getFullYear(), view.getMonth() + 1, 1))}
              style={iconBtnStyle()}
              aria-label="Bulan berikutnya"
              onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--brand-50, #fef0ed)'; e.currentTarget.style.color = 'var(--brand-600, #c41f0a)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--ink-700, #444)'; }}
            >
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
            </button>
          </div>
        </div>

        {/* Day labels */}
        <div style={{ display:'grid', gridTemplateColumns:'repeat(7, 36px)', gap:4, marginBottom:4 }}>
          {ID_DAY_SHORT.map((d) => (
            <div key={d} style={{ width:36, textAlign:'center', fontSize:12, color:'var(--ink-400, #999)', fontWeight:500, padding:'4px 0' }}>{d}</div>
          ))}
        </div>

        {/* Date grid */}
        <div style={{ display:'grid', gridTemplateColumns:'repeat(7, 36px)', gap:4 }}>
          {grid.map((d, i) => {
            const iso = _toISO(d);
            const isToday = iso === todayISOStr;
            const isSelected = iso === initialISOStr;
            const isOtherMonth = d.getMonth() !== view.getMonth();
            const isMonday = d.getDay() === 1;
            const baseColor = isOtherMonth ? 'var(--ink-300, #ccc)' : 'var(--ink-900, #1a1614)';
            const bg = isSelected
              ? 'var(--brand-500, #ed3a1a)'
              : isMonday && !isOtherMonth
                ? 'var(--surface-2, #f3f3f0)'
                : 'transparent';
            const color = isSelected
              ? 'white'
              : isToday && !isOtherMonth
                ? 'var(--brand-600, #c41f0a)'
                : baseColor;
            return (
              <button
                key={i}
                type="button"
                onClick={() => onSelect(iso)}
                style={{
                  width:36, height:36,
                  borderRadius:'50%',
                  border:'none', background: bg, color,
                  fontSize:13.5, cursor:'pointer',
                  fontWeight: isSelected || isToday ? 700 : 500,
                  fontFamily:'inherit',
                  transition:'all .1s',
                  outline: isToday && !isSelected ? '1.5px solid var(--brand-500, #ed3a1a)' : 'none',
                  outlineOffset: -2,
                }}
                onMouseEnter={(e) => {
                  if (!isSelected) {
                    e.currentTarget.style.background = 'var(--brand-50, #fef0ed)';
                    e.currentTarget.style.color = 'var(--brand-700, #a82210)';
                  }
                }}
                onMouseLeave={(e) => {
                  if (!isSelected) {
                    e.currentTarget.style.background = bg;
                    e.currentTarget.style.color = color;
                  }
                }}
              >
                {d.getDate()}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

function iconBtnStyle() {
  return {
    width:28, height:28, display:'grid', placeItems:'center',
    background:'transparent', border:'none', cursor:'pointer',
    color:'var(--ink-700, #444)', borderRadius:6,
    fontFamily:'inherit',
    transition:'all .1s',
  };
}

window.DateRangeFilter = DateRangeFilter;
window.inRange = inRange;

// =====================================================================
// Print helpers — open a new window with print-ready HTML and trigger
// the browser print dialog. No external libs needed.
// =====================================================================

const COURIER_PREFIXES = ['JNE', 'JNT', 'SiCepat', 'AnterAja', 'Lion'];

function generateTrackingNo(prefix) {
  const p = prefix || COURIER_PREFIXES[Math.floor(Math.random() * COURIER_PREFIXES.length)];
  const n = Math.floor(Math.random() * 1e10).toString().padStart(11, '0');
  return `${p}-${n}`;
}
window.generateTrackingNo = generateTrackingNo;

function escapeHtml(s) {
  return String(s ?? '').replace(/[&<>"']/g, (c) => ({
    '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;',
  }[c]));
}

function barcodeStripes(text, height = 60) {
  // Visual-only stripes derived deterministically from the text. Not scannable.
  const seed = text.split('').reduce((s, c) => s + c.charCodeAt(0), 0);
  let bars = '';
  for (let i = 0; i < 60; i++) {
    const w = ((seed + i * 31) % 4) + 1;
    const black = ((seed + i * 17) % 5) > 1;
    bars += `<span style="display:inline-block;width:${w}px;height:${height}px;background:${black ? '#000' : '#fff'};"></span>`;
  }
  return `<div style="line-height:0;background:#fff;padding:0;">${bars}</div>`;
}

function buildResiHtml(opts) {
  const { order, items, trackingNo, business } = opts;
  const courier = (trackingNo.split('-')[0] || 'JNE').toUpperCase();
  const itemsHtml = items.map(it => `
    <tr>
      <td style="padding:2px 0;font-family:monospace;font-size:9pt;">${escapeHtml(it.sku)}</td>
      <td style="padding:2px 4px;font-size:10pt;">${escapeHtml(it.name)}</td>
      <td style="padding:2px 0;text-align:right;font-weight:700;font-size:10pt;">${it.qty}×</td>
    </tr>`).join('');

  return `<!DOCTYPE html>
<html><head><meta charset="UTF-8"/><title>Resi ${escapeHtml(trackingNo)}</title>
<style>
  @page { size: 100mm 150mm; margin: 0; }
  * { box-sizing: border-box; }
  body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; color: #000; }
  .label { width: 100mm; height: 150mm; padding: 4mm; display: flex; flex-direction: column; }
  .row { display: flex; justify-content: space-between; align-items: center; }
  .courier { font-size: 18pt; font-weight: 900; letter-spacing: -0.02em; }
  .service { font-size: 8pt; padding: 2px 6px; border: 1px solid #000; border-radius: 2px; }
  .section { padding: 3mm 0; border-top: 1px dashed #000; margin-top: 3mm; }
  .label-tiny { font-size: 7pt; text-transform: uppercase; letter-spacing: 0.1em; color: #666; }
  .text-name { font-size: 11pt; font-weight: 700; margin-top: 1mm; }
  .text-addr { font-size: 9pt; line-height: 1.35; margin-top: 1mm; }
  .tracking { font-family: monospace; font-size: 12pt; font-weight: 700; margin-top: 1mm; }
  .barcode { margin-top: 2mm; text-align: center; }
  .items table { width: 100%; border-collapse: collapse; }
  .pack-id { font-family: monospace; font-size: 9pt; padding: 1mm 2mm; background: #f0f0f0; border-radius: 2px; }
  @media print { body { -webkit-print-color-adjust: exact; print-color-adjust: exact; } }
</style></head>
<body onload="setTimeout(()=>window.print(),200);window.onafterprint=()=>window.close();">
  <div class="label">
    <div class="row">
      <div class="courier">${escapeHtml(courier)}</div>
      <div class="service">REGULAR</div>
    </div>

    <div class="section">
      <div class="label-tiny">Penerima</div>
      <div class="text-name">${escapeHtml(order?.buyer || '—')}</div>
      <div class="text-addr">${escapeHtml(order?._raw?.notes || 'Alamat akan ditarik dari marketplace')}</div>
    </div>

    <div class="section">
      <div class="label-tiny">Pengirim</div>
      <div class="text-name">${escapeHtml(business?.businessName || 'Simantep WMS')}</div>
      <div class="text-addr">Surabaya · WMS Simantep</div>
    </div>

    <div class="section">
      <div class="row">
        <div>
          <div class="label-tiny">No. Resi</div>
          <div class="tracking">${escapeHtml(trackingNo)}</div>
        </div>
        <div style="text-align:right">
          <div class="label-tiny">No. Pesanan</div>
          <div class="pack-id">${escapeHtml(order?.id || '—')}</div>
        </div>
      </div>
      <div class="barcode">${barcodeStripes(trackingNo, 50)}</div>
    </div>

    <div class="section items">
      <div class="label-tiny" style="margin-bottom:1mm">Isi Paket (${items.length} SKU)</div>
      <table>${itemsHtml}</table>
    </div>
  </div>
</body></html>`;
}

function buildPackingSlipHtml(opts) {
  const { order, items, business } = opts;
  const itemsHtml = items.map(it => `
    <tr>
      <td style="padding:6px 8px;font-family:monospace;font-size:11pt;border-bottom:1px solid #eee;">${escapeHtml(it.sku)}</td>
      <td style="padding:6px 8px;font-size:11pt;border-bottom:1px solid #eee;">${escapeHtml(it.name)}</td>
      <td style="padding:6px 8px;text-align:right;font-weight:700;font-size:11pt;border-bottom:1px solid #eee;">${it.qty}</td>
    </tr>`).join('');
  return `<!DOCTYPE html>
<html><head><meta charset="UTF-8"/><title>Packing Slip ${escapeHtml(order?.id ?? '')}</title>
<style>
  @page { size: A5; margin: 12mm; }
  body { margin:0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; color:#000; }
  h1 { font-size: 18pt; margin: 0; }
  .meta { display:flex; justify-content:space-between; margin-top:8px; font-size:10pt; color:#666; }
  table { width:100%; border-collapse:collapse; margin-top: 16px; }
  thead th { text-align:left; font-size:9pt; text-transform:uppercase; letter-spacing:.06em; color:#666; padding:6px 8px; border-bottom:2px solid #000; }
  thead th:last-child { text-align:right; }
  .footer { margin-top:24px; font-size:9pt; color:#666; padding-top:8px; border-top:1px dashed #aaa; }
</style></head>
<body onload="setTimeout(()=>window.print(),200);window.onafterprint=()=>window.close();">
  <h1>${escapeHtml(business?.businessName || 'Simantep')}</h1>
  <div class="meta">
    <div>Pesanan: <strong>${escapeHtml(order?.id || '—')}</strong></div>
    <div>Pembeli: <strong>${escapeHtml(order?.buyer || '—')}</strong></div>
  </div>
  <table>
    <thead><tr><th>SKU</th><th>Produk</th><th>Qty</th></tr></thead>
    <tbody>${itemsHtml}</tbody>
  </table>
  <div class="footer">
    Mohon cek isi paket sebelum dikirim. Untuk komplain, hubungi WhatsApp di Simantep WMS.
  </div>
</body></html>`;
}

function openPrintWindow(html) {
  const w = window.open('', '_blank', 'width=420,height=620');
  if (!w) {
    alert('Browser memblokir popup. Izinkan popup untuk localhost:4000 lalu coba lagi.');
    return;
  }
  w.document.open();
  w.document.write(html);
  w.document.close();
}

window.printResi = function ({ order, items, trackingNo }) {
  openPrintWindow(buildResiHtml({ order, items, trackingNo, business: window.__user || {} }));
};
window.printPackingSlip = function ({ order, items }) {
  openPrintWindow(buildPackingSlipHtml({ order, items, business: window.__user || {} }));
};

function buildInvoiceHtml(opts) {
  const { order, items, business } = opts;
  const subtotal = items.reduce((s, it) => s + it.qty * it.unitPrice, 0);
  const taxRate = Number(order.taxRate || 0);
  const taxAmount = Number(order.taxAmount || 0);
  const total = subtotal + taxAmount;
  const itemsHtml = items.map(it => `
    <tr>
      <td style="padding:8px;font-family:monospace;font-size:10pt;border-bottom:1px solid #eee;">${escapeHtml(it.sku)}</td>
      <td style="padding:8px;font-size:11pt;border-bottom:1px solid #eee;">${escapeHtml(it.name)}</td>
      <td style="padding:8px;text-align:right;font-size:11pt;border-bottom:1px solid #eee;">${it.qty}</td>
      <td style="padding:8px;text-align:right;font-size:11pt;border-bottom:1px solid #eee;">Rp${Number(it.unitPrice).toLocaleString('id-ID')}</td>
      <td style="padding:8px;text-align:right;font-size:11pt;font-weight:600;border-bottom:1px solid #eee;">Rp${(it.qty*it.unitPrice).toLocaleString('id-ID')}</td>
    </tr>`).join('');

  return `<!DOCTYPE html>
<html><head><meta charset="UTF-8"/><title>Faktur ${escapeHtml(order?.fakturNumber ?? order?.id ?? '')}</title>
<style>
  @page { size: A4; margin: 14mm; }
  body { margin:0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; color:#000; }
  .header { display:flex; justify-content:space-between; align-items:flex-start; padding-bottom:14mm; border-bottom:2px solid #000; }
  .biz h1 { font-size: 22pt; margin: 0 0 4px; }
  .biz .meta { font-size:9pt; color:#666; line-height:1.5; }
  .doc-title { font-size: 28pt; font-weight: 800; letter-spacing:-0.02em; }
  .faktur-no { font-family: monospace; font-size: 12pt; margin-top:4px; }
  .parties { display:flex; justify-content:space-between; padding: 8mm 0; }
  .party h3 { font-size:9pt; text-transform:uppercase; letter-spacing:.06em; color:#666; margin:0 0 4px; }
  .party .name { font-size:13pt; font-weight:700; }
  .party .detail { font-size:10pt; color:#444; line-height:1.5; }
  table.lines { width:100%; border-collapse:collapse; margin-top:6mm; }
  table.lines thead th { text-align:left; font-size:9pt; text-transform:uppercase; letter-spacing:.06em; color:#666; padding:6px 8px; border-bottom:2px solid #000; }
  table.lines thead th:nth-child(3),
  table.lines thead th:nth-child(4),
  table.lines thead th:nth-child(5) { text-align:right; }
  .totals { margin-top:6mm; margin-left:auto; width:280px; }
  .totals .row { display:flex; justify-content:space-between; padding:6px 8px; }
  .totals .row.total { font-size:14pt; font-weight:800; border-top:2px solid #000; padding-top:10px; margin-top:4px; }
  .footer { margin-top:14mm; padding-top:8mm; border-top:1px dashed #aaa; font-size:9pt; color:#666; }
</style></head>
<body onload="setTimeout(()=>window.print(),200);window.onafterprint=()=>window.close();">
  <div class="header">
    <div class="biz">
      <h1>${escapeHtml(business?.businessName || 'Simantep')}</h1>
      <div class="meta">
        ${business?.businessAddress ? escapeHtml(business.businessAddress) + '<br/>' : ''}
        ${business?.npwp ? 'NPWP: ' + escapeHtml(business.npwp) + '<br/>' : ''}
        ${business?.phone ? 'Telp: ' + escapeHtml(business.phone) : ''}
      </div>
    </div>
    <div style="text-align:right">
      <div class="doc-title">FAKTUR PAJAK</div>
      ${order.fakturNumber ? `<div class="faktur-no">${escapeHtml(order.fakturNumber)}</div>` : ''}
      <div style="font-size:10pt;color:#666;margin-top:6mm">No. Pesanan: <strong>${escapeHtml(order.id)}</strong></div>
      <div style="font-size:10pt;color:#666">Tanggal: <strong>${new Date(order._raw?.shippedAt || order._raw?.createdAt || Date.now()).toLocaleDateString('id-ID')}</strong></div>
    </div>
  </div>

  <div class="parties">
    <div class="party">
      <h3>Pengusaha Kena Pajak</h3>
      <div class="name">${escapeHtml(business?.businessName || 'Simantep')}</div>
      <div class="detail">${business?.businessAddress ? escapeHtml(business.businessAddress) + '<br/>' : ''}NPWP: ${escapeHtml(business?.npwp || '—')}</div>
    </div>
    <div class="party" style="text-align:right">
      <h3>Pembeli BKP / Penerima JKP</h3>
      <div class="name">${escapeHtml(order.buyer || '—')}</div>
      <div class="detail">via ${escapeHtml(order.mp || 'manual')}</div>
    </div>
  </div>

  <table class="lines">
    <thead>
      <tr>
        <th>SKU</th>
        <th>Nama Barang/Jasa</th>
        <th>Qty</th>
        <th>Harga Satuan</th>
        <th>Total</th>
      </tr>
    </thead>
    <tbody>${itemsHtml}</tbody>
  </table>

  <div class="totals">
    <div class="row"><span>DPP</span><strong>Rp${subtotal.toLocaleString('id-ID')}</strong></div>
    <div class="row"><span>PPN ${taxRate}%</span><strong>Rp${taxAmount.toLocaleString('id-ID')}</strong></div>
    <div class="row total"><span>TOTAL</span><strong>Rp${total.toLocaleString('id-ID')}</strong></div>
  </div>

  <div class="footer">
    Faktur ini sah dan dicetak melalui sistem Simantep WMS. Tanda tangan elektronik tidak diperlukan.
  </div>
</body></html>`;
}

window.printInvoice = function ({ order, items }) {
  openPrintWindow(buildInvoiceHtml({ order, items, business: window.__user || {} }));
};

/**
 * Bulk print resi for a list of orders. Each order opens in its own tab so
 * the user can review/cancel any individually.
 */
window.printResiBulk = function (orders) {
  for (const o of orders) {
    const items = (o._raw?.items || []).map(i => ({ sku: i.sku, name: i.name, qty: i.qty }));
    const trackingNo = o._raw?.trackingNo || generateTrackingNo();
    window.printResi({ order: o, items, trackingNo });
  }
};
