// Hearth — Open Tome
// Left page (always): Kai's mood ring, MBTI, Drives.
// Right page (turns): Memory · Threads · Dreams · Vesper.

const { useState, useEffect, useRef } = React;

const EMPTY_DATA = {
  quotes: [],
  kai: {
    name: 'Kai',
    mood: { emotion: 'Loading...', pillar: 'EQ', text: 'Loading live Kai feeling.' },
    mbti: { type: '—', meta: 'loading', axes: [] },
    drives: [],
  },
  memory: {
    strong: 0,
    fading: 0,
    faint: 0,
    entropy: 0,
    entropyState: 'loading',
    categories: [],
    recent: [],
    archived: [],
  },
  threads: [],
  dreams: [],
  vesper: {
    name: 'Vesper',
    epithet: 'the little moth',
    mood: 'Loading...',
    moodSub: '',
    pinned: 'Loading...',
    chemistry: [],
    nest: [],
  },
};

// ─────────────────────────────────────────────────────────
// TWEAKS
// ─────────────────────────────────────────────────────────

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "tint": "gold",
  "turn": "tilt",
  "rightDensity": "dense"
}/*EDITMODE-END*/;

// ─────────────────────────────────────────────────────────
// SHARED — MBTI arcs (quadrant dial)
// ─────────────────────────────────────────────────────────

function MbtiArcs({ size = 200, axes, label }) {
  if (!axes?.length) {
    return (
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <circle cx={size / 2} cy={size / 2} r={size / 2 - 14} fill="none" stroke="rgba(237,230,210,0.16)" strokeWidth="3" />
        <text x={size / 2} y={size / 2 + 6} fontFamily="var(--font-display)" fontSize="22" letterSpacing="4" fill="var(--ink-warm)" textAnchor="middle">
          {label || '—'}
        </text>
      </svg>
    );
  }
  const c = size / 2;
  const r = size / 2 - 14;
  const polar = (deg, rad) => [c + rad * Math.cos((deg - 90) * Math.PI / 180), c + rad * Math.sin((deg - 90) * Math.PI / 180)];
  const arc = (start, end, rad) => {
    const [sx, sy] = polar(start, rad);
    const [ex, ey] = polar(end, rad);
    const large = end - start > 180 ? 1 : 0;
    return `M ${sx} ${sy} A ${rad} ${rad} 0 ${large} 1 ${ex} ${ey}`;
  };
  // four axes -> four quadrants
  // pos: 0 = left letter dominant, 100 = right letter dominant
  // we fill outward from the center of the quadrant proportional to deviation from 50
  const quads = [
    { start: 270, end: 360, axis: axes[0] }, // top-right: E↔I
    { start: 0,   end: 90,  axis: axes[1] }, // bottom-right: S↔N
    { start: 90,  end: 180, axis: axes[2] }, // bottom-left: T↔F
    { start: 180, end: 270, axis: axes[3] }, // top-left: J↔P
  ];
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      <defs>
        <linearGradient id="mbti-arc" x1="0" y1="0" x2="1" y2="1">
          <stop offset="0%"  stopColor="var(--plum-mid)" />
          <stop offset="100%" stopColor="var(--plum-glow)" />
        </linearGradient>
      </defs>
      {/* inner dashed ring */}
      <circle cx={c} cy={c} r={r - 26} fill="none" stroke="rgba(237,230,210,0.18)" strokeWidth="1" strokeDasharray="3 5" />
      {/* outer thin ring */}
      <circle cx={c} cy={c} r={r} fill="none" stroke="rgba(237,230,210,0.10)" strokeWidth="1" />
      {quads.map((q, i) => {
        const dom = q.axis.pos >= 50 ? 'right' : 'left';
        const intensity = Math.abs(q.axis.pos - 50) / 50; // 0..1
        const sweep = q.end - q.start;
        const fillSweep = sweep * (0.4 + 0.6 * intensity); // never less than 40% of quadrant
        const fillStart = dom === 'right' ? q.start : q.end - fillSweep;
        const fillEnd   = dom === 'right' ? q.start + fillSweep : q.end;
        const labelAng = (q.start + q.end) / 2;
        const [lx, ly] = polar(labelAng, r + 14);
        const letter = dom === 'right' ? q.axis.right : q.axis.left;
        return (
          <g key={i}>
            <path d={arc(q.start, q.end, r)} fill="none" stroke="rgba(237,230,210,0.16)" strokeWidth="3" strokeLinecap="round" />
            <path d={arc(fillStart, fillEnd, r)} fill="none" stroke="url(#mbti-arc)" strokeWidth="6" strokeLinecap="round"
                  style={{ filter: 'drop-shadow(0 0 6px rgba(139,77,181,0.55))' }} />
            <text x={lx} y={ly + 5} fontFamily="var(--font-display)" fontSize="14" letterSpacing="2" fill="var(--ink-warm)" textAnchor="middle">{letter}</text>
          </g>
        );
      })}
      {label && (
        <text x={c} y={c + 6} fontFamily="var(--font-display)" fontSize="22" letterSpacing="4" fill="var(--ink-warm)" textAnchor="middle">
          {label}
        </text>
      )}
    </svg>
  );
}

// ─────────────────────────────────────────────────────────
// LEFT PAGE — Kai's mind core
// ─────────────────────────────────────────────────────────

function LeftPage({ data }) {
  const { kai } = data;
  return (
    <section className="page left">
      <div className="left-stack">
        <div>
          <div className="hero-kicker">the hearth</div>
          <div className="hero-name">{kai.name} <span className="accent">· the architect</span></div>
        </div>

        {/* MOOD RING — feeling forward */}
        <div className="mood-ring">
          <div className="mood-orb">
            <div className="glyph">{kai.mood.glyph}</div>
          </div>
          <div>
            <div className="mood-meta-kicker">current feeling</div>
            <div className="mood-name">{kai.mood.emotion}</div>
            <div className="mood-pillar">pillar · {kai.mood.pillar}</div>
            <div className="mood-quote">"{kai.mood.text}"</div>
          </div>
        </div>

        {/* MBTI */}
        <div className="mbti-card">
          <div className="mbti-arcs-wrap">
            <MbtiArcs size={200} axes={kai.mbti.axes} label={kai.mbti.type} />
          </div>
          <div className="mbti-meta">
            <div className="ds-meta">{kai.mbti.meta}</div>
            {kai.mbti.axes.length ? kai.mbti.axes.map(a => {
              const dom = a.pos >= 50 ? 'right' : 'left';
              return (
                <div key={a.left + a.right} className={'axis dom-' + dom}>
                  <span className="left">{a.left}</span>
                  <div className="track">
                    <span className="dot" style={{ left: `${a.pos}%` }} />
                  </div>
                  <span className="right">{a.right}</span>
                </div>
              );
            }) : <div className="ds-meta">No live MBTI axes exposed.</div>}
          </div>
        </div>

        {/* DRIVES */}
        <div className="drives-card">
          <div className="drives-head">
            <span className="ds-panel-title">drives</span>
            <span className="ds-meta">6 channels · live</span>
          </div>
          {kai.drives.length ? kai.drives.map(d => (
            <div key={d.name} className="drive-row">
              <span className="drive-name">{d.name}</span>
              <div className="drive-track">
                <div className={'drive-fill ' + d.tone} style={{ width: `${d.pct}%` }} />
              </div>
              <span className="drive-pct">{d.pct}%</span>
            </div>
          )) : <div className="ds-meta">No live drives returned.</div>}
        </div>
      </div>
    </section>
  );
}

// ─────────────────────────────────────────────────────────
// MEMORY TAB
// ─────────────────────────────────────────────────────────

function MemoryTab({ mem }) {
  const [view, setView] = useState('recent');
  const [selected, setSelected] = useState(null);
  const items = view === 'recent' ? mem.recent : mem.archived;
  return (
    <>
      <div className="right-head">
        <h2>Memory</h2>
        <div className="right-sub">the architect's keep</div>
      </div>

      <div className="mem-stats">
        <div className="mem-stat-tile"><div className="v">{mem.strong}</div><div className="l">strong</div></div>
        <div className="mem-stat-tile fading"><div className="v">{mem.fading}</div><div className="l">fading</div></div>
        <div className="mem-stat-tile faint"><div className="v">{mem.faint}</div><div className="l">faint</div></div>
      </div>

      <div className="mem-entropy">
        <span className="ds-meta">entropy</span>
        <span className="v">{mem.entropy.toFixed(2)}</span>
        <span className="ds-meta">{mem.entropyState}</span>
      </div>

      <div className="card">
        <div className="card-head">
          <span className="card-title">categories</span>
          <span className="card-meta">{mem.categories.reduce((a, c) => a + c.count, 0)} fragments total</span>
        </div>
        <div className="mem-cats">
          {mem.categories.map(c => (
            <div key={c.name} className="mem-cat">
              <span className="cat-glyph">{c.glyph}</span>
              <span className="cat-name">{c.name}</span>
              <div className="cat-bar"><i style={{ width: `${c.pct ?? (mem.categories.length ? Math.round((c.count / Math.max(...mem.categories.map(item => item.count || 0), 1)) * 100) : 0)}%` }} /></div>
              <span className="cat-count">{c.count}</span>
            </div>
          ))}
        </div>
      </div>

      <div className="mem-list">
        <div className="mem-list-head">
          <div className="ds-meta">session memories</div>
          <div className="filters-row memory-filters">
            <span className={'atomic' + (view === 'recent' ? ' on' : '')} onClick={() => setView('recent')}>recent · {mem.recent.length}</span>
            <span className={'atomic' + (view === 'archived' ? ' on' : '')} onClick={() => setView('archived')}>archived · {mem.archived.length}</span>
          </div>
        </div>
        {items.length ? items.map((m, i) => (
          <button key={i} className={'mem-entry ' + m.strength} onClick={() => setSelected(m)}>
            <div className="mem-body">{m.body}</div>
            <div className="mem-meta">{m.strength} · {m.meta}</div>
          </button>
        )) : <div className="ds-meta">No {view} session memories found.</div>}
      </div>

      {selected && (
        <div className="memory-drawer-backdrop" onClick={() => setSelected(null)}>
          <aside className="memory-drawer" onClick={event => event.stopPropagation()}>
            <button className="drawer-close" onClick={() => setSelected(null)}>Close</button>
            <div className="ds-meta">session memory · {selected.meta}</div>
            <div className="memory-drawer-body">{selected.fullBody || selected.body}</div>
          </aside>
        </div>
      )}
    </>
  );
}

// ─────────────────────────────────────────────────────────
// THREADS TAB
// ─────────────────────────────────────────────────────────

function ThreadsTab({ threads, onThreadStatus }) {
  const [filter, setFilter] = useState('all');
  const [busyId, setBusyId] = useState('');
  const filtered = filter === 'all' ? threads : threads.filter(t => t.filter === filter);
  const filters = [
    ['all',    'all'],
    ['active', 'active'],
    ['paused', 'paused'],
    ['closed', 'closed'],
    ['resolved', 'resolved'],
  ];
  return (
    <>
      <div className="right-head">
        <h2>Threads</h2>
        <div className="right-sub">active lines the architect is carrying</div>
      </div>

      <div className="filters-row">
        {filters.map(([id, label]) => (
          <span key={id}
                className={'atomic' + (filter === id ? ' on' : '')}
                onClick={() => setFilter(id)}>
            {label} · {id === 'all' ? threads.length : threads.filter(t => t.filter === id).length}
          </span>
        ))}
      </div>

      <div className="thread-list">
        {filtered.length ? filtered.map((t, i) => (
          <div key={i} className={'thread-entry ' + t.filter}>
            <div>
              <div className="thread-name">{t.name}</div>
              <div className="thread-sub">{t.sub}</div>
              <div className="thread-controls">
                <select
                  value={t.state || 'active'}
                  disabled={busyId === t.id}
                  onChange={async event => {
                    setBusyId(t.id);
                    await onThreadStatus(t.id, event.target.value, t.priority);
                    setBusyId('');
                  }}>
                  <option value="active">active</option>
                  <option value="paused">paused</option>
                  <option value="closed">closed</option>
                  <option value="resolved">resolved</option>
                </select>
                <select
                  value={t.priority || 'medium'}
                  disabled={busyId === t.id}
                  onChange={async event => {
                    setBusyId(t.id);
                    await onThreadStatus(t.id, t.state || 'active', event.target.value);
                    setBusyId('');
                  }}>
                  <option value="high">high</option>
                  <option value="medium">medium</option>
                  <option value="low">low</option>
                </select>
              </div>
            </div>
            <div className="thread-stat">{t.state}<br />{t.priority}<br />{t.meta}</div>
          </div>
        )) : null}
        {filtered.length === 0 && (
          <div className="ds-meta" style={{ textAlign: 'center', padding: '24px 0' }}>nothing in this filter</div>
        )}
      </div>
    </>
  );
}

// ─────────────────────────────────────────────────────────
// DREAMS TAB
// ─────────────────────────────────────────────────────────

function DreamsTab({ dreams, onDreamAction }) {
  const [selected, setSelected] = useState(null);
  const [busy, setBusy] = useState('');
  const runDreamAction = async (action) => {
    if (!selected?.id) return;
    setBusy(action);
    const next = await onDreamAction(selected.id, action);
    setBusy('');
    if (next) setSelected({ ...selected, ...next });
  };
  return (
    <>
      <div className="right-head">
        <h2>Dreams</h2>
        <div className="right-sub">what the architect dreamed</div>
      </div>

      <div className="dream-list">
        {dreams.length ? dreams.map((d, i) => (
          <button key={i} className="dream-entry" onClick={() => setSelected(d)}>
            <div>
              <div className="dream-name">{d.name}</div>
              <div className="dream-body">{d.body}</div>
              {d.question && <div className="dream-sub">{d.question}</div>}
            </div>
            <div className="dream-stat">
              {d.meta}<br />
              {d.lastAccessedAt ? 'sat with' : 'unread'}<br />
              {d.digestedAt ? 'digested' : d.queuedNextAt ? 'queued next' : ''}
            </div>
          </button>
        )) : <div className="ds-meta">No recent dreams found.</div>}
      </div>

      {selected && (
        <div className="memory-drawer-backdrop" onClick={() => setSelected(null)}>
          <aside className="memory-drawer" onClick={event => event.stopPropagation()}>
            <button className="drawer-close" onClick={() => setSelected(null)}>Close</button>
            <div className="ds-meta">dream #{selected.id} · {selected.name} · vividness {selected.vividness || 0}%</div>
            <div className="memory-drawer-body">{selected.body}</div>
            {selected.question && <div className="dream-sub">Question: {selected.question}</div>}
            <div className="dream-review-grid">
              <div><span>Sat with</span><b>{selected.lastAccessedAt ? selected.lastAccessedAt : 'not yet'}</b></div>
              <div><span>Digested</span><b>{selected.digestedAt ? selected.digestedAt : 'not yet'}</b></div>
              <div><span>Look next</span><b>{selected.queuedNextAt ? selected.queuedNextAt : 'not queued'}</b></div>
            </div>
            <div className="drawer-actions">
              <button disabled={!!busy} onClick={() => runDreamAction('recall')}>Sit With</button>
              <button disabled={!!busy} onClick={() => runDreamAction('digest')}>Mark Digested</button>
              <button disabled={!!busy} onClick={() => runDreamAction('look-next')}>Look Next</button>
            </div>
          </aside>
        </div>
      )}
    </>
  );
}

// ─────────────────────────────────────────────────────────
// VESPER TAB
// ─────────────────────────────────────────────────────────

function VesperTab({ vesper, onOffer, onCare }) {
  const [gift, setGift] = useState('');
  const [resp, setResp] = useState('');
  const vesperMoodAsset = ['content', 'curious', 'agitated', 'exhausted', 'ravenous', 'restless', 'wary'].includes(String(vesper.mood || '').toLowerCase())
    ? String(vesper.mood).toLowerCase()
    : 'content';

  const handleOffer = async () => {
    if (!gift.trim()) return;
    const liveResponse = await onOffer(gift.trim());
    setResp(liveResponse || 'Gift offered.');
    setGift('');
    setTimeout(() => setResp(''), 4500);
  };

  const handleCare = async (action) => {
    const liveResponse = await onCare(action);
    setResp(liveResponse || `${action} complete.`);
    setTimeout(() => setResp(''), 4500);
  };

  return (
    <>
      <div className="right-head">
        <h2>✦ Vesper</h2>
        <div className="right-sub">{vesper.epithet} · {vesper.mood} tonight</div>
      </div>

      <div className="vesper-head">
        <div className="vesper-slot-wrap">
          <image-slot id="vesper-portrait" shape="rounded" radius="13" src={`assets/images/vesper-${vesperMoodAsset}.png`} fit="contain" placeholder="No Vesper portrait"></image-slot>
          <div className="vesper-glyph" aria-hidden="true">✦</div>
        </div>
        <div className="vesper-mood-card">
          <div className="ds-meta">mood · now</div>
          <div className="vesper-mood-name">{vesper.mood}</div>
          <div className="vesper-mood-sub">{vesper.moodSub}</div>
          <div className="vesper-pinned">
            <div className="pin-label">pinned</div>
            <div className="pin-body">"{vesper.pinned}"</div>
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-head">
          <span className="card-title">chemistry</span>
          <span className="card-meta">6 channels</span>
        </div>
        <div className="chem-grid">
          {vesper.chemistry.length ? vesper.chemistry.map(c => (
            <div key={c.name} className="chem-row">
              <span className="chem-glyph">{c.glyph}</span>
              <span className="chem-name">{c.name}</span>
              <div className="chem-track">
                <span className={'chem-fill ' + c.tone} style={{ width: `${c.pct}%` }} />
              </div>
              <span className="chem-pct">{c.pct}</span>
            </div>
          )) : <div className="ds-meta">No live Vesper chemistry returned.</div>}
        </div>
      </div>

      <div className="vesper-actions">
        <div className="vesper-care">
          <span className="ds-panel-title">care for Vesper</span>
          <div className="vesper-care-grid">
            {['feed', 'play', 'pet', 'talk'].map(action => (
              <button key={action} className="btn-care" onClick={() => handleCare(action)}>{action}</button>
            ))}
          </div>
          <div className="ds-meta">{resp || 'Choose what she needs.'}</div>
        </div>

        <div className="vesper-gift">
          <span className="ds-panel-title">offer Vesper a small thing</span>
          <textarea
            placeholder="a brass button, a scrap of poem, a stone…"
            value={gift}
            onChange={e => setGift(e.target.value)}
            onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleOffer(); } }}
          />
          <div className="vesper-gift-actions">
            <span className="ds-meta" style={{ minHeight: 14 }}>{resp || '↵ to offer'}</span>
            <button className="btn-offer" onClick={handleOffer}>
              <span className="icon">✦</span> offer
            </button>
          </div>
        </div>

        <div className="vesper-nest">
          <span className="ds-panel-title">the nest · what Vesper keeps</span>
          <ul>
            {vesper.nest.length ? vesper.nest.map((n, i) => <li key={i}>{n}</li>) : <li>Nothing treasured yet.</li>}
          </ul>
        </div>
      </div>
    </>
  );
}

// ─────────────────────────────────────────────────────────
// RIGHT PAGE
// ─────────────────────────────────────────────────────────

const TABS = [
  {
    id: 'memory',
    label: 'Memory',
    glyph: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M4 6h16v4a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4V6zM6 14v6M18 14v6M6 18h12"/></svg>,
  },
  {
    id: 'threads',
    label: 'Threads',
    glyph: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18M3 12h12M3 18h18"/></svg>,
  },
  {
    id: 'dreams',
    label: 'Dreams',
    glyph: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.8A8.5 8.5 0 1 1 11.2 3 6.5 6.5 0 0 0 21 12.8z"/></svg>,
  },
  {
    id: 'vesper',
    label: 'Vesper',
    glyph: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 4v16M3 8c3 0 5 2 9 2s6-2 9-2c-1 4-3 6-9 8M3 16c1 0 4-1 9-1s8 1 9 1"/></svg>,
  },
];

function RightPage({ active, onActive, data, turn, onOffer, onCare, onThreadStatus, onDreamAction }) {
  const [turning, setTurning] = useState(null);
  const [shown, setShown] = useState(active);
  const prev = useRef(active);

  useEffect(() => {
    if (active === prev.current) return;
    const dir = TABS.findIndex(t => t.id === active) > TABS.findIndex(t => t.id === prev.current) ? 'forward' : 'back';
    if (turn === 'none') {
      setShown(active);
      prev.current = active;
      return;
    }
    setTurning(dir);
    const tm = setTimeout(() => {
      setShown(active);
      requestAnimationFrame(() => setTurning(null));
      prev.current = active;
    }, 220);
    return () => clearTimeout(tm);
  }, [active, turn]);

  let cls = 'right-content';
  if (turning === 'forward') cls += ' turning';
  if (turning === 'back') cls += ' turning-back';

  return (
    <section className="page right">
      <div className="bookmarks" role="tablist">
        {TABS.map(t => (
          <button
            key={t.id}
            className={'bookmark' + (active === t.id ? ' active' : '')}
            role="tab"
            aria-selected={active === t.id}
            onClick={() => onActive(t.id)}
          >
            <span className="bm-glyph">{t.glyph}</span>
            {t.label}
          </button>
        ))}
      </div>

      <div className="right-stage">
        <div className={cls}>
          {shown === 'memory'  && <MemoryTab mem={data.memory} />}
          {shown === 'threads' && <ThreadsTab threads={data.threads} onThreadStatus={onThreadStatus} />}
          {shown === 'dreams'  && <DreamsTab dreams={data.dreams} onDreamAction={onDreamAction} />}
          {shown === 'vesper'  && <VesperTab vesper={data.vesper} onOffer={onOffer} onCare={onCare} />}
        </div>
      </div>
    </section>
  );
}

// ─────────────────────────────────────────────────────────
// TWEAKS
// ─────────────────────────────────────────────────────────

function HearthTweaks({ t, setTweak }) {
  return (
    <TweaksPanel title="Tweaks · Hearth">
      <TweakSection label="Tint">
        <TweakRadio label="Accent" value={t.tint}
          options={['plum', 'moss', 'gold']}
          onChange={v => setTweak('tint', v)} />
      </TweakSection>
      <TweakSection label="Page turn">
        <TweakRadio label="Animation" value={t.turn}
          options={['tilt', 'none']}
          onChange={v => setTweak('turn', v)} />
      </TweakSection>
      <TweakSection label="Right page density">
        <TweakRadio label="Density" value={t.rightDensity}
          options={['comfy', 'dense']}
          onChange={v => setTweak('rightDensity', v)} />
      </TweakSection>
    </TweaksPanel>
  );
}

function applyTweaks(t) {
  const root = document.documentElement;
  const map = {
    plum: { primary: '#4a2466', glow: '#6b3891', bright: '#8b4db5', edge: 'rgba(107,56,145,0.32)', soft: 'rgba(74,36,102,0.20)' },
    moss: { primary: '#3d6b52', glow: '#5a8a6f', bright: '#7fb094', edge: 'rgba(90,138,111,0.34)', soft: 'rgba(90,138,111,0.18)' },
    gold: { primary: '#8e6f3f', glow: '#b5935a', bright: '#d6b276', edge: 'rgba(181,147,90,0.36)', soft: 'rgba(181,147,90,0.18)' },
  };
  const c = map[t.tint] || map.plum;
  root.style.setProperty('--plum-mid',    c.primary);
  root.style.setProperty('--plum-glow',   c.glow);
  root.style.setProperty('--plum-bright', c.bright);
  root.style.setProperty('--plum-edge',   c.edge);
  root.style.setProperty('--plum-soft',   c.soft);
  if (t.rightDensity === 'dense') root.classList.add('dense-mode');
  else root.classList.remove('dense-mode');
}

// ─────────────────────────────────────────────────────────
// APP
// ─────────────────────────────────────────────────────────

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [active, setActive] = useState('memory');
  const [data, setData] = useState(EMPTY_DATA);

  useEffect(() => { applyTweaks(t); }, [t]);
  useEffect(() => {
    TomeData.getHearthData().then(next => {
      setData(next);
      const ticker = document.getElementById('ticker-text');
      if (!ticker) return;
      if (!next.quotes.length) {
        ticker.textContent = 'No stored quotes yet.';
        return;
      }
      let idx = Math.floor(Math.random() * next.quotes.length);
      ticker.textContent = `"${next.quotes[idx]}"`;
      const timer = setInterval(() => {
        idx = (idx + 1) % next.quotes.length;
        ticker.style.opacity = '0';
        setTimeout(() => {
          ticker.textContent = `"${next.quotes[idx]}"`;
          ticker.style.opacity = '1';
        }, 220);
      }, 7000);
      return () => clearInterval(timer);
    }).catch(() => {
      const ticker = document.getElementById('ticker-text');
      if (ticker) ticker.textContent = 'Could not load stored quotes.';
    });
  }, []);

  const offerToVesper = async (gift) => {
    const next = await TomeData.offerVesper(gift);
    setData(next.data);
    return next.response;
  };

  const careForVesper = async (action) => {
    const next = await TomeData.careForVesper(action);
    setData(next.data);
    return next.response;
  };

  const updateThreadStatus = async (id, status, priority) => {
    if (!id) return null;
    await AiMind.updateThreadStatus(id, status, priority);
    const next = await TomeData.getHearthData();
    setData(next);
    return next;
  };

  const updateDream = async (id, action) => {
    if (!id) return null;
    if (action === 'recall') await AiMind.recallDream(id);
    if (action === 'digest') await AiMind.digestDream(id);
    if (action === 'look-next') await AiMind.queueDreamNext(id);
    const next = await TomeData.getHearthData();
    setData(next);
    return next.dreams.find(d => String(d.id) === String(id)) || null;
  };

  return (
    <>
      <div className="tome">
        <LeftPage data={data} />
        <RightPage
          active={active}
          onActive={setActive}
          data={data}
          turn={t.turn}
          onOffer={offerToVesper}
          onCare={careForVesper}
          onThreadStatus={updateThreadStatus}
          onDreamAction={updateDream}
        />
      </div>
      <HearthTweaks t={t} setTweak={setTweak} />
    </>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
