/* @jsx React.createElement */
const { useState, useEffect, useRef, useMemo } = React;
/* ============================================================
   Yappari — APP SHELL + router
   ============================================================ */
const NAV = [
  { id: 'overview',  label: 'Overview',        jp: '概要',       icon: 'overview' },
  { id: 'sales',     label: 'Penjualan',       jp: '売上',       icon: 'sales' },
  { id: 'stock',     label: 'Stok',            jp: '在庫',       icon: 'stock' },
  { id: 'planogram', label: 'Planogram',       jp: '棚割',       icon: 'planogram' },
  { id: 'control',   label: 'Machine Control', jp: '制御',       icon: 'control' },
  { id: 'signage',   label: 'Signage',         jp: '広告',       icon: 'screen' },
  { id: 'products',  label: 'Produk',          jp: '商品',       icon: 'products' },
  { id: 'events',    label: 'Events',          jp: 'イベント',   icon: 'events' },
  { id: 'settings',  label: 'Pengaturan',      jp: '設定',       icon: 'settings' },
];

/* tweakable typography + accent */
const TWEAK_DEFAULTS = { uiFont: 'Plus Jakarta Sans', numberStyle: 'Rapi', headWeight: 'Sedang', textScale: 100, accent: '#004080' };
const TFONTS = {
  'Plus Jakarta Sans': '"Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif',
  'Be Vietnam Pro': '"Be Vietnam Pro", ui-sans-serif, system-ui, sans-serif',
  'Hanken Grotesk': '"Hanken Grotesk", ui-sans-serif, system-ui, sans-serif',
  'Figtree': '"Figtree", ui-sans-serif, system-ui, sans-serif',
};
const TWHEAD = { Ringan: 600, Sedang: 700, Tebal: 800 };

function useClickOutside(ref, cb) {
  useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) cb(); };
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, []);
}

function MachineSelect({ machines, value, onChange }) {
  const [open, setOpen] = useState(false);
  const ref = useRef();
  useClickOutside(ref, () => setOpen(false));
  const sel = machines.find(m => m.id === value);
  const dotColor = (s) => s === 'online' ? 'var(--st-online)' : s === 'offline' ? 'var(--st-offline)' : s === 'error' ? 'var(--st-error)' : 'var(--st-maint)';
  return React.createElement('div', { className: 'mach-select', ref },
    React.createElement('button', { className: 'ms-btn', onClick: () => setOpen(o => !o) },
      sel ? React.createElement('span', { className: 'ms-dot', style: { background: dotColor(sel.status) } }) : React.createElement(Icon, { name: 'layers', size: 16, style: { color: 'var(--st-maint)' } }),
      React.createElement('span', { style: { flex: 1, textAlign: 'left', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, sel ? sel.name : 'Semua mesin'),
      React.createElement(Icon, { name: 'chevronDown', size: 16, style: { color: 'var(--fg-3)' } })),
    open && React.createElement('div', { className: 'ms-menu' },
      React.createElement('div', { className: 'ms-opt', onClick: () => { onChange(null); setOpen(false); }, style: value == null ? { background: 'var(--bg-sunken)' } : null },
        React.createElement(Icon, { name: 'layers', size: 16, style: { color: 'var(--st-maint)' } }),
        React.createElement('div', null, React.createElement('div', { style: { fontWeight: 700 } }, 'Semua mesin'), React.createElement('div', { className: 'ms-loc' }, machines.length + ' unit'))),
      machines.map(m => React.createElement('div', { key: m.id, className: 'ms-opt', onClick: () => { onChange(m.id); setOpen(false); }, style: value === m.id ? { background: 'var(--bg-sunken)' } : null },
        React.createElement('span', { className: 'ms-dot', style: { background: dotColor(m.status) } }),
        React.createElement('div', { style: { minWidth: 0 } }, React.createElement('div', { style: { fontWeight: 700 } }, m.name), React.createElement('div', { className: 'ms-loc', style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, m.loc)))),
    ),
  );
}

function Clock() {
  const [t, setT] = useState(new Date());
  useEffect(() => { const id = setInterval(() => setT(new Date()), 1000); return () => clearInterval(id); }, []);
  const hh = String(t.getHours()).padStart(2, '0');
  const mm = String(t.getMinutes()).padStart(2, '0');
  const ss = String(t.getSeconds()).padStart(2, '0');
  return React.createElement('div', { className: 'tb-clock' }, hh + ':' + mm, React.createElement('span', { className: 'secs' }, ':' + ss));
}

function MachineDrawer({ m, onClose, onGo }) {
  const Y = window.YAPPARI;
  const sum = machineStockSummary(m.id);
  const sales = Y.SALES_BY_MACHINE[m.id];
  const tempBad = m.temp != null && m.temp > 10;
  const stat = (label, value, color) => React.createElement('div', { className: 'card', style: { padding: 14, boxShadow: 'none', background: 'var(--bg-sunken)' } },
    React.createElement('div', { className: 'field-label', style: { marginBottom: 4 } }, label),
    React.createElement('div', { style: { fontSize: 18, fontWeight: 800, color: color || 'var(--fg-1)' } }, value));
  return React.createElement('div', { style: { position: 'fixed', inset: 0, zIndex: 150, display: 'flex', justifyContent: 'flex-end', background: 'rgba(0,20,38,.45)', animation: 'fadeIn .2s' }, onClick: onClose },
    React.createElement('aside', { onClick: e => e.stopPropagation(), style: { width: 440, maxWidth: '92vw', background: 'var(--bg)', height: '100%', overflowY: 'auto', boxShadow: 'var(--shadow-3)', animation: 'viewIn .25s' } },
      React.createElement('div', { style: { background: 'linear-gradient(150deg,#004080,#002E5C)', color: '#fff', padding: '22px 24px', position: 'relative', overflow: 'hidden' } },
        React.createElement('div', { style: { position: 'absolute', right: -10, top: -10, opacity: .16 } }, React.createElement(PlumBlossom, { size: 120, color: '#fff' })),
        React.createElement('div', { className: 'row', style: { justifyContent: 'space-between', alignItems: 'flex-start' } },
          React.createElement('div', null,
            React.createElement('div', { style: { fontFamily: 'var(--font-display)', fontSize: 30, letterSpacing: '.02em' } }, m.name),
            React.createElement('div', { className: 'row gap-1', style: { fontSize: 13, opacity: .9, marginTop: 4 } }, React.createElement(Icon, { name: 'mapPin', size: 14 }), m.loc)),
          React.createElement('button', { className: 'icon-btn', onClick: onClose, style: { background: 'rgba(255,255,255,.15)', border: 'none', color: '#fff' } }, React.createElement(Icon, { name: 'x', size: 18 }))),
        React.createElement('div', { style: { marginTop: 14 } }, React.createElement(StatusBadge, { status: m.status })),
      ),
      React.createElement('div', { style: { padding: 24 } },
        React.createElement('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 16 } },
          stat('Suhu kabin', m.temp != null ? m.temp + '°C' : '—', tempBad ? 'var(--st-error)' : 'var(--st-online)'),
          stat('Pintu', m.door === 'closed' ? 'Tertutup' : m.door === 'open' ? 'Terbuka' : '—', m.door === 'open' ? 'var(--st-warn)' : null),
          stat('Omzet hari ini', fmtRpShort(sales.totalRev)),
          stat('Transaksi', fmtNum(sales.totalTx)),
          stat('Slot habis', sum.empty, sum.empty ? 'var(--st-error)' : 'var(--st-online)'),
          stat('Stok rendah', sum.low, sum.low ? 'var(--st-warn)' : 'var(--st-online)')),
        React.createElement('div', { style: { fontSize: 12.5, color: 'var(--fg-3)', marginBottom: 16 } }, 'Serial ' + m.serial + ' · ' + m.model + ' · terlihat ' + relMins(m.lastSeen)),
        React.createElement('div', { className: 'col gap-3' },
          React.createElement('div', { className: 'row gap-3' },
            React.createElement('button', { className: 'btn btn-ghost', style: { flex: 1, justifyContent: 'center' }, onClick: () => onGo('stock', m.id) }, React.createElement(Icon, { name: 'stock', size: 16 }), 'Stok'),
            React.createElement('button', { className: 'btn btn-ghost', style: { flex: 1, justifyContent: 'center' }, onClick: () => onGo('planogram', m.id) }, React.createElement(Icon, { name: 'planogram', size: 16 }), 'Planogram')),
          React.createElement('button', { className: 'btn btn-danger', style: { justifyContent: 'center' }, onClick: () => onGo('control', m.id) }, React.createElement(Icon, { name: 'zap', size: 16 }), 'Buka Machine Control'),
        ),
      ),
    ),
  );
}

function App() {
  const Y = window.YAPPARI;
  const machines = Y.MACHINES;
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [, forceRev] = useState(0);
  const bump = () => forceRev(v => v + 1);
  const [theme, setTheme] = useState(() => localStorage.getItem('yappari-theme') || 'light');
  const [view, setView] = useState('overview');
  const [selMachine, setSelMachine] = useState(null);
  const [collapsed, setCollapsed] = useState(false);
  const [mobileOpen, setMobileOpen] = useState(false);
  const [drawer, setDrawer] = useState(null);
  const [refreshing, setRefreshing] = useState(false);
  const [lastUpdate, setLastUpdate] = useState(new Date());
  const [tick, setTick] = useState(0);

  useEffect(() => { document.documentElement.setAttribute('data-theme', theme); localStorage.setItem('yappari-theme', theme); }, [theme]);
  useEffect(() => {
    const rs = document.documentElement.style;
    rs.setProperty('--font-sans', TFONTS[t.uiFont] || TFONTS['Plus Jakarta Sans']);
    rs.fontSize = (16 * (t.textScale || 100) / 100) + 'px';
    rs.setProperty('--w-head', String(TWHEAD[t.headWeight] || 700));
    if (t.numberStyle === 'Tegas') { rs.setProperty('--font-num', 'var(--font-display)'); rs.setProperty('--w-num', '400'); rs.setProperty('--ls-num', '.01em'); }
    else { rs.setProperty('--font-num', 'var(--font-sans)'); rs.setProperty('--w-num', '700'); rs.setProperty('--ls-num', '-.01em'); }
    rs.setProperty('--accent', t.accent || '#004080');
  }, [t]);
  useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 5000); return () => clearInterval(id); }, []);

  const online = machines.filter(m => m.status === 'online').length;
  const offline = machines.length - online;
  const navMeta = NAV.find(n => n.id === view);

  const doRefresh = () => { setRefreshing(true); setTimeout(() => { setRefreshing(false); setLastUpdate(new Date()); }, 900); };
  const relUpdate = () => { const s = Math.floor((Date.now() - lastUpdate.getTime()) / 1000); return s < 5 ? 'baru saja' : s < 60 ? s + ' detik lalu' : Math.floor(s / 60) + ' menit lalu'; };
  const goView = (v) => { setView(v); setMobileOpen(false); };
  const goFromDrawer = (v, mid) => { setSelMachine(mid); setView(v); setDrawer(null); };

  const renderView = () => {
    switch (view) {
      case 'overview':  return React.createElement(OverviewView, { machines, onOpenMachine: setDrawer });
      case 'sales':     return React.createElement(SalesView, { selectedMachine: selMachine, machines });
      case 'stock':     return React.createElement(StockView, { selectedMachine: selMachine, machines });
      case 'planogram': return React.createElement(PlanogramView, { selectedMachine: selMachine, machines });
      case 'control':   return React.createElement(ControlView, { selectedMachine: selMachine, machines });
      case 'signage':   return React.createElement(SignageView, { machines, selectedMachine: selMachine });
      case 'products':  return React.createElement(ProductsView, null);
      case 'events':    return React.createElement(EventsView, { machines, selectedMachine: selMachine });
      case 'settings':  return React.createElement(SettingsView, { machines, onChange: bump });
      default: return null;
    }
  };

  return React.createElement('div', { className: 'app' },
    mobileOpen && React.createElement('div', { className: 'scrim-mobile show', onClick: () => setMobileOpen(false) }),
    // ---- SIDEBAR ----
    React.createElement('aside', { className: 'sidebar' + (collapsed ? ' collapsed' : '') + (mobileOpen ? ' mobile-open' : '') },
      React.createElement('div', { className: 'side-brand' },
        React.createElement('img', { src: 'assets/yappari.png', alt: 'Yappari' }),
        React.createElement('div', { style: { minWidth: 0 } },
          React.createElement('div', { className: 'wordmark' }, 'YAPPARI!'),
          React.createElement('div', { className: 'sub' }, 'Vending Control')),
      ),
      React.createElement('nav', { className: 'side-nav' },
        NAV.map(n => React.createElement('button', { key: n.id, className: 'nav-item' + (view === n.id ? ' active' : ''), onClick: () => goView(n.id), title: n.label },
          React.createElement('span', { className: 'ni-icon' }, React.createElement(Icon, { name: n.icon, size: 20 })),
          React.createElement('span', { className: 'ni-label' }, n.label),
          n.id === 'control' && React.createElement('span', { className: 'ni-badge' }, offline)),
        )),
      React.createElement('div', { className: 'side-foot' },
        React.createElement('div', { className: 'side-foot-label', style: { fontSize: 11, textTransform: 'uppercase', letterSpacing: '.12em', fontWeight: 700, color: 'var(--fg-3)', marginBottom: 8 } }, 'Status armada'),
        React.createElement('div', { className: 'side-status' },
          React.createElement('div', { className: 'ss-pill ss-on' }, React.createElement('span', { className: 'ss-num' }, online), React.createElement('span', { className: 'ss-lab' }, 'Online')),
          React.createElement('div', { className: 'ss-pill ss-off' }, React.createElement('span', { className: 'ss-num' }, offline), React.createElement('span', { className: 'ss-lab' }, 'Offline'))),
        React.createElement('button', { className: 'nav-item', style: { marginTop: 8, justifyContent: collapsed ? 'center' : 'flex-start' }, onClick: () => setCollapsed(c => !c) },
          React.createElement('span', { className: 'ni-icon' }, React.createElement(Icon, { name: collapsed ? 'chevronRight' : 'chevronLeft', size: 20 })),
          React.createElement('span', { className: 'ni-label' }, 'Ciutkan')),
        React.createElement('button', { className: 'nav-item', style: { justifyContent: collapsed ? 'center' : 'flex-start', color: 'var(--st-error)' }, onClick: () => window.YAPPARI_AUTH.logout(), title: 'Keluar' },
          React.createElement('span', { className: 'ni-icon' }, React.createElement(Icon, { name: 'wifiOff', size: 20 })),
          React.createElement('span', { className: 'ni-label' }, 'Keluar')),
      ),
    ),
    // ---- MAIN ----
    React.createElement('div', { className: 'main' },
      React.createElement('header', { className: 'topbar' },
        React.createElement('button', { className: 'icon-btn menu-toggle', onClick: () => setMobileOpen(true) }, React.createElement(Icon, { name: 'menu', size: 20 })),
        React.createElement('div', { className: 'tb-title' }, navMeta.label, React.createElement('span', { className: 'jp' }, navMeta.jp)),
        React.createElement('div', { className: 'tb-spacer' }),
        React.createElement('div', { className: 'hide-sm' }, React.createElement(MachineSelect, { machines, value: selMachine, onChange: setSelMachine })),
        React.createElement('button', { className: 'icon-btn' + (refreshing ? ' spinning' : ''), onClick: doRefresh, title: 'Refresh' }, React.createElement(Icon, { name: 'refresh', size: 18 })),
        React.createElement('div', { className: 'col hide-sm', style: { alignItems: 'flex-end', gap: 0 } },
          React.createElement(Clock, null),
          React.createElement('div', { className: 'tb-update' }, React.createElement('span', { className: 'dot' }), 'Update ' + relUpdate())),
        React.createElement('button', { className: 'icon-btn', onClick: () => setTheme(t => t === 'light' ? 'dark' : 'light'), title: 'Ganti tema' }, React.createElement(Icon, { name: theme === 'light' ? 'moon' : 'sun', size: 18 })),
      ),
      React.createElement('main', { className: 'content' },
        React.createElement('div', { className: 'content-inner' }, renderView())),
    ),
    drawer && React.createElement(MachineDrawer, { m: drawer, onClose: () => setDrawer(null), onGo: goFromDrawer }),
    React.createElement(TweaksPanel, null,
      React.createElement(TweakSection, { label: 'Tipografi' }),
      React.createElement(TweakSelect, { label: 'Font teks', value: t.uiFont, options: ['Plus Jakarta Sans', 'Be Vietnam Pro', 'Hanken Grotesk', 'Figtree'], onChange: v => setTweak('uiFont', v) }),
      React.createElement(TweakRadio, { label: 'Angka besar', value: t.numberStyle, options: ['Rapi', 'Tegas'], onChange: v => setTweak('numberStyle', v) }),
      React.createElement(TweakRadio, { label: 'Bobot judul', value: t.headWeight, options: ['Ringan', 'Sedang', 'Tebal'], onChange: v => setTweak('headWeight', v) }),
      React.createElement(TweakSlider, { label: 'Ukuran teks', value: t.textScale, min: 90, max: 115, step: 5, unit: '%', onChange: v => setTweak('textScale', v) }),
      React.createElement(TweakSection, { label: 'Tampilan' }),
      React.createElement(TweakColor, { label: 'Aksen', value: t.accent, options: ['#004080', '#F04000', '#0078A8', '#1FA463'], onChange: v => setTweak('accent', v) }),
      React.createElement(TweakToggle, { label: 'Mode gelap', value: theme === 'dark', onChange: v => setTheme(v ? 'dark' : 'light') }),
    ),
  );
}

/* ---- Boot: login (jika perlu) lalu muat data dari API ---- */
function BootScreen({ msg }) {
  return React.createElement('div', { style: { position: 'fixed', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 18, background: 'var(--bg)' } },
    React.createElement('img', { src: 'assets/yappari.png', alt: 'Yappari', style: { width: 72, height: 72, borderRadius: '50%', animation: 'pulse 1.4s ease-in-out infinite' } }),
    React.createElement('div', { style: { fontFamily: 'var(--font-display)', fontSize: 28, letterSpacing: '.04em', color: 'var(--accent)' } }, 'YAPPARI!'),
    React.createElement('div', { style: { fontSize: 14, color: 'var(--fg-3)' } }, msg || 'Memuat data…'));
}

function LoginScreen({ onDone }) {
  const [email, setEmail] = useState('');
  const [pw, setPw] = useState('');
  const [err, setErr] = useState('');
  const [busy, setBusy] = useState(false);
  const submit = async () => {
    setErr('');
    if (!email) { setErr('Email wajib diisi'); return; }
    if (!pw) { setErr('Password wajib diisi'); return; }
    setBusy(true);
    try { await window.YAPPARI_AUTH.login(email, pw); onDone(); }
    catch (e) { setErr(e.message || 'Login gagal'); setBusy(false); }
  };
  const onKey = (e) => { if (e.key === 'Enter') submit(); };
  return React.createElement('div', { style: { position: 'fixed', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'linear-gradient(150deg,#004080,#002E5C)', padding: 20 } },
    React.createElement('div', { style: { width: 380, maxWidth: '94vw', background: 'var(--bg)', borderRadius: 16, padding: '32px 28px', boxShadow: '0 20px 60px rgba(0,0,0,.3)' } },
      React.createElement('div', { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10, marginBottom: 22 } },
        React.createElement('img', { src: 'assets/yappari.png', alt: 'Yappari', style: { width: 56, height: 56, borderRadius: '50%' } }),
        React.createElement('div', { style: { fontFamily: 'var(--font-display)', fontSize: 26, letterSpacing: '.04em', color: 'var(--accent)' } }, 'YAPPARI!'),
        React.createElement('div', { style: { fontSize: 13, color: 'var(--fg-3)' } }, 'Vending Control — masuk untuk lanjut')),
      React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 12 } },
        React.createElement('input', { className: 'inp', type: 'email', placeholder: 'Email', value: email, autoFocus: true, onChange: (e) => setEmail(e.target.value), onKeyDown: onKey, style: { padding: '10px 12px', borderRadius: 10, border: '1px solid var(--border-subtle)', background: 'var(--bg-elev)', color: 'var(--fg-1)', fontSize: 14 } }),
        React.createElement('input', { className: 'inp', type: 'password', placeholder: 'Password', value: pw, onChange: (e) => setPw(e.target.value), onKeyDown: onKey, style: { padding: '10px 12px', borderRadius: 10, border: '1px solid var(--border-subtle)', background: 'var(--bg-elev)', color: 'var(--fg-1)', fontSize: 14 } }),
        err && React.createElement('div', { style: { fontSize: 13, color: 'var(--st-error)' } }, err),
        React.createElement('button', { onClick: submit, disabled: busy, style: { padding: '11px 12px', borderRadius: 10, border: 'none', background: 'var(--accent)', color: '#fff', fontSize: 15, fontWeight: 700, cursor: 'pointer', opacity: busy ? .6 : 1 } }, busy ? 'Memproses…' : 'Masuk'))));
}

const _root = ReactDOM.createRoot(document.getElementById('root'));

function boot() {
  if (!window.YAPPARI_AUTH.getToken()) {
    _root.render(React.createElement(LoginScreen, { onDone: boot }));
    return;
  }
  _root.render(React.createElement(BootScreen, { msg: 'Memuat data…' }));
  window.loadYappari().then(function (Y) {
    if (!Y) { _root.render(React.createElement(LoginScreen, { onDone: boot })); return; }
    if (Y._fallback) console.warn('[yappari] berjalan dengan data contoh (mock).');
    _root.render(React.createElement(App));
  }).catch(function (e) {
    console.error('[yappari] boot gagal:', e);
    _root.render(React.createElement(BootScreen, { msg: 'Gagal memuat data. Coba muat ulang.' }));
  });
}
boot();
