/* Noctua Ledger — app shell, persona switcher, scripted playback engine, tweaks */
(function () {
  const { useState, useRef, useEffect } = React;
  const lanes = window.LEDGER.lanes;
  const { Sheet, AgentCursor, ProposalFloat } = window.LedgerSheet;
  const { Rail } = window.LedgerRail;
  const DS = window.CircleBackDesignSystem_66b292;
  const { useTweaks, TweaksPanel, TweakSection, TweakRadio, TweakToggle } = window;

  const SPEED = { Calm: 1.5, Brisk: 1.0, Fast: 0.6 };
  const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
    "lane": "Finance",
    "speed": "Brisk",
    "density": "regular",
    "darkSheet": false,
    "reviewMode": "Review each",
    "showThinking": true
  }/*EDITMODE-END*/;

  const LANE_KEY = 'noctua_ledger_lane';

  function PlayIcon() { return React.createElement('svg', { width: 15, height: 15, viewBox: '0 0 24 24', fill: 'currentColor' }, React.createElement('path', { d: 'M8 5v14l11-7z' })); }
  function RefreshIcon() { return React.createElement('svg', { width: 14, height: 14, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2.2, strokeLinecap: 'round', strokeLinejoin: 'round' }, React.createElement('path', { d: 'M21 12a9 9 0 1 1-2.64-6.36M21 3v6h-6' })); }

  function App() {
    const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
    const lane = lanes.find((l) => l.dept === t.lane) || lanes[0];

    const [phase, setPhase] = useState('idle');
    const [progress, setProgress] = useState({});
    const [activeRow, setActiveRow] = useState(null);
    const [log, setLog] = useState([]);
    const [proposals, setProposals] = useState([]);
    const [cursor, setCursor] = useState({ x: 60, y: 60, hidden: true, label: '' });
    const [float, setFloat] = useState(null);

    const gridRef = useRef(null);
    const timers = useRef([]);
    const runRef = useRef(null);

    const speed = SPEED[t.speed] || 1;
    const after = (ms, fn) => { const id = setTimeout(fn, ms * speed); timers.current.push(id); };
    const clearTimers = () => { timers.current.forEach(clearTimeout); timers.current = []; };

    const cellPos = (rowId, colId) => {
      const g = gridRef.current; if (!g) return null;
      const cell = g.querySelector(`[data-cell="${rowId}:${colId}"]`);
      if (!cell) return null;
      const gr = g.getBoundingClientRect(); const cr = cell.getBoundingClientRect();
      return { left: cr.left - gr.left, top: cr.top - gr.top, w: cr.width, h: cr.height, gw: g.clientWidth, gh: g.clientHeight };
    };

    const reset = () => {
      clearTimers(); setPhase('idle'); setProgress({}); setActiveRow(null);
      setLog([]); setProposals([]); setFloat(null); setCursor((c) => ({ ...c, hidden: true }));
    };

    const maybeFinish = (next) => {
      if (next.length && next.every((p) => p.state !== 'pending')) {
        after(560, () => { setPhase('done'); setActiveRow(null); setFloat(null); setCursor((c) => ({ ...c, hidden: true }));
          setLog((L) => [...L, { kind: 'done', text: 'All changes applied. The ledger is reconciled.' }]); });
      }
    };

    const approve = (id) => {
      setProgress((pr) => (pr[id] ? { ...pr, [id]: { ...pr[id], phase: 'committed' } } : pr));
      setProposals((ps) => { const next = ps.map((p) => p.id === id ? { ...p, state: 'approved' } : p); maybeFinish(next); return next; });
    };
    const skip = (id) => {
      setProgress((pr) => { const c = { ...pr }; delete c[id]; return c; });
      setProposals((ps) => { const next = ps.map((p) => p.id === id ? { ...p, state: 'skipped' } : p); maybeFinish(next); return next; });
    };
    const approveAll = () => {
      setProgress((pr) => { const c = { ...pr }; Object.keys(c).forEach((k) => { c[k] = { ...c[k], phase: 'committed' }; }); return c; });
      setProposals((ps) => { const next = ps.map((p) => p.state === 'pending' ? { ...p, state: 'approved' } : p); maybeFinish(next); return next; });
    };

    const run = () => {
      clearTimers(); setProgress({}); setProposals([]); setFloat(null);
      setActiveRow(null); setCursor((c) => ({ ...c, hidden: true }));
      setPhase('scanning');
      setLog([{ kind: 'ask', text: lane.ask }]);
      const steps = lane.script;
      let delay = 520;
      steps.forEach((step) => {
        const startAt = delay;
        after(startAt, () => {
          setActiveRow(step.row);
          const p = cellPos(step.row, lane.workCol) || cellPos(step.row, lane.columns[0].id);
          if (p) setCursor({ x: p.left + 16, y: p.top + p.h * 0.5, hidden: false, label: 'reading' });
          if (t.showThinking) setLog((L) => [...L, { kind: step.kind === 'flag' ? 'flag' : 'think', text: step.think }]);
        });
        after(startAt + 880, () => {
          setProgress((pr) => ({ ...pr, [step.row]: { values: step.set, status: step.set.status, kind: step.kind, phase: 'pending' } }));
          setLog((L) => [...L, { kind: step.kind === 'flag' ? 'flag' : 'do', text: editText(step) }]);
          setProposals((ps) => [...ps, { id: step.row, kind: step.kind, sub: step.proposal.sub, from: step.proposal.from, to: step.proposal.to, note: step.proposal.note, state: 'pending' }]);
          const p = cellPos(step.row, lane.workCol);
          if (p) {
            setCursor({ x: p.left + p.w * 0.55, y: p.top + p.h * 0.5, hidden: false, label: 'writing' });
            if (t.showThinking) { const fy = Math.min(Math.max(p.top - 6, 6), Math.max(p.gh - 184, 6)); setFloat({ step, kind: step.kind, pos: { x: Math.max(p.gw - 286, 12), y: fy } }); }
          }
        });
        delay += 1880;
      });
      after(delay, () => {
        setActiveRow(null); setFloat(null); setCursor((c) => ({ ...c, hidden: true }));
        setLog((L) => [...L, { kind: 'do', text: `Scan complete — ${steps.length} changes staged for your review.` }]);
        if (t.reviewMode === 'Auto-apply') { setTimeout(() => approveAll(), 250); }
        else setPhase('review');
      });
    };
    runRef.current = run;

    // auto-play on mount and whenever the lane (persona) changes
    useEffect(() => {
      try { localStorage.setItem(LANE_KEY, t.lane); } catch (e) {}
      reset();
      const id = setTimeout(() => runRef.current(), 480);
      return () => { clearTimeout(id); clearTimers(); };
    // eslint-disable-next-line
    }, [t.lane]);

    // (activity feed auto-scrolls inside the Rail component)

    const viewRows = lane.rows.map((row) => {
      const prog = progress[row.id];
      const values = prog ? { ...row, ...prog.values } : row;
      const agentCols = prog ? Object.keys(prog.values).filter((k) => k !== 'status') : [];
      return { id: row.id, values, status: prog ? prog.status : row.status, agentCols,
        kind: prog ? prog.kind : null, phase: prog ? prog.phase : null, active: activeRow === row.id, prog: !!prog };
    });

    const pendingCount = proposals.filter((p) => p.state === 'pending').length;

    return React.createElement('div', { style: { display: 'flex', flexDirection: 'column', height: '100vh', background: 'var(--paper)' } },
      /* top bar */
      React.createElement('header', { style: { height: 56, flex: 'none', display: 'flex', alignItems: 'center', gap: 16,
        padding: '0 18px', background: 'rgba(246,242,233,.86)', backdropFilter: 'blur(10px)', borderBottom: '1px solid var(--border-soft)' } },
        React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 10 } },
          React.createElement('img', { src: (window.__resources && window.__resources.glyph) || 'ledger/assets/logo-glyph.svg', width: 26, height: 26, alt: 'Noctua' }),
          React.createElement('span', { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: '16px', letterSpacing: '-.02em', color: 'var(--ink-900)' } }, 'Noctua Ledger')),
        React.createElement('div', { style: { width: 1, height: 24, background: 'var(--border-soft)' } }),
        /* persona switcher */
        React.createElement('div', { style: { display: 'flex', gap: 7 } },
          lanes.map((l) => {
            const on = l.dept === t.lane;
            return React.createElement('button', { key: l.id, onClick: () => setTweak('lane', l.dept),
              title: `${l.persona.name} · ${l.flow}`,
              style: { display: 'flex', alignItems: 'center', gap: 8, padding: '6px 12px 6px 7px', borderRadius: 'var(--radius-pill)',
                cursor: 'pointer', border: on ? '1px solid var(--green-600)' : '1px solid var(--border-soft)',
                background: on ? 'var(--green-100)' : 'var(--surface)', transition: 'all .15s var(--ease-out)' } },
              React.createElement('span', { style: { width: 22, height: 22, borderRadius: '50%', flex: 'none',
                background: on ? 'var(--green-600)' : 'var(--ink-200)', color: on ? '#fff' : 'var(--ink-600)',
                display: 'grid', placeItems: 'center', fontFamily: 'var(--font-mono)', fontSize: '10px', fontWeight: 600 } }, l.persona.initials),
              React.createElement('span', { style: { display: 'flex', flexDirection: 'column', alignItems: 'flex-start', lineHeight: 1.1 } },
                React.createElement('span', { style: { fontFamily: 'var(--font-body)', fontWeight: 600, fontSize: '12.5px', color: on ? 'var(--green-700)' : 'var(--ink-700)' } }, l.persona.name),
                React.createElement('span', { style: { fontFamily: 'var(--font-mono)', fontSize: '9.5px', color: on ? 'var(--green-600)' : 'var(--ink-400)' } }, l.dept)));
          })),
        React.createElement('div', { style: { flex: 1 } }),
        React.createElement('div', { style: { fontFamily: 'var(--font-mono)', fontSize: '11px', color: 'var(--ink-400)' } },
          'powered by ', React.createElement('span', { style: { color: 'var(--green-600)', fontWeight: 600 } }, 'Claude')),
      ),

      /* sub bar — ask + flow + controls */
      React.createElement('div', { style: { flex: 'none', display: 'flex', alignItems: 'center', gap: 16, padding: '11px 18px',
        background: 'var(--surface)', borderBottom: '1px solid var(--border-soft)' } },
        React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 2, minWidth: 0 } },
          React.createElement('span', { style: { fontFamily: 'var(--font-mono)', fontSize: '10px', letterSpacing: '.1em', textTransform: 'uppercase', color: 'var(--ink-400)' } },
            lane.dept, ' · ', lane.flow),
          React.createElement('span', { style: { fontSize: '13.5px', color: 'var(--ink-800)', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } },
            '“', lane.ask, '”')),
        React.createElement('div', { style: { flex: 1 } }),
        React.createElement(FlowSteps, { lane, phase }),
        React.createElement('div', { style: { width: 1, height: 28, background: 'var(--border-soft)' } }),
        React.createElement('div', { style: { display: 'flex', gap: 8 } },
          phase === 'idle'
            ? React.createElement(DS.Button, { variant: 'primary', size: 'sm', onClick: () => run(), iconLeft: React.createElement(PlayIcon) }, 'Run ', lane.persona.name)
            : React.createElement(DS.Button, { variant: 'secondary', size: 'sm', onClick: () => run(), iconLeft: React.createElement(RefreshIcon) }, phase === 'scanning' ? 'Restart' : 'Run again'),
          (phase === 'review' && pendingCount > 0) && React.createElement(DS.Button, { variant: 'primary', size: 'sm', onClick: () => approveAll() }, `Approve all (${pendingCount})`))),

      /* work area */
      React.createElement('div', { style: { flex: 1, display: 'flex', minHeight: 0 } },
        /* thin nav rail */
        React.createElement('nav', { style: { width: 50, flex: 'none', background: 'var(--surface-2)', borderRight: '1px solid var(--border-soft)',
          display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6, padding: '14px 0' } },
          [0, 1, 2, 3].map((i) => React.createElement('span', { key: i, style: { width: 30, height: 30, borderRadius: 'var(--radius-sm)',
            background: i === 1 ? 'var(--green-100)' : 'transparent', border: i === 1 ? '1px solid var(--green-200)' : '1px solid transparent',
            display: 'grid', placeItems: 'center' } },
            React.createElement('span', { style: { width: 15, height: 15, borderRadius: 4, border: `1.6px solid ${i === 1 ? 'var(--green-600)' : 'var(--ink-300)'}` } })))),

        /* grid + overlay */
        React.createElement('div', { style: { position: 'relative', flex: 1, display: 'flex', minWidth: 0, background: t.darkSheet ? 'var(--ink-900)' : 'var(--surface)' } },
          React.createElement(Sheet, { ref: gridRef, lane, viewRows, density: t.density, dark: t.darkSheet }),
          React.createElement('div', { style: { position: 'absolute', inset: 0, pointerEvents: 'none', overflow: 'hidden' } },
            t.showThinking && React.createElement(ProposalFloat, { pos: float ? float.pos : { x: -400, y: 0 }, step: float ? float.step : null, kind: float ? float.kind : 'match', persona: lane.persona.name }),
            React.createElement(AgentCursor, { pos: { x: cursor.x, y: cursor.y }, name: lane.persona.name, label: cursor.label, hidden: cursor.hidden }))),

        /* right rail */
        React.createElement(Rail, { lane, phase, log, proposals, onApprove: approve, onSkip: skip, onApproveAll: approveAll })),

      /* tweaks */
      React.createElement(TweaksPanel, null,
        React.createElement(TweakSection, { label: 'Agent & flow' }),
        React.createElement(TweakRadio, { label: 'Department', value: t.lane, options: ['Finance', 'Procurement', 'Operations'], onChange: (v) => setTweak('lane', v) }),
        React.createElement(TweakRadio, { label: 'Run speed', value: t.speed, options: ['Calm', 'Brisk', 'Fast'], onChange: (v) => setTweak('speed', v) }),
        React.createElement(TweakSection, { label: 'Review' }),
        React.createElement(TweakRadio, { label: 'Approvals', value: t.reviewMode, options: ['Review each', 'Auto-apply'], onChange: (v) => setTweak('reviewMode', v) }),
        React.createElement(TweakToggle, { label: 'Show agent reasoning', value: t.showThinking, onChange: (v) => setTweak('showThinking', v) }),
        React.createElement(TweakSection, { label: 'Sheet' }),
        React.createElement(TweakRadio, { label: 'Density', value: t.density, options: ['compact', 'regular', 'comfy'], onChange: (v) => setTweak('density', v) }),
        React.createElement(TweakToggle, { label: 'Dark sheet', value: t.darkSheet, onChange: (v) => setTweak('darkSheet', v) })));
  }

  function editText(step) {
    const who = (step.proposal.sub.split(' · ')[0] || '').trim();
    return step.kind === 'flag' ? `${who} — ${step.proposal.to}` : `${who} → ${step.proposal.to}`;
  }

  function FlowSteps({ lane, phase }) {
    return React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 6 } },
      lane.flowSteps.map((s, i) => React.createElement(React.Fragment, { key: s },
        i > 0 && React.createElement('span', { style: { color: 'var(--ink-300)', fontSize: '11px' } }, '→'),
        React.createElement('span', { style: { fontFamily: 'var(--font-mono)', fontSize: '10.5px', letterSpacing: '.03em',
          padding: '4px 9px', borderRadius: 'var(--radius-pill)', whiteSpace: 'nowrap',
          background: i === lane.flowSteps.length - 1 ? 'var(--green-100)' : 'var(--ink-100)',
          color: i === lane.flowSteps.length - 1 ? 'var(--green-700)' : 'var(--ink-500)', fontWeight: 600 } }, s))));
  }

  ReactDOM.createRoot(document.getElementById('ledger-app')).render(React.createElement(App));
})();
