/* ═══════════════════════════════════════════════════════════
   Main app — icons, login, overview dashboard, app shell
   (rail nav + topbar + theme toggle), Root state + mount.
   This is the reconstructed entry that ties every view +
   modal together.
═══════════════════════════════════════════════════════════ */
(function () {
const { useState: useStateA, useEffect: useEffectA, useReducer, useRef: useRefA } = React;
const {
  GUNS: GUNS_A, parseKey: parseKeyA, keyLabel: keyLabelA, fmtDatetime: fmtA,
  totalAmmo: totalAmmoA, totalAmmoGuns: totalAmmoGunsA, totalAmmoBunker: totalAmmoBunkerA,
  calcGroupTotal: calcGroupTotalA,
  buildInit: buildInitA, applyMigrations: applyMigrationsA,
  reducer: reducerA, saveState: saveStateA,
} = window;

/* ── Icons (inline stroke SVG) ──────────────────────────── */
const ICON_PATHS = {
  grid: 'M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z',
  layers: 'M12 2 2 7l10 5 10-5zM2 17l10 5 10-5M2 12l10 5 10-5',
  box: 'M21 8 12 3 3 8v8l9 5 9-5zM3 8l9 5 9-5M12 13v8',
  target: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM12 6a6 6 0 1 0 0 12 6 6 0 0 0 0-12zM12 10a2 2 0 1 0 0 4 2 2 0 0 0 0-4z',
  swap: 'M16 3l4 4-4 4M20 7H8M8 21l-4-4 4-4M4 17h12',
  ban: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM5 5l14 14',
  barrel: 'M5 4h14M5 4v16M19 4v16M5 20h14M8 4v16M16 4v16',
  list: 'M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01',
  settings: 'M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8zM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-2.82 1.17V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.2.61.76 1 1.4 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z',
  sun: 'M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10zM12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4',
  moon: 'M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z',
  logout: 'M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9',
  menu: 'M3 12h18M3 6h18M3 18h18',
  plus: 'M12 5v14M5 12h14',
  cloud: 'M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z',
  bolt: 'M13 2 3 14h9l-1 8 10-12h-9z',
  shield: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z',
};
function Icon({ name, size = 18, stroke = 2, fill = false }) {
  const d = ICON_PATHS[name] || '';
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill ? 'currentColor' : 'none'}
      stroke="currentColor" strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d={d} />
    </svg>
  );
}

/* ── Toast ──────────────────────────────────────────────── */
function useToast() {
  const [toast, setToast] = useStateA(null);
  const show = (msg, kind = 'ok') => { setToast({ msg, kind }); setTimeout(() => setToast(null), 2400); };
  const node = toast ? <div className={'toast' + (toast.kind === 'error' ? ' error' : '')}>{toast.msg}</div> : null;
  return [node, show];
}

/* ── Login screen ───────────────────────────────────────── */
const ROLE_META = {
  viewer:   { label: 'צפייה בלבד', color: 'var(--text-3)',  icon: '👁' },
  operator: { label: 'מפעיל',       color: 'var(--ok)',      icon: '⚡' },
  admin:    { label: 'מנהל',         color: 'var(--accent)',  icon: '🔐' },
};

function LoginScreen({ onAuthed, sessionExpired }) {
  const cfg = window.APP_CONFIG || {};
  const [code, setCode] = useStateA('');
  const [err, setErr]   = useStateA('');
  const [busy, setBusy] = useStateA(false);
  const [role, setRole] = useStateA(null); // show after login

  const submit = async () => {
    if (!code || busy) return;
    setBusy(true); setErr('');
    try {
      const d = await window.api.login(code);
      setRole(d.role);
      // Brief role flash then continue
      setTimeout(() => onAuthed(), 900);
    }
    catch { setErr('קוד שגוי — נסה שוב'); setCode(''); }
    finally { setBusy(false); }
  };

  if (role) {
    const m = ROLE_META[role] || ROLE_META.viewer;
    return (
      <div className="login-wrap">
        <div className="login-card" style={{ gap: '.6rem', textAlign: 'center' }}>
          <div style={{ fontSize: '2.5rem' }}>{m.icon}</div>
          <div style={{ fontWeight: 700, fontSize: '1.2rem', color: m.color }}>{m.label}</div>
          <div className="dim u-sm">כניסה מאושרת...</div>
        </div>
      </div>
    );
  }

  return (
    <div className="login-wrap">
      <div className="login-card">
        <div className="login-logo"><Icon name="target" size={30} /></div>
        <h1 className="login-title">{cfg.appName || 'ניהול תחמושת סוללתית'}</h1>
        <p className="login-sub">{cfg.appShort || 'ARTY · AMMO'} · גרסה {cfg.version || ''}</p>
        {sessionExpired && (
          <div className="callout callout-warn u-center" style={{ width: '100%', fontSize: '.82rem' }}>
            ⏱ הסשן פג — יש להתחבר מחדש
          </div>
        )}
        {err && <div className="callout callout-danger u-center u-bold" style={{ width: '100%' }}>{err}</div>}
        <input type="password" autoFocus value={code} placeholder="הזן קוד גישה"
          onChange={e => setCode(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && submit()}
          style={{ textAlign: 'center', fontSize: '1.05rem', letterSpacing: '.12em' }} />
        <button className="btn btn-primary btn-lg btn-block" disabled={busy || !code} onClick={submit}>
          {busy ? 'מאמת…' : 'כניסה למערכת'}
        </button>
        {cfg.roles?.hasOperator && (
          <div style={{ fontSize: '.7rem', color: 'var(--text-4)', textAlign: 'center', lineHeight: 1.6 }}>
            👁 צפייה · ⚡ מפעיל · 🔐 מנהל
          </div>
        )}
        <p className="login-foot"><Icon name="shield" size={13} /> אימות HMAC מאובטח בצד השרת</p>
      </div>
    </div>
  );
}

/* ── Overview dashboard ─────────────────────────────────── */
function StatCard({ icon, label, value, meta, accent }) {
  return (
    <div className="stat">
      <span className="stat-label">{icon}{label}</span>
      <span className={'stat-val' + (accent ? ' stat-accent' : '')}>{value}</span>
      {meta && <span className="stat-meta">{meta}</span>}
    </div>
  );
}

function categoryTotals(state) {
  const gun    = totalAmmoGunsA(state);
  const ramsav = totalAmmoBunkerA(state);
  const outGun = { shell: 0, charge: 0, fuze: 0 };
  const outRamsav = { shell: 0, charge: 0, fuze: 0 };
  (state.registeredTypes || []).forEach(r => {
    outGun[r.category]    = (outGun[r.category]    || 0) + (gun[r.key]    || 0);
    outRamsav[r.category] = (outRamsav[r.category] || 0) + (ramsav[r.key] || 0);
  });
  return { gun: outGun, ramsav: outRamsav };
}

/* ── Custom domain icons (inline SVG) ───────────────────── */
function ShellIcon({ size = 16 }) {
  // Artillery shell silhouette
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M12 2c-1.1 0-2 .7-2 1.6V7h4V3.6C14 2.7 13.1 2 12 2z"/>
      <rect x="9" y="7" width="6" height="3" rx="1"/>
      <rect x="8" y="10" width="8" height="3" rx="1"/>
      <rect x="7" y="13" width="10" height="3" rx="1"/>
      <path d="M7 16h10c0 2.8-2.2 5-5 5s-5-2.2-5-5z"/>
    </svg>
  );
}
function MaintenanceIcon({ size = 16 }) {
  // Wrench — cleaning/maintenance
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
    </svg>
  );
}
function BrokenBarrelIcon({ size = 16 }) {
  // Cracked barrel — barrel wear
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <rect x="4" y="3" width="16" height="18" rx="3"/>
      <line x1="4" y1="8" x2="20" y2="8"/>
      <line x1="4" y1="16" x2="20" y2="16"/>
      <polyline points="10,11 13,12.5 10,14" stroke="var(--danger)" strokeWidth="2"/>
    </svg>
  );
}

function readinessOf(state, g) {
  if (state.readiness?.red === g)    return { cls: 'dot-danger', label: 'כוננות צוות אדום' };
  if (state.readiness?.yellow === g) return { cls: 'dot-warn',   label: 'כוננות צוות צהוב' };
  return { cls: 'dot-ok', label: 'כוננות צוות ירוק' };
}

function GunMiniCard({ state, gun }) {
  const regs = state.registeredTypes;
  const inv = state.guns[gun] || {};
  const items = regs.filter(r => (inv[r.key] || 0) > 0).sort((a, b) => (inv[b.key] || 0) - (inv[a.key] || 0));
  const top = items.slice(0, 4);
  const r = readinessOf(state, gun);
  const bd = state.barrelData?.[gun] || {};
  const totalShells = bd.totalShells || 0;

  return (
    <div className="gun-card">
      <div className="gun-card-top">
        <span className="gun-id">{gun}</span>
        <span className="chip"><span className={'dot ' + r.cls} />{r.label}</span>
      </div>
      <div className="gun-amlist">
        {top.length === 0 ? <span className="dim u-sm">אין מלאי</span> : top.map(it => (
          <div key={it.key} className="gun-amrow"><span className="lbl">{it.label}</span><span className="mono u-bold">{inv[it.key]}</span></div>
        ))}
        {items.length > 4 && <span className="dim u-tiny">+{items.length - 4} סוגים נוספים</span>}
      </div>
      <div className="gun-wear">
        <div className="wear-pill"><span className="n">{bd.shellsSinceClean || 0}</span><span className="t"><MaintenanceIcon size={11} /> נקיון</span></div>
        <div className="wear-pill"><span className="n">{bd.muzzle?.count || 0}</span><span className="t"><BrokenBarrelIcon size={11} /> קנה</span></div>
        <div className="wear-pill"><span className="n mono">{totalShells}</span><span className="t"><ShellIcon size={11} /> סה"כ</span></div>
      </div>
    </div>
  );
}

function ActivityFeed({ state }) {
  const regs = state.registeredTypes;
  const fires = (state.firingLog || []).slice(0, 6).map(r => ({
    kind: 'fire', ts: (r.date || '') + ' ' + (r.time || ''),
    title: `משימת אש ${r.missionId} — ${r.target || ''}`, sub: `צוות ${r.gun} · ${r.unit || ''}`,
  }));
  const moves = [...(state.transferLog || [])].slice(-6).reverse().map(r => ({
    kind: 'move', ts: fmtA(r.datetime),
    title: `${r.src} ← ${r.dst}`, sub: (r.items || []).map(it => `${keyLabelA(it.key, regs)}×${it.qty}`).join(' · '),
  }));
  const feed = [...fires, ...moves].slice(0, 8);

  const meta = {
    fire: { icon: <Icon name="target" size={15} />, color: 'var(--danger)', soft: 'var(--danger-soft)' },
    move: { icon: <Icon name="swap" size={15} />, color: 'var(--info)', soft: 'var(--info-soft)' },
  };

  return (
    <div className="section-card">
      <div className="section-header"><span className="section-title"><Icon name="list" size={16} /> פעילות אחרונה</span></div>
      <div className="card-pad" style={{ paddingTop: '.3rem', paddingBottom: '.3rem' }}>
        {feed.length === 0 ? <div className="empty u-sm">אין פעילות עדיין</div> : (
          <div className="feed">
            {feed.map((f, i) => (
              <div key={i} className="feed-item">
                <span className="feed-ico" style={{ background: meta[f.kind].soft, color: meta[f.kind].color }}>{meta[f.kind].icon}</span>
                <div className="feed-txt"><span className="t">{f.title}</span><span className="s">{f.sub} · {f.ts}</span></div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

function OverviewView({ state }) {
  const cats = categoryTotals(state);
  const redTeam = state.readiness?.red, yellowTeam = state.readiness?.yellow;
  const totalsGun = totalAmmoGunsA(state);
  const critical = (state.registeredTypes || []).filter(r => { const rl = state.redLines?.[r.key] || 0; return rl > 0 && (totalsGun[r.key] || 0) < rl; });
  const groups = (state.ammoGroups || []).map(g => ({ ...g, ...calcGroupTotalA(g, state) }));
  const critGroups = groups.filter(g => g.redLine > 0 && g.total < g.redLine);

  return (
    <div className="view-stack" style={{ gap: '.8rem' }}>
      {(redTeam || yellowTeam || critical.length > 0 || critGroups.length > 0) && (
        <div className="row" style={{ gap: '.6rem', flexWrap: 'wrap' }}>
          {redTeam && <div className="callout callout-danger row" style={{ gap: '.5rem' }}><span className="dot dot-danger" /> צוות <b>{redTeam}</b> כוננות צוות אדום</div>}
          {yellowTeam && <div className="callout callout-warn row" style={{ gap: '.5rem' }}><span className="dot dot-warn" /> צוות <b>{yellowTeam}</b> כוננות צוות צהוב</div>}
          {critical.length > 0 && <div className="callout callout-danger row" style={{ gap: '.5rem' }}>⚠ {critical.length} סוגי תחמושת מתחת לקו האדום</div>}
          {critGroups.map(g => <div key={g.id} className="callout callout-danger row" style={{ gap: '.5rem' }}>⚠ קבוצה <b>{g.label}</b>: {g.total} / קו {g.redLine}</div>)}
        </div>
      )}

      <div className="stat-grid">
        <StatCard icon={<ShellIcon size={15} />} label="פגזים קרקע" value={cats.gun.shell} meta="ערום צוותים" accent />
        <StatCard icon={<ShellIcon size={15} />} label="פגזים רמסע" value={cats.ramsav.shell} meta="משטחים/מחסן" />
        <StatCard icon={<Icon name="bolt" size={15} />} label='חנ"ה קרקע' value={cats.gun.charge} />
        <StatCard icon={<Icon name="shield" size={15} />} label="מרעומים קרקע" value={cats.gun.fuze} />
        <StatCard icon={<Icon name="target" size={15} />} label="משימות אש" value={(state.firingLog || []).length} />
        <StatCard icon={<Icon name="ban" size={15} />} label="פינת פסולים" value={(state.quarantineLog || []).length} />
      </div>

      {/* Ammo groups summary — only shown when groups exist */}
      {groups.length > 0 && (
        <div className="section-card">
          <div className="section-header"><span className="section-title">📦 קבוצות תחמושת</span></div>
          <div className="card-pad">
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: '.6rem' }}>
              {groups.map(g => {
                const crit = g.redLine > 0 && g.total < g.redLine;
                const pct  = g.redLine > 0 ? Math.min(100, Math.round(g.total / g.redLine * 100)) : null;
                return (
                  <div key={g.id} style={{
                    border: '1px solid ' + (crit ? 'var(--danger-line)' : 'var(--border)'),
                    borderRadius: 'var(--r2)', padding: '.7rem .85rem',
                    background: crit ? 'var(--danger-soft)' : 'var(--surface)',
                  }}>
                    <div className="spread" style={{ marginBottom: '.4rem' }}>
                      <span className="u-bold u-sm">{g.label}</span>
                      {crit && <span style={{ color: 'var(--danger)', fontSize: '.72rem', fontWeight: 700 }}>⚠ מתחת לקו</span>}
                    </div>
                    <div className="row" style={{ gap: '1rem', marginBottom: '.5rem' }}>
                      <div className="stack" style={{ gap: 0, alignItems: 'center' }}>
                        <span className="mono u-bold" style={{ fontSize: '1.3rem', color: crit ? 'var(--danger)' : 'var(--accent)' }}>{g.total}</span>
                        <span className="dim u-tiny">סה"כ</span>
                      </div>
                      <div className="stack" style={{ gap: 0, alignItems: 'center' }}>
                        <span className="mono u-bold" style={{ fontSize: '1rem' }}>{g.gunTotal}</span>
                        <span className="dim u-tiny">קרקע</span>
                      </div>
                      <div className="stack" style={{ gap: 0, alignItems: 'center' }}>
                        <span className="mono" style={{ fontSize: '1rem', color: 'var(--info)' }}>{g.bunkerTotal}</span>
                        <span className="dim u-tiny">רמסע</span>
                      </div>
                      {g.redLine > 0 && (
                        <div className="stack" style={{ gap: 0, alignItems: 'center' }}>
                          <span className="mono" style={{ fontSize: '1rem', color: 'var(--text-3)' }}>{g.redLine}</span>
                          <span className="dim u-tiny">קו אדום</span>
                        </div>
                      )}
                    </div>
                    {pct !== null && (
                      <div className="bar">
                        <i style={{ width: pct + '%', background: crit ? 'var(--danger)' : pct < 40 ? 'var(--warn)' : 'var(--ok)' }} />
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          </div>
        </div>
      )}

      {/* Bottom section fills remaining height on PC */}
      <div className="split-2" style={{ flex: 1, minHeight: 0, alignItems: 'stretch' }}>
        <div className="section-card">
          <div className="section-header"><span className="section-title"><Icon name="layers" size={16} /> מצב צוותים</span><span className="dim u-tiny">{GUNS_A.length} צוותים</span></div>
          <div className="card-pad">
            <div className="grid-teams">
              {GUNS_A.map(g => <GunMiniCard key={g} state={state} gun={g} />)}
            </div>
          </div>
        </div>
        <ActivityFeed state={state} />
      </div>
    </div>
  );
}

/* ── App shell ──────────────────────────────────────────── */
const NAV = [
  { sec: 'ראשי', items: [{ id: 'overview', label: 'סקירה כללית', icon: 'grid' }] },
  { sec: 'מלאי', items: [
    { id: 'teams', label: 'מטריצת צוותים', icon: 'layers' },
    { id: 'bunker', label: 'מחסן ומשטחים', icon: 'box' },
    { id: 'barrel', label: 'בלאי קנה', icon: 'barrel' },
  ] },
  { sec: 'תיעוד', items: [
    { id: 'missions', label: 'יומן משימות אש', icon: 'target' },
    { id: 'transfers', label: 'יומן תנועות', icon: 'swap' },
    { id: 'quarantine', label: 'פינת פסולים', icon: 'ban' },
  ] },
  { sec: 'מערכת', items: [{ id: 'catalog', label: 'קטלוג תחמושת', icon: 'settings' }] },
];

const VIEW_TITLES = {
  overview: 'סקירה כללית', teams: 'מטריצת מלאי צוותים', bunker: 'מחסן ומשטחים', barrel: 'בלאי קנה',
  missions: 'יומן משימות אש', transfers: 'יומן תנועות מלאי', quarantine: 'פינת פסולים', catalog: 'קטלוג תחמושת מרכזי',
};

function App({ state, dispatch, loadingCloud, theme, onToggleTheme, onLogout }) {
  const [view, setView] = useStateA('overview');
  const [drawer, setDrawer] = useStateA(false);
  const [modal, setModal] = useStateA(null);
  const [adminModal, setAdminModal] = useStateA(null);
  const [resetConfirm, setResetConfirm] = useStateA(false);
  const [importFile, setImportFile] = useStateA(null);
  const [isOnline, setIsOnline] = useStateA(() => window.api.isOnline());
  const [offlinePending, setOfflinePending] = useStateA(() => window.api.hasOfflineQueue());
  const [syncing, setSyncing] = useStateA(false);
  const [toastNode, showToast] = useToast();

  const counts = {
    quarantine: (state.quarantineLog || []).length,
    bunker: (state.bunker || []).length,
    missions: (state.firingLog || []).length,
  };

  // Listen for sync conflict events from api.js
  useEffectA(() => {
    const handler = () => showToast('⚠ סנכרון: נמצאה גרסה חדשה יותר — התצוגה עודכנה');
    window.addEventListener('arty:sync-conflict', handler);
    return () => window.removeEventListener('arty:sync-conflict', handler);
  }, [showToast]);

  // Listen for online/offline status changes
  useEffectA(() => {
    const onStatus = (e) => setIsOnline(e.detail.online);
    const onQueued = () => setOfflinePending(true);
    const onBackOnline = () => {
      // Back online and there's a queue — show a prompt but don't auto-sync
      setIsOnline(true);
      showToast('חיבור שוחזר — לחץ "סנכרן שינויים" לשמירה');
    };
    window.addEventListener('arty:online-status', onStatus);
    window.addEventListener('arty:queued-offline', onQueued);
    window.addEventListener('arty:back-online', onBackOnline);
    return () => {
      window.removeEventListener('arty:online-status', onStatus);
      window.removeEventListener('arty:queued-offline', onQueued);
      window.removeEventListener('arty:back-online', onBackOnline);
    };
  }, [showToast]);

  const go = id => { setView(id); setDrawer(false); };
  const addPallet = (ammo, newTypes) => { dispatch({ type: 'ADD_PALLET', ammo, newTypes }); setModal(null); showToast('המשטח נקלט בהצלחה'); };

  // ── Export (admin only — uses cached token) ──────────────
  const handleExport = async () => {
    try {
      const d = await window.api.exportState();
      const blob = new Blob([JSON.stringify(d, null, 2)], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url; a.download = `arty-ammo-backup-${new Date().toISOString().slice(0, 10)}.json`; a.click();
      URL.revokeObjectURL(url);
      showToast('ייצוא הצליח');
    } catch (e) {
      showToast('שגיאה בייצוא — בדוק הרשאות', 'error');
    }
  };

  // ── Import (admin-gated) ──────────────────────────────────
  const handleImportFile = (e) => {
    const file = e.target.files?.[0]; if (!file) return;
    const reader = new FileReader();
    reader.onload = ev => {
      try { setImportFile(JSON.parse(ev.target.result)); setAdminModal('import'); }
      catch { showToast('קובץ לא תקין', 'error'); }
    };
    reader.readAsText(file);
  };

  const handleImport = async () => {
    if (!importFile) return;
    const payload = importFile.data || importFile;
    const ver = importFile.version || 0;
    try {
      await window.api.importState(payload, ver);
      dispatch({ type: 'IMPORT_STATE', payload: applyMigrationsA ? applyMigrationsA(payload) : payload });
      setAdminModal(null); setImportFile(null); showToast('ייבוא הצליח — המערכת עודכנה');
    } catch { showToast('שגיאה בייבוא — בדוק הרשאות', 'error'); }
  };

  const handleResetStep1 = () => {
    // Admin already authenticated — just confirm
    setAdminModal(null); setResetConfirm(true);
  };

  const handleResetConfirmed = async () => {
    const freshState = buildInitA();
    try {
      const r = await fetch(window.api.base() + '/state', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + window.api._token },
        body: JSON.stringify({ data: freshState, version: null }),
      });
      if (!r.ok) throw new Error('save failed: ' + r.status);
      window.api._version = 1;
    } catch (e) {
      console.error('[reset] DB write failed:', e.message);
      showToast('שגיאה בכתיבה ל-DB — נסה שוב', 'error');
      setResetConfirm(false); return;
    }
    dispatch({ type: 'RESET_STATE' });
    try { localStorage.clear(); } catch {}
    setResetConfirm(false);
    showToast('המערכת אופסה בהצלחה — כל הנתונים נמחקו');
  };

  // ── Manual sync of offline queue ─────────────────────────
  const handleSync = async () => {
    if (syncing || !isOnline) return;
    setSyncing(true);
    try {
      const result = await window.api.syncOfflineQueue();
      if (result.synced) {
        setOfflinePending(false);
        showToast('✓ השינויים סונכרנו בהצלחה');
      } else if (result.reason === 'still_offline') {
        showToast('עדיין אין חיבור — נסה שוב', 'error');
      } else if (result.reason === 'conflict_server_wins') {
        setOfflinePending(false);
        showToast('⚠ קונפליקט — המערכת עודכנה מהשרת');
      } else {
        showToast('שגיאה בסנכרון — נסה שוב', 'error');
      }
    } finally {
      setSyncing(false);
    }
  };

  return (
    <div className="app-shell">
      {/* ── Offline banner (topbar overlay) ── */}
      {!isOnline && (
        <div style={{
          position: 'fixed', top: 0, left: 0, right: 0, zIndex: 200,
          background: 'var(--warn)', color: '#fff',
          padding: '.35rem 1rem', textAlign: 'center',
          fontSize: '.8rem', fontWeight: 700, letterSpacing: '.02em',
        }}>
          ⚠ אין חיבור לרשת — שינויים נשמרים מקומית ויסונכרנו בחזרת החיבור
        </div>
      )}
      {/* ── Rail ── */}
      <aside className={'rail' + (drawer ? ' open' : '')} style={!isOnline ? { marginTop: '28px' } : undefined}>
        <div className="rail-brand">
          <div className="rail-logo"><Icon name="target" size={20} /></div>
          <div className="rail-brand-txt">
            <b>{(window.APP_CONFIG || {}).appName || 'ניהול תחמושת'}</b>
            <span>{(window.APP_CONFIG || {}).appShort || 'ARTY · AMMO'}</span>
          </div>
        </div>
        {/* Role badge */}
        {(() => {
          const role = window.api?.getRole();
          const m = ROLE_META[role] || null;
          return m ? (
            <div style={{ margin: '-.2rem 0 .4rem', padding: '.25rem .6rem', borderRadius: 'var(--r-full)',
              background: 'var(--surface-2)', border: '1px solid var(--border)',
              display: 'flex', alignItems: 'center', gap: '.4rem', fontSize: '.72rem', color: m.color }}>
              <span>{m.icon}</span><span style={{ fontWeight: 600 }}>{m.label}</span>
            </div>
          ) : null;
        })()}
        <nav className="rail-nav">
          {NAV.map(group => (
            <React.Fragment key={group.sec}>
              <div className="rail-sec">{group.sec}</div>
              {group.items.map(it => (
                <div key={it.id} className={'nav-item' + (view === it.id ? ' on' : '') + (it.id === 'quarantine' && counts.quarantine ? ' warn' : '')} onClick={() => go(it.id)}>
                  <span className="nav-ico"><Icon name={it.icon} /></span>
                  <span>{it.label}</span>
                  {counts[it.id] > 0 && <span className="nav-count">{counts[it.id]}</span>}
                </div>
              ))}
            </React.Fragment>
          ))}
        </nav>
        <div className="rail-foot">
          {/* Sync status line */}
          <div className="sync-line" style={{ color: !isOnline ? 'var(--warn)' : undefined }}>
            <Icon name={isOnline ? 'cloud' : 'bolt'} size={14} />
            {!isOnline
              ? 'לא מחובר — מצב לא מקוון'
              : loadingCloud
              ? 'מסנכרן…'
              : 'עדכון אחרון: ' + (state.lastUpdateTs ? fmtA(state.lastUpdateTs) : '—')}
          </div>

          {/* Sync button — shown when there are offline changes to push */}
          {offlinePending && (
            <button
              className="btn btn-sm"
              onClick={handleSync}
              disabled={syncing || !isOnline}
              style={{
                width: '100%', marginBottom: '.3rem', fontWeight: 700,
                background: isOnline ? 'var(--ok-soft)' : 'var(--warn-soft)',
                color: isOnline ? 'var(--ok)' : 'var(--warn)',
                border: '1px solid ' + (isOnline ? 'var(--ok-line)' : 'var(--warn-line)'),
                opacity: syncing ? .7 : 1,
              }}
              title={isOnline ? 'שמור שינויים שנאספו במצב לא מקוון' : 'ממתין לחיבור'}
            >
              {syncing ? '↻ מסנכרן…' : isOnline ? '↑ סנכרן שינויים' : '⏸ ממתין לחיבור'}
              {!syncing && <span style={{ marginRight: '.4rem', fontSize: '.68rem', opacity: .7 }}>•</span>}
            </button>
          )}

          {/* Export / Import / Reset — admin only */}
          {window.api?.isAdmin() && (
            <>
              <div className="row" style={{ gap: '.3rem', marginBottom: '.3rem' }}>
                <button className="btn btn-outline btn-sm grow" onClick={handleExport} title="ייצוא גיבוי JSON">
                  <Icon name="download" size={13} /> ייצוא
                </button>
                <label className="btn btn-outline btn-sm grow" style={{ cursor: 'pointer', textAlign: 'center' }} title="ייבוא מגיבוי">
                  <Icon name="upload" size={13} /> ייבוא
                  <input type="file" accept=".json" onChange={handleImportFile} style={{ display: 'none' }} />
                </label>
              </div>
              <button className="btn btn-sm" onClick={() => setAdminModal('reset')}
                style={{ width: '100%', marginBottom: '.3rem', background: 'var(--danger-soft)', color: 'var(--danger)', border: '1px solid var(--danger-line)', fontWeight: 700 }}>
                ⚠ איפוס מלא של המסד
              </button>
            </>
          )}
          <div className="row" style={{ gap: '.4rem' }}>
            <button className="btn btn-outline btn-sm grow" onClick={onToggleTheme}>
              <Icon name={theme === 'dark' ? 'sun' : 'moon'} size={15} /> {theme === 'dark' ? 'בהיר' : 'כהה'}
            </button>
            <button className="btn btn-ghost btn-sm" onClick={onLogout} title="התנתק"><Icon name="logout" size={15} /></button>
          </div>
        </div>
      </aside>
      <div className={'scrim' + (drawer ? ' show' : '')} onClick={() => setDrawer(false)} />

      {/* ── Main ── */}
      <main className="main">
        <header className="topbar">
          <button className="btn btn-ghost btn-icon menu-btn" onClick={() => setDrawer(true)}><Icon name="menu" /></button>
          <div className="stack">
            <h1>{VIEW_TITLES[view]}</h1>
            <span className="topbar-sub">משימת אש אחרונה: {state.lastFireMissionId || '—'}</span>
          </div>
          <div className="topbar-actions">
            {window.api?.canEdit() && <>
              <button className="btn btn-outline btn-sm" onClick={() => setModal('pallet')}><Icon name="plus" size={15} /><span className="lbl">משטח</span></button>
              <button className="btn btn-outline btn-sm" onClick={() => setModal('transfer')}><Icon name="swap" size={15} /><span className="lbl">ניוד</span></button>
              <button className="btn btn-outline btn-sm" onClick={() => setModal('stock')}><Icon name="box" size={15} /><span className="lbl">ערום</span></button>
              <button className="btn btn-primary btn-sm" onClick={() => setModal('fire')}><Icon name="target" size={15} /><span className="lbl">משימת אש</span></button>
            </>}
            {window.api?.isViewer() && (
              <span className="dim u-tiny" style={{ padding: '.3rem .6rem', background: 'var(--surface-2)', borderRadius: 'var(--r-full)', border: '1px solid var(--border)' }}>
                👁 מצב צפייה בלבד
              </span>
            )}
          </div>
        </header>

        <div className="content">
          {view === 'overview' && <OverviewView state={state} />}
          {view === 'teams' && <window.TeamsView state={state} dispatch={dispatch} />}
          {view === 'bunker' && <window.BunkerView state={state} dispatch={dispatch} onAddPallet={() => setModal('pallet')} />}
          {view === 'barrel' && <window.BarrelView state={state} dispatch={dispatch} />}
          {view === 'missions' && <window.MissionsView state={state} dispatch={dispatch} />}
          {view === 'transfers' && <window.TransfersView state={state} />}
          {view === 'quarantine' && <window.QuarantineSection state={state} regs={state.registeredTypes} dispatch={dispatch} />}
          {view === 'catalog' && <window.ConfigView state={state} dispatch={dispatch} />}
        </div>
      </main>

      {/* ── Modals ── */}
      {modal === 'fire' && <window.FireMissionModal state={state} dispatch={dispatch} onClose={() => setModal(null)} />}
      {modal === 'pallet' && <window.AddPalletModal nextId={state.nextPalletId} registeredTypes={state.registeredTypes} onClose={() => setModal(null)} onSubmit={addPallet} />}
      {modal === 'transfer' && <window.TransferModal state={state} dispatch={dispatch} onClose={() => setModal(null)} />}
      {modal === 'stock' && <window.EditGunStockModal state={state} dispatch={dispatch} onClose={() => setModal(null)} />}

      {/* ── Admin modals — no password re-entry (token cached in session) ── */}
      {adminModal === 'import' && importFile && (
        <ResetConfirmModal
          title="ייבוא גיבוי — אישור"
          message={<span>ייבוא יחליף את כל נתוני המערכת. הקלד <b>RESET</b> לאישור.</span>}
          onConfirm={handleImport}
          onCancel={() => { setAdminModal(null); setImportFile(null); }}
        />
      )}
      {adminModal === 'reset' && <ResetConfirmModal onConfirm={handleResetStep1} onCancel={() => setAdminModal(null)} />}
      {resetConfirm && <ResetConfirmModal onConfirm={handleResetConfirmed} onCancel={() => setResetConfirm(false)} />}

      {toastNode}
    </div>
  );
}

/* ── Admin password modal ────────────────────────────────── */
function AdminGate({ title, onSuccess, onCancel }) {
  const [code, setCode] = useStateA('');
  const [err, setErr] = useStateA('');
  const [working, setWorking] = useStateA(false);
  const attempt = async () => {
    if (!code || working) return;
    setWorking(true); setErr('');
    try { await onSuccess(code); }
    catch { setErr('קוד מנהל שגוי ⛔'); setCode(''); }
    finally { setWorking(false); }
  };
  return (
    <div className="modal-overlay" onClick={e => { if (e.target === e.currentTarget) onCancel(); }}>
      <div className="modal-box">
        <div className="section-header">
          <span className="section-title">🔐 {title}</span>
          <button className="btn btn-ghost btn-sm" onClick={onCancel}>✕</button>
        </div>
        <div className="modal-body stack" style={{ gap: '.85rem' }}>
          <div className="muted u-center u-sm">נדרש קוד מנהל (ADMIN_PASSWORD)</div>
          {err && <div className="callout callout-danger u-center u-bold">{err}</div>}
          <input type="password" value={code} onChange={e => setCode(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && attempt()} placeholder="הקלד קוד מנהל..." autoFocus
            style={{ textAlign: 'center', fontSize: '1rem', letterSpacing: '.15em' }} />
          <div className="row" style={{ gap: '.5rem', justifyContent: 'center' }}>
            <button className="btn btn-green" disabled={working || !code} onClick={attempt}>{working ? 'מאמת...' : '✔ אישור'}</button>
            <button className="btn btn-gray" onClick={onCancel}>ביטול</button>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── Full reset second-confirmation modal ────────────────── */
function ResetConfirmModal({ onConfirm, onCancel, title, message }) {
  const [typed, setTyped] = useStateA('');
  const ok = typed.trim() === 'RESET';
  return (
    <div className="modal-overlay" onClick={e => { if (e.target === e.currentTarget) onCancel(); }}>
      <div className="modal-box">
        <div className="section-header">
          <span className="section-title" style={{ color: 'var(--danger)' }}>⚠ {title || 'אישור סופי — איפוס מלא'}</span>
          <button className="btn btn-ghost btn-sm" onClick={onCancel}>✕</button>
        </div>
        <div className="modal-body stack" style={{ gap: '1rem' }}>
          <div className="callout callout-danger">
            {message || (<><b>כל הנתונים יימחקו לצמיתות מה-DB.</b><br />מלאי, משימות, תנועות, פסולים, בלאי קנים, קטלוג.<br /><b>פעולה זו אינה הפיכה.</b></>)}
          </div>
          <div className="form-group">
            <label style={{ color: 'var(--danger)', fontWeight: 700 }}>
              הקלד <span style={{ fontFamily: 'monospace', background: 'var(--danger-soft)', padding: '0 .4rem', borderRadius: '4px' }}>RESET</span> לאישור
            </label>
            <input type="text" value={typed} onChange={e => setTyped(e.target.value)}
              placeholder="RESET" autoFocus style={{ textAlign: 'center', fontFamily: 'monospace', fontSize: '1.1rem' }} />
          </div>
          <div className="row" style={{ gap: '.6rem', justifyContent: 'flex-end' }}>
            <button className="btn btn-gray" onClick={onCancel}>ביטול</button>
            <button className="btn btn-red" disabled={!ok} onClick={onConfirm}>⚠ אשר</button>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── Root: config + auth + state wiring ─────────────────── */
function AuthedApp({ theme, onToggleTheme, onLogout }) {
  const [loadingCloud, setLoadingCloud] = useStateA(true);
  const [state, dispatch] = useReducer(reducerA, null, () => buildInitA());

  useEffectA(() => { window.__appDispatch = dispatch; return () => { window.__appDispatch = null; }; }, [dispatch]);

  const cloudLoaded = useRefA(false);
  const firstMount  = useRefA(true);

  useEffectA(() => {
    window.__syncConflictToast = () => window.dispatchEvent(new CustomEvent('arty:sync-conflict'));
    return () => { window.__syncConflictToast = null; };
  }, []);

  useEffectA(() => {
    let alive = true;
    (async () => {
      try {
        const r = await window.api.loadState();
        if (alive && r && r.data) dispatch({ type: 'IMPORT_STATE', payload: applyMigrationsA(r.data) });
      } catch {}
      finally {
        if (alive) {
          cloudLoaded.current = true;
          setLoadingCloud(false);
          window.api.startPolling(30000);
        }
      }
    })();
    return () => { alive = false; window.api.stopPolling(); };
  }, []);

  useEffectA(() => {
    if (firstMount.current) { firstMount.current = false; return; }
    if (!cloudLoaded.current) return;
    // Only operators and admins save — viewers are read-only
    if (window.api.canEdit()) saveStateA(state);
  }, [state]);

  return <App state={state} dispatch={dispatch} loadingCloud={loadingCloud} theme={theme} onToggleTheme={onToggleTheme} onLogout={onLogout} />;
}

function Root() {
  const [ready, setReady]   = useStateA(false);
  const [authed, setAuthed] = useStateA(false);
  const [sessionExpired, setSessionExpired] = useStateA(false);
  const [theme, setTheme]   = useStateA(() => { try { return localStorage.getItem('arty_theme') || 'dark'; } catch { return 'dark'; } });

  useEffectA(() => { document.documentElement.setAttribute('data-theme', theme); try { localStorage.setItem('arty_theme', theme); } catch {} }, [theme]);
  const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark');

  useEffectA(() => {
    (async () => {
      try { await window.loadConfig(); } catch {}
      const session = window.api.restoreSession();
      if (session) setAuthed(true);
      setReady(true);
    })();
  }, []);

  // Handle midnight token expiry — show a "session expired, please log in again" notice
  useEffectA(() => {
    const handler = () => { setSessionExpired(true); setAuthed(false); };
    window.addEventListener('arty:session-expired', handler);
    return () => window.removeEventListener('arty:session-expired', handler);
  }, []);

  const logout = () => {
    window.api.stopPolling();
    window.api.logout();
    try { localStorage.clear(); } catch {}
    setAuthed(false);
    setSessionExpired(false);
  };

  if (!ready) return <div className="boot"><div className="boot-logo"><Icon name="target" size={28} /></div><span>טוען מערכת…</span></div>;
  if (!authed) return <LoginScreen onAuthed={() => { setAuthed(true); setSessionExpired(false); }} sessionExpired={sessionExpired} />;
  return <AuthedApp theme={theme} onToggleTheme={toggleTheme} onLogout={logout} />;
}

window.App = App;
window.Root = Root;
ReactDOM.createRoot(document.getElementById('root')).render(<Root />);
})();
