/* Editor's Notes — hidden screen, only reachable when ?editor=1 (sets a
   localStorage flag). The Overview page shows neutral aggregates; this page
   collects hypothesis-led commentary the owner is using as raw material for
   a write-up. Public visitors should not see it framed as the dashboard's
   default story.

   Scoring framework: each note carries five sub-scores (surprise,
   quotability, specificity, verifiability, narrative) and an optional set
   of small boosts. The composite is computed live below so weights stay in
   one place. See docs/insight-rubric.md for the full rubric. */

/* ── Scoring framework (must match docs/insight-rubric.md) ──
   Sourced from window.notesEngine (public/design/notesEngine.js) so the pure
   ranking logic stays in one shared module that also runs in Node. */
var NOTE_WEIGHTS = window.notesEngine.NOTE_WEIGHTS;
var NOTE_DIM_LABELS = window.notesEngine.NOTE_DIM_LABELS;
/* Render a string with every @handle turned into an external link to x.com.
   Used in note headlines / bodies / stats / punchlines so any handle the
   editor cites is one click away from verification. */
function linkifyHandles(text) {
  if (text == null) return text;
  var parts = String(text).split(/(@[A-Za-z0-9_]{1,15})/g);
  return parts.map(function (part, i) {
    if (part.length > 1 && part.charAt(0) === '@') {
      var h = part.slice(1);
      return (
        <a key={i} href={'https://x.com/' + h} target="_blank" rel="noopener noreferrer"
          title={'Open @' + h + ' on x.com'}
          style={{
            color: 'var(--accent)', textDecoration: 'none', fontWeight: 600,
            borderBottom: '1px dotted rgba(249, 115, 22,0.45)',
          }}>{part}</a>
      );
    }
    return part;
  });
}

/* Score badge with an *instant* hover tooltip showing the dimension
   breakdown. The browser's native `title=` attribute waits ~500ms before
   appearing; this CSS-driven panel pops the moment the cursor lands. */
function ScoreBadge({ n, displayScore, scoreColor, scoreBg }) {
  var [hov, setHov] = React.useState(false);
  var dims = n.dims || {};
  var border = displayScore >= 6.5 ? 'rgba(249, 115, 22,0.25)' : 'var(--border-subtle)';

  return (
    <div
      onMouseEnter={function () { setHov(true); }}
      onMouseLeave={function () { setHov(false); }}
      style={{ position: 'relative', display: 'inline-block' }}>
      <div style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        padding: '2px 9px', borderRadius: 10,
        background: scoreBg, border: '1px solid ' + border,
        fontSize: 11, fontFamily: 'var(--mono)', color: scoreColor, fontFeatureSettings: "'tnum' 1", fontWeight: 600,
        cursor: 'help',
      }}>
        <span style={{ display: 'inline-flex', alignItems: 'flex-end', gap: 1.5, height: 11 }}>
          {Object.keys(NOTE_DIM_LABELS).map(function (k) {
            var v = dims[k] || 0;
            return (
              <span key={k} style={{
                width: 3, height: Math.max(2, v * 11),
                background: v >= 0.7 ? 'currentColor' : 'rgba(255,255,255,0.20)',
                borderRadius: 1,
                opacity: v >= 0.7 ? 1 : 0.6,
              }}></span>
            );
          })}
        </span>
        <span>{displayScore.toFixed(1)}</span>
        <span style={{ fontSize: 9, opacity: 0.65, fontWeight: 400 }}>/10</span>
      </div>

      {hov && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 6px)', right: 0,
          minWidth: 220, padding: '10px 12px',
          background: 'var(--bg-elevated)', border: '1px solid var(--border-strong)',
          borderRadius: 8, boxShadow: '0 6px 20px rgba(0,0,0,0.45)',
          fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-secondary)',
          fontFeatureSettings: "'tnum' 1", lineHeight: 1.65, zIndex: 10,
          whiteSpace: 'nowrap', pointerEvents: 'none',
        }}>
          {Object.keys(NOTE_DIM_LABELS).map(function (k) {
            var v = dims[k] || 0;
            var w = NOTE_WEIGHTS[k];
            return (
              <div key={k} style={{ display: 'flex', gap: 10, alignItems: 'baseline' }}>
                <span style={{ color: 'var(--text-tertiary)', minWidth: 100 }}>{NOTE_DIM_LABELS[k]}</span>
                <span style={{ color: v >= 0.7 ? 'var(--accent)' : 'var(--text-primary)' }}>{v.toFixed(2)}</span>
                <span style={{ color: 'var(--text-tertiary)' }}>× {w.toFixed(2)}</span>
              </div>
            );
          })}
          {(n.crossCohort || n.selfCritical) && (
            <div style={{ marginTop: 6, paddingTop: 6, borderTop: '1px solid var(--border-subtle)', color: 'var(--accent)' }}>
              {n.crossCohort  && <div>+0.05 cross-cohort boost</div>}
              {n.selfCritical && <div>+0.05 self-critique boost</div>}
            </div>
          )}
          <div style={{ marginTop: 6, paddingTop: 6, borderTop: '1px solid var(--border-subtle)', color: 'var(--text-primary)', fontWeight: 600 }}>
            Composite {displayScore.toFixed(1)} / 10
          </div>
        </div>
      )}
    </div>
  );
}

function EditorNotesPage() {
  var lang = useContentLang();
  var zh = lang === 'zh';
  /* Pure computation lives in the shared notesEngine module so the same
     ranking can run server-side. Pass the live globals + content language. */
  var built = window.notesEngine.buildNotes(window.COHORT, window.TIMELINE_DATA, lang);
  var notes = built.notes;
  var staleNotes = built.staleNotes;
  var total = built.metrics.total;

  return (
    <div style={{ padding: '40px 32px 60px', maxWidth: 880, margin: '0 auto', overflowY: 'auto', height: '100%' }}>

      {/* ── Hero ── */}
      <div style={{ marginBottom: 32, paddingBottom: 24, borderBottom: '1px solid var(--border-subtle)' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, marginBottom: 14 }}>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '3px 10px', borderRadius: 4, background: 'var(--accent-muted)', border: '1px solid rgba(249, 115, 22,0.25)', fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--accent)', letterSpacing: '0.08em', textTransform: 'uppercase', fontWeight: 600 }}>
            <span style={{ width: 4, height: 4, borderRadius: '50%', background: 'var(--accent)' }}></span>
            editor only
          </div>
          <LangToggle />
        </div>
        <h1 style={{ fontSize: 28, fontWeight: 600, color: 'var(--text-primary)', letterSpacing: '-0.02em', margin: 0, lineHeight: 1.15 }}>
          {zh ? '編輯筆記' : "Editor's Notes"}
        </h1>
        <p style={{ fontSize: 14, color: 'var(--text-secondary)', lineHeight: 1.6, marginTop: 14, maxWidth: 660 }}>
          {zh
            ? '從 cohort 數據整理出的工作觀察——假設導向，尚未當成對外定調。適合當作把這份資料寫成文章的素材。每個數字都會從載入的 cohort 即時重算，所以文字會隨資料刷新保持同步。'
            : 'Working observations from the cohort data — hypothesis-led, not vetted as public framing. Useful as raw material for writing the dataset up. Each stat is recomputed live from the loaded cohort so the prose stays in sync as the data refreshes.'}
        </p>
        <p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginTop: 12, lineHeight: 1.65 }}>
          {zh
            ? <>卡片依 5 維綜合分數排序（驚奇度 · 可引用度 · 具體度 · 可驗證度 · 敘事張力），對應 Phase 2 的 light score。把游標移到分數徽章上可看各維拆解。完整評分表：<code style={{ fontFamily: 'var(--mono)', color: 'var(--text-secondary)', marginLeft: 4 }}>docs/insight-rubric.md</code>。<br />要隱藏本頁：前往 <code style={{ fontFamily: 'var(--mono)', color: 'var(--text-secondary)' }}>/?editor=0</code>。</>
            : <>Cards are ranked by a 5-dimensional composite (surprise · quotability · specificity · verifiability · narrative pull) mirroring the Phase 2 light score. Hover any score badge to see the dimension breakdown. Full rubric:<code style={{ fontFamily: 'var(--mono)', color: 'var(--text-secondary)', marginLeft: 4 }}>docs/insight-rubric.md</code>.<br />To hide this page: visit <code style={{ fontFamily: 'var(--mono)', color: 'var(--text-secondary)' }}>/?editor=0</code>.</>}
        </p>
      </div>

      {/* ── Notes ── */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
        {notes.map(function (n, i) {
          var displayScore = Math.round(Math.min(1, n._composite) * 100) / 10;   /* 0.0–10.0 (clamped; sort uses unclamped _composite) */
          var scoreColor = displayScore >= 8.5 ? 'var(--accent)'
                         : displayScore >= 6.5 ? 'rgba(249, 115, 22,0.55)'
                         : 'var(--text-disabled)';
          var scoreBg    = displayScore >= 8.5 ? 'var(--accent-muted)'
                         : displayScore >= 6.5 ? 'rgba(249, 115, 22,0.06)'
                         : 'var(--bg-elevated)';
          /* Build a tooltip showing the dimensional breakdown — the
             "argument surface" that lets the reader disagree with the rank
             on substance, not vibes. */
          var dimTip = Object.keys(NOTE_DIM_LABELS).map(function (k) {
            return NOTE_DIM_LABELS[k] + ' ' + ((n.dims || {})[k] || 0).toFixed(2) + ' × ' + NOTE_WEIGHTS[k].toFixed(2);
          }).join('\n');
          if (n.crossCohort)  dimTip += '\n+0.05 cross-cohort boost';
          if (n.selfCritical) dimTip += '\n+0.05 self-critique boost';
          dimTip += '\n────────\nComposite ' + displayScore.toFixed(1) + ' / 10';
          return (
            <div key={i} style={{
              background: 'var(--bg-card)', border: '1px solid var(--border-subtle)',
              borderRadius: 14, padding: '22px 26px', display: 'flex', gap: 18, alignItems: 'flex-start',
            }}>
              <div style={{
                width: 34, height: 34, borderRadius: 9, background: 'var(--bg-elevated)', flexShrink: 0,
                display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 16,
                color: 'var(--accent)', fontFamily: 'var(--mono)', fontWeight: 600,
              }}>{n.icon}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                {/* Top row: rank label on the left, importance score on the right */}
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 4 }}>
                  <div style={{ fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', letterSpacing: '0.06em' }}>
                    {(zh ? '筆記 ' : 'NOTE ') + String(i + 1).padStart(2, '0')}
                  </div>
                  {n._composite != null && (
                    <ScoreBadge n={n} displayScore={displayScore} scoreColor={scoreColor} scoreBg={scoreBg} />
                  )}
                </div>
                <h2 style={{ fontSize: 16, fontWeight: 600, color: 'var(--text-primary)', margin: 0, lineHeight: 1.35, marginBottom: 10 }}>
                  {linkifyHandles(n.headline)}
                </h2>
                {n._guard && n._guard.state === 'warn' && n._guard.failed.length > 0 && (
                  <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '3px 9px', borderRadius: 4, background: 'rgba(234,179,8,0.10)', border: '1px solid rgba(234,179,8,0.30)', fontSize: 10, fontFamily: 'var(--mono)', color: '#eab308', letterSpacing: '0.04em', marginBottom: 10 }}>
                    <span style={{ width: 4, height: 4, borderRadius: '50%', background: '#eab308' }}></span>
                    claim drifted · {n._guard.failed[0].a.label} — now {String(n._guard.failed[0].actual)}
                  </div>
                )}
                <p style={{ fontSize: 14, color: 'var(--text-secondary)', lineHeight: 1.65, margin: 0, marginBottom: 12 }}>
                  {linkifyHandles(n.body)}
                </p>
                {n.stat && (
                  <div style={{ fontSize: 12, fontFamily: 'var(--mono)', color: 'var(--accent)', fontFeatureSettings: "'tnum' 1", paddingTop: 10, borderTop: '1px solid var(--border-subtle)' }}>
                    {linkifyHandles(n.stat)}
                  </div>
                )}
                {n.punchline && (
                  <div style={{
                    marginTop: 14, paddingTop: 12, borderTop: '1px solid var(--border-subtle)',
                    display: 'flex', alignItems: 'flex-start', gap: 8,
                  }}>
                    <span style={{ fontSize: 18, color: 'var(--accent)', lineHeight: 1, fontFamily: 'Georgia, serif', fontStyle: 'italic', flexShrink: 0, marginTop: -2 }}>“</span>
                    <span style={{ fontSize: 14, color: 'var(--text-primary)', fontStyle: 'italic', lineHeight: 1.5, fontWeight: 500 }}>
                      {linkifyHandles(n.punchline)}
                    </span>
                  </div>
                )}
              </div>
            </div>
          );
        })}
      </div>

      {/* ── Stale notes: frozen claims a guard has invalidated. Kept out of the
            ranked feed but surfaced collapsed so the editor can rewrite them. ── */}
      {staleNotes.length > 0 && (
        <details style={{ marginTop: 24, padding: '14px 18px', background: 'var(--bg-elevated)', border: '1px solid var(--border-subtle)', borderRadius: 12 }}>
          <summary style={{ cursor: 'pointer', fontSize: 12, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', letterSpacing: '0.04em' }}>
            {zh
              ? staleNotes.length + ' 則過期筆記 — 主張已不成立，已從排序中隱藏'
              : staleNotes.length + ' stale note' + (staleNotes.length === 1 ? '' : 's') + ' — claim no longer holds, hidden from ranking'}
          </summary>
          <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 10 }}>
            {staleNotes.map(function (n, i) {
              return (
                <div key={i} style={{ fontSize: 13, color: 'var(--text-disabled)', lineHeight: 1.5 }}>
                  <span style={{ color: 'var(--text-secondary)' }}>{linkifyHandles(n.headline)}</span>
                  <div style={{ fontSize: 11, fontFamily: 'var(--mono)', color: '#eab308', marginTop: 3 }}>
                    {n._guard.failed.map(function (f) { return f.a.label + ' — now ' + String(f.actual); }).join(' · ')}
                  </div>
                </div>
              );
            })}
          </div>
        </details>
      )}

      {/* ── Footer ── */}
      <div style={{ marginTop: 40, padding: '20px 0', borderTop: '1px solid var(--border-subtle)', fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', lineHeight: 1.7 }}>
        {zh
          ? notes.length + ' 則筆記 · 每次載入自 /data/xai.json 重新整理 · cohort n=' + total
          : notes.length + ' note' + (notes.length === 1 ? '' : 's') + ' · auto-refreshes from /data/xai.json on each load · cohort n=' + total}
      </div>
    </div>
  );
}

window.EditorNotesPage = EditorNotesPage;
