// recall.jsx — Active recall & spaced repetition tab (Leitner board)
const rcFontHead = `'Fraunces', Georgia, serif`;
const rcFontBody = `'Geist', system-ui, sans-serif`;
const rcFontMono = `'JetBrains Mono', monospace`;

function useSRS() {
  const [, bump] = React.useState(0);
  React.useEffect(() => {
    const on = () => bump(v => v + 1);
    window.addEventListener('medhub:srs', on);
    return () => window.removeEventListener('medhub:srs', on);
  }, []);
  return window.SRS;
}

function dueLabel(e) {
  const S = window.SRS;
  if (!e || !e.due) return 'Not scheduled';
  const n = S.daysUntil(e);
  if (n < 0) return `Overdue ${-n} day${n === -1 ? '' : 's'}`;
  if (n === 0) return 'Due today';
  if (n === 1) return 'Due tomorrow';
  return `Due in ${n} days`;
}

function dueTone(e, palette) {
  const S = window.SRS;
  if (!e || !e.due) return palette.inkSoft;
  const n = S.daysUntil(e);
  if (n < 0) return palette.accent1;
  if (n === 0) return palette.accent3;
  return palette.inkSoft;
}

function RcPill({ children, onClick, palette, tone, solid, title, disabled }) {
  const c = tone || palette.accent1;
  return (
    <button onClick={onClick} title={title} disabled={disabled} style={{
      background: solid ? c : palette.surface, color: solid ? '#fff' : palette.ink,
      border: `1px solid ${solid ? c : palette.ink + '20'}`, borderRadius: 999,
      padding: '6px 12px', fontSize: 12, fontWeight: 600, fontFamily: rcFontBody,
      cursor: disabled ? 'default' : 'pointer', opacity: disabled ? .45 : 1,
      whiteSpace: 'nowrap', flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 6,
    }}>{children}</button>
  );
}

function RcStat({ label, value, palette, tone }) {
  return (
    <div style={{ background: palette.surface, border: `1px solid ${palette.ink}10`, borderRadius: 14, padding: '12px 16px', minWidth: 96 }}>
      <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '.1em', textTransform: 'uppercase', color: palette.inkSoft }}>{label}</div>
      <div style={{ fontFamily: rcFontHead, fontSize: 30, lineHeight: 1.1, marginTop: 4, fontVariantNumeric: 'tabular-nums', color: tone || palette.ink }}>{value}</div>
    </div>
  );
}

function RecallCard({ chat, entry, palette, onStudy, onStart, onMove, onRemove }) {
  const d = window.MED_DATA;
  const S = window.SRS;
  const Icon = window.SYSTEM_ICONS[chat.system] || window.PillIcon;
  const [menu, setMenu] = React.useState(false);
  const sysLabel = d.systems.find(s => s.id === chat.system)?.label || 'Other';
  const reps = (entry.history || []).filter(h => h.a === 'got' || h.a === 'forgot').length;
  return (
    <div style={{ background: palette.surface, border: `1px solid ${S.isDue(entry) ? palette.accent1 + '55' : palette.ink + '12'}`,
                  borderRadius: 12, padding: 10, display: 'grid', gap: 8 }}>
      <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start' }}>
        <div style={{ width: 26, height: 26, borderRadius: 7, background: palette.chip, display: 'grid', placeItems: 'center', flexShrink: 0 }}>
          <Icon size={17} color={palette[window.SYSTEM_ACCENT[chat.system]]} stroke={palette.ink}/>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 500, lineHeight: 1.3, textWrap: 'pretty' }}>{chat.title}</div>
          <div style={{ fontSize: 10.5, color: palette.inkSoft, marginTop: 3 }}>{sysLabel}{reps ? ` · ${reps} rep${reps === 1 ? '' : 's'}` : ''}</div>
        </div>
        <button onClick={() => setMenu(m => !m)} title="Options" style={{
          background: 'transparent', border: 0, color: palette.inkSoft, cursor: 'pointer',
          fontSize: 15, lineHeight: 1, padding: '0 2px', flexShrink: 0,
        }}>⋯</button>
      </div>
      <div style={{ fontSize: 11, fontWeight: 600, color: dueTone(entry, palette), fontFamily: rcFontMono }}>{dueLabel(entry)}</div>
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
        {entry.box === 0
          ? <RcPill palette={palette} solid tone={palette.accent3} onClick={onStart}>Start learning</RcPill>
          : <RcPill palette={palette} solid={S.isDue(entry)} tone={palette.accent1} onClick={onStudy}>{S.isDue(entry) ? 'Review now' : 'Open'}</RcPill>}
      </div>
      {menu && (
        <div style={{ borderTop: `1px solid ${palette.ink}12`, paddingTop: 8, display: 'grid', gap: 6 }}>
          <label style={{ fontSize: 10.5, color: palette.inkSoft, display: 'grid', gap: 4 }}>
            Move to box
            <select value={entry.box} onChange={e => { onMove(parseInt(e.target.value, 10)); setMenu(false); }} style={{
              background: palette.bg, color: palette.ink, border: `1px solid ${palette.ink}20`,
              borderRadius: 8, padding: '5px 6px', font: 'inherit', fontSize: 12,
            }}>
              {S.BOXES.map(b => <option key={b.id} value={b.id}>{b.label}</option>)}
            </select>
          </label>
          <RcPill palette={palette} onClick={() => { onRemove(); setMenu(false); }}>Remove from plan</RcPill>
        </div>
      )}
    </div>
  );
}

function StudyPanel({ chatId, palette, onClose, nav }) {
  const S = useSRS();
  const d = window.MED_DATA;
  const chat = d.chats.find(c => c.id === chatId);
  const entry = S.get(chatId);
  const isMobile = window.useIsMobile();
  const [note, setNote] = React.useState(entry?.note || '');
  const [showHistory, setShowHistory] = React.useState(false);
  React.useEffect(() => { setNote(S.get(chatId)?.note || ''); }, [chatId]);
  if (!chat || !entry) return null;
  const nextBox = Math.min(5, (entry.box || 0) + 1);
  const downBox = Math.max(1, (entry.box || 1) - 1);
  const hist = [...(entry.history || [])].reverse();

  function act(kind) {
    if (note !== (entry.note || '')) S.setNote(chatId, note);
    if (kind === 'got') S.pass(chatId); else S.fail(chatId);
    onClose();
  }

  return (
    <div style={{ display: 'grid', gap: 12 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
        <RcPill palette={palette} onClick={onClose}>← Back to board</RcPill>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '.1em', textTransform: 'uppercase', color: palette.inkSoft }}>
            Box {entry.box} · {S.boxLabel(entry.box)} · {dueLabel(entry)}
          </div>
          <div style={{ fontFamily: rcFontHead, fontSize: isMobile ? 18 : 22, fontWeight: 500, lineHeight: 1.2 }}>{chat.title}</div>
        </div>
        <RcPill palette={palette} onClick={() => setShowHistory(h => !h)}>{showHistory ? 'Hide' : 'History'} ({hist.length})</RcPill>
        <RcPill palette={palette} onClick={() => nav('chat', chat.id)}>Full page ↗</RcPill>
      </div>

      {showHistory && (
        <div style={{ background: palette.surface, border: `1px solid ${palette.ink}12`, borderRadius: 12, padding: 12, maxHeight: 200, overflow: 'auto' }}>
          {hist.length === 0 && <div style={{ fontSize: 12, color: palette.inkSoft }}>No repetitions logged yet.</div>}
          <div style={{ display: 'grid', gap: 6 }}>
            {hist.map((h, i) => (
              <div key={i} style={{ display: 'flex', gap: 10, alignItems: 'baseline', fontSize: 12, fontFamily: rcFontMono, color: palette.ink }}>
                <span style={{ color: palette.inkSoft, minWidth: 84 }}>{h.d}</span>
                <span style={{ fontWeight: 600, color: h.a === 'forgot' ? palette.accent1 : h.a === 'got' ? palette.accent4 || palette.accent3 : palette.inkSoft, minWidth: 62 }}>
                  {h.a === 'got' ? 'Got it' : h.a === 'forgot' ? 'Forgot' : h.a === 'start' ? 'Started' : 'Moved'}
                </span>
                <span style={{ color: palette.inkSoft }}>→ box {h.box}{h.due ? ` · next ${h.due}` : ''}</span>
              </div>
            ))}
          </div>
        </div>
      )}

      <div style={{ background: palette.surface, border: `1px solid ${palette.ink}15`, borderRadius: 16, overflow: 'hidden' }}>
        <iframe src={`chats/${chat.file}`} title={chat.title}
                style={{ width: '100%', height: isMobile ? 'calc(100vh - 330px)' : 'calc(100vh - 340px)', minHeight: isMobile ? 360 : 460,
                         border: 0, display: 'block', background: '#fff',
                         filter: palette.name === 'Midnight' ? 'invert(1) hue-rotate(180deg)' : 'none' }}/>
      </div>

      <textarea value={note} onChange={e => setNote(e.target.value)} onBlur={() => S.setNote(chatId, note)}
                placeholder="Notes for this repetition — what tripped you up?"
                style={{ width: '100%', minHeight: 60, background: palette.surface, color: palette.ink,
                         border: `1px solid ${palette.ink}15`, borderRadius: 12, padding: 10,
                         font: `13px/1.5 ${rcFontBody}`, resize: 'vertical', outline: 'none' }}/>

      <div style={{ position: 'sticky', bottom: 0, background: palette.bg, borderTop: `1px solid ${palette.ink}12`,
                    padding: '12px 0', display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap' }}>
        <button onClick={() => act('got')} style={{
          background: palette.accent4 || palette.accent3, color: '#2A1810', border: 0, borderRadius: 999,
          padding: '11px 22px', fontSize: 14, fontWeight: 700, cursor: 'pointer', fontFamily: rcFontBody, flexShrink: 0,
        }}>✓ Got it → {S.BOXES[nextBox].label}</button>
        <button onClick={() => act('forgot')} style={{
          background: palette.accent1, color: '#2A1810', border: 0, borderRadius: 999,
          padding: '11px 22px', fontSize: 14, fontWeight: 700, cursor: 'pointer', fontFamily: rcFontBody, flexShrink: 0,
        }}>↺ Forgot → {S.BOXES[downBox].label}</button>
        <RcPill palette={palette} onClick={onClose}>Skip for now</RcPill>
      </div>
    </div>
  );
}

function RecallCalendar({ palette, nav }) {
  const S = useSRS();
  const d = window.MED_DATA;
  const plan = S.all();
  const today = S.todayStr();
  const byDay = {};
  let overdue = 0;
  for (const id in plan) {
    const e = plan[id];
    if (!e.due) continue;
    const n = S.diffDays(today, e.due);
    if (n < 0) { overdue++; continue; }
    (byDay[e.due] = byDay[e.due] || []).push(id);
  }
  const start = S.addDays(today, -((S.parse(today).getDay() + 6) % 7));
  const weeks = [];
  for (let w = 0; w < 9; w++) weeks.push(Array.from({ length: 7 }, (_, i) => S.addDays(start, w * 7 + i)));
  const [sel, setSel] = React.useState(null);
  const selIds = sel ? (byDay[sel] || []) : [];

  return (
    <div style={{ display: 'grid', gap: 14 }}>
      {overdue > 0 && (
        <div style={{ fontSize: 12.5, color: palette.accent1, fontWeight: 600 }}>{overdue} overdue chat{overdue === 1 ? '' : 's'} waiting — they show up in Due now.</div>
      )}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 4 }}>
        {['Mon','Tue','Wed','Thu','Fri','Sat','Sun'].map(l => (
          <div key={l} style={{ fontSize: 10, fontWeight: 700, letterSpacing: '.08em', textTransform: 'uppercase', color: palette.inkSoft, textAlign: 'center', paddingBottom: 2 }}>{l}</div>
        ))}
        {weeks.flat().map(day => {
          const n = (byDay[day] || []).length;
          const isToday = day === today;
          const past = S.diffDays(today, day) < 0;
          return (
            <button key={day} onClick={() => setSel(n ? day : null)} style={{
              background: n ? palette.accent1 : palette.surface,
              color: n ? '#fff' : past ? palette.inkSoft + '80' : palette.ink,
              border: `1px solid ${isToday ? palette.ink : palette.ink + '12'}`,
              borderWidth: isToday ? 2 : 1, borderRadius: 10, padding: '7px 4px', cursor: n ? 'pointer' : 'default',
              font: 'inherit', display: 'grid', gap: 2, opacity: n || isToday ? 1 : .75,
            }}>
              <span style={{ fontSize: 12, fontVariantNumeric: 'tabular-nums', fontWeight: isToday ? 700 : 500 }}>{Number(day.slice(8))}</span>
              <span style={{ fontSize: 10, opacity: .85, minHeight: 12 }}>{n ? `${n}` : ''}</span>
            </button>
          );
        })}
      </div>
      {sel && (
        <div style={{ background: palette.surface, border: `1px solid ${palette.ink}12`, borderRadius: 14, padding: 14 }}>
          <div style={{ fontFamily: rcFontHead, fontSize: 18, marginBottom: 8 }}>{sel} · {selIds.length} chat{selIds.length === 1 ? '' : 's'}</div>
          <div style={{ display: 'grid', gap: 6 }}>
            {selIds.map(id => {
              const c = d.chats.find(x => x.id === id);
              if (!c) return null;
              return (
                <button key={id} onClick={() => nav('chat', id)} style={{
                  background: palette.bg, border: `1px solid ${palette.ink}12`, borderRadius: 10, padding: '8px 10px',
                  textAlign: 'left', cursor: 'pointer', font: 'inherit', fontSize: 13, color: palette.ink,
                  display: 'flex', justifyContent: 'space-between', gap: 10,
                }}>
                  <span>{c.title}</span>
                  <span style={{ color: palette.inkSoft, fontSize: 11, fontFamily: rcFontMono, flexShrink: 0 }}>box {plan[id].box}</span>
                </button>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

function RecallView({ nav, palette }) {
  const S = useSRS();
  const d = window.MED_DATA;
  const isMobile = window.useIsMobile();
  const [view, setView] = React.useState('board');
  const [studyId, setStudyId] = React.useState(null);
  const [q, setQ] = React.useState('');
  const fileRef = React.useRef(null);

  const plan = S.all();
  const counts = S.counts();
  const st = S.streak();
  const chatOf = id => d.chats.find(c => c.id === id);
  const match = id => { const c = chatOf(id); return c && (!q.trim() || c.title.toLowerCase().includes(q.toLowerCase())); };
  const inBox = box => Object.keys(plan).filter(id => (plan[id].box || 0) === box && match(id))
    .sort((a, b) => (plan[a].due || '9') < (plan[b].due || '9') ? -1 : 1);
  const dueIds = S.dueList().filter(match);

  function doExport() {
    const blob = new Blob([S.exportJSON()], { type: 'application/json' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = `repetition-plan-${S.todayStr()}.json`;
    a.click();
    setTimeout(() => URL.revokeObjectURL(a.href), 2000);
  }
  function doImport(e) {
    const f = e.target.files?.[0]; if (!f) return;
    const r = new FileReader();
    r.onload = () => { try { const n = S.importJSON(String(r.result), 'merge'); alert(`Imported ${n} chats into your plan.`); } catch { alert('That file could not be read as a repetition plan.'); } };
    r.readAsText(f);
    e.target.value = '';
  }

  const cardProps = id => ({
    chat: chatOf(id), entry: plan[id], palette,
    onStudy: () => setStudyId(id),
    onStart: () => S.start(id),
    onMove: box => S.moveTo(id, box),
    onRemove: () => S.remove(id),
  });

  return (
    <div style={{ background: palette.bg, color: palette.ink, fontFamily: rcFontBody, minHeight: '100%' }}>
      <window.BackBar nav={nav} palette={palette} subtitle="Active recall" title="Repetition boxes"
        right={
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            <RcPill palette={palette} onClick={() => nav('home')} title="Add chats from your library">＋ Add from library</RcPill>
            <RcPill palette={palette} onClick={doExport}>⬇ Export</RcPill>
            <RcPill palette={palette} onClick={() => fileRef.current?.click()}>⬆ Import</RcPill>
            <input ref={fileRef} type="file" accept="application/json,.json" onChange={doImport} style={{ display: 'none' }}/>
          </div>
        }/>

      <div style={{ padding: isMobile ? '16px 14px 60px' : '22px 32px 60px', maxWidth: 1400, margin: '0 auto' }}>
        {studyId ? (
          <StudyPanel chatId={studyId} palette={palette} nav={nav} onClose={() => setStudyId(null)}/>
        ) : (
          <>
            <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 16 }}>
              <RcStat label="Due now" value={counts.due} palette={palette} tone={counts.due ? palette.accent1 : undefined}/>
              <RcStat label="Overdue" value={counts.overdue} palette={palette} tone={counts.overdue ? palette.accent1 : undefined}/>
              <RcStat label="In plan" value={counts.total - counts.waitlist} palette={palette}/>
              <RcStat label="Waitlist" value={counts.waitlist} palette={palette}/>
              <RcStat label="Day streak" value={st.count} palette={palette} tone={st.count ? palette.accent3 : undefined}/>
            </div>

            <div style={{ display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap', marginBottom: 16 }}>
              <div style={{ display: 'flex', gap: 4, padding: 4, background: palette.chip, borderRadius: 999 }}>
                {[{ id: 'board', label: 'Boxes' }, { id: 'due', label: `Due now${counts.due ? ` · ${counts.due}` : ''}` }, { id: 'calendar', label: 'Calendar' }].map(t => (
                  <button key={t.id} onClick={() => setView(t.id)} style={{
                    background: view === t.id ? palette.surface : 'transparent', color: palette.ink, border: 0,
                    borderRadius: 999, padding: '6px 14px', cursor: 'pointer', fontSize: 13,
                    fontWeight: view === t.id ? 600 : 500, fontFamily: rcFontBody, whiteSpace: 'nowrap',
                    boxShadow: view === t.id ? `0 1px 3px ${palette.ink}15` : 'none',
                  }}>{t.label}</button>
                ))}
              </div>
              {view !== 'calendar' && (
                <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search chats in your plan…"
                       style={{ flex: isMobile ? '1 1 100%' : '0 0 260px', padding: '9px 14px', borderRadius: 999,
                                border: `1px solid ${palette.ink}20`, background: palette.surface, color: palette.ink,
                                font: 'inherit', fontSize: 13, outline: 'none' }}/>
              )}
            </div>

            {counts.total === 0 ? (
              <div style={{ background: palette.surface, border: `1px dashed ${palette.ink}25`, borderRadius: 18,
                            padding: isMobile ? 24 : 40, textAlign: 'center', maxWidth: 620, margin: '20px auto' }}>
                <div style={{ fontFamily: rcFontHead, fontSize: 24, marginBottom: 8 }}>Your boxes are empty</div>
                <p style={{ color: palette.inkSoft, fontSize: 14, lineHeight: 1.6, margin: '0 0 16px' }}>
                  Add chats from your library with the ⟳ button on any list row. They land in the waitlist,
                  and once you press <em>Start learning</em> the ladder begins: +1 day, then +2, +5, +7 and +30.
                </p>
                <RcPill palette={palette} solid onClick={() => nav('home')}>Go to library</RcPill>
              </div>
            ) : view === 'calendar' ? (
              <RecallCalendar palette={palette} nav={nav}/>
            ) : view === 'due' ? (
              dueIds.length === 0 ? (
                <div style={{ padding: 40, textAlign: 'center', color: palette.inkSoft, fontSize: 14 }}>
                  Nothing due right now. Next up: {(() => {
                    const up = Object.keys(plan).filter(id => plan[id].due).sort((a, b) => plan[a].due < plan[b].due ? -1 : 1)[0];
                    return up ? `${chatOf(up)?.title} on ${plan[up].due}` : '—';
                  })()}
                </div>
              ) : (
                <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(auto-fill, minmax(260px, 1fr))', gap: 10 }}>
                  {dueIds.map(id => <RecallCard key={id} {...cardProps(id)}/>)}
                </div>
              )
            ) : (
              <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(6, minmax(210px, 1fr))',
                            gap: 12, overflowX: isMobile ? 'visible' : 'auto', alignItems: 'start', paddingBottom: 8 }}>
                {S.BOXES.map(b => {
                  const ids = inBox(b.id);
                  return (
                    <div key={b.id} style={{ background: palette.chip + '80', border: `1px solid ${palette.ink}10`,
                                             borderRadius: 16, padding: 10, display: 'grid', gap: 10, alignContent: 'start' }}>
                      <div>
                        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 }}>
                          <span style={{ fontFamily: rcFontHead, fontSize: 17, fontWeight: 500 }}>{b.label}</span>
                          <span style={{ fontSize: 12, color: palette.inkSoft, fontVariantNumeric: 'tabular-nums' }}>{ids.length}</span>
                        </div>
                        <div style={{ fontSize: 10.5, color: palette.inkSoft, marginTop: 2, lineHeight: 1.4 }}>{b.desc}</div>
                      </div>
                      {ids.map(id => <RecallCard key={id} {...cardProps(id)}/>)}
                      {ids.length === 0 && (
                        <div style={{ fontSize: 11.5, color: palette.inkSoft, padding: '10px 2px', opacity: .8 }}>Empty</div>
                      )}
                    </div>
                  );
                })}
              </div>
            )}
          </>
        )}
      </div>
    </div>
  );
}

// Small add/remove control used in the library lists.
function PlanButton({ chatId, palette, size }) {
  const S = useSRS();
  const e = S.get(chatId);
  const s = size || 26;
  return (
    <span role="button" tabIndex={0}
      onClick={ev => { ev.stopPropagation(); e ? S.remove(chatId) : S.add(chatId); }}
      onKeyDown={ev => { if (ev.key === 'Enter' || ev.key === ' ') { ev.preventDefault(); ev.stopPropagation(); e ? S.remove(chatId) : S.add(chatId); } }}
      title={e ? 'Remove from repetition plan' : 'Add to repetition plan'}
      style={{
        width: s, height: s, borderRadius: 8, flexShrink: 0, cursor: 'pointer',
        background: e ? palette.accent3 : 'transparent',
        color: e ? '#fff' : palette.inkSoft,
        border: `1px solid ${e ? palette.accent3 : palette.ink + '20'}`,
        display: 'grid', placeItems: 'center', fontSize: 13, lineHeight: 1, padding: 0,
      }}>⟳</span>
  );
}

Object.assign(window, { RecallView, RecallCard, StudyPanel, RecallCalendar, PlanButton, useSRS });
