/* Discussion Intelligence — hidden editor-only page.
   Sibling of editor-notes.jsx, but instead of editorial commentary scored by
   a rubric, this page surfaces *what the cohort is actually discussing* this
   week — extracted by the LLM classifier per tweet and aggregated by
   scripts/discussionDigest.ts into public/data/xai-discussion-7d.json. */

var DISCUSSION_JSON_URL = '/data/xai-discussion-7d.json';

/* Content-language helper for this page's leaf labels. Reads the global set by
   the shared LangToggle; safe because a lang change re-renders DiscussionPage
   (it calls useContentLang), which cascades to every child below. */
function _dzh() { return (typeof window !== 'undefined' && window.__contentLang === 'zh'); }

function DiscussionPage() {
  var lang = useContentLang();
  var zh = lang === 'zh';
  var [data, setData] = React.useState(null);
  var [err, setErr] = React.useState(null);

  React.useEffect(function () {
    fetch(DISCUSSION_JSON_URL)
      .then(function (r) { return r.ok ? r.json() : Promise.reject(new Error('GET /data/xai-discussion-7d.json → HTTP ' + r.status)); })
      .then(setData)
      .catch(function (e) { setErr(String(e.message || e)); });
  }, []);

  if (err) {
    return (
      <div style={{ padding: 40, maxWidth: 800, margin: '0 auto', color: 'var(--text-secondary)' }}>
        <h1 style={{ fontSize: 24, color: 'var(--text-primary)', marginBottom: 14 }}>{zh ? '討論' : 'Discussion'}</h1>
        <p style={{ fontSize: 13, lineHeight: 1.6 }}>
          {err}
        </p>
        <p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginTop: 14, lineHeight: 1.6 }}>
          {zh
            ? <>討論頁讀取 <code style={{ fontFamily: 'var(--mono)' }}>public/data/xai-discussion-7d.json</code>，由 <code style={{ fontFamily: 'var(--mono)' }}>pnpm discussion-digest</code> 產生。請在 <code style={{ fontFamily: 'var(--mono)' }}>pnpm classify</code> 已把 mood / competitor / dimension 欄位寫進 tweets 表後跑一次。</>
            : <>The Discussion page reads <code style={{ fontFamily: 'var(--mono)' }}>public/data/xai-discussion-7d.json</code>, written by <code style={{ fontFamily: 'var(--mono)' }}>pnpm discussion-digest</code>. Run that once after <code style={{ fontFamily: 'var(--mono)' }}>pnpm classify</code> has populated mood / competitor / dimension fields on the tweets table.</>}
        </p>
      </div>
    );
  }
  if (!data) {
    return <div style={{ padding: 40, color: 'var(--text-tertiary)', fontSize: 13 }}>{zh ? '討論資料載入中…' : 'Loading discussion data…'}</div>;
  }

  return (
    <div style={{ padding: '40px 32px 80px', maxWidth: 980, margin: '0 auto', overflowY: 'auto', height: '100%' }}>
      <DiscussionHero data={data} zh={zh} />

      <DiscussionSection
        title={zh ? '熱門面向' : 'Hot dimensions'}
        sub={zh ? '這週這群人最常聊到各主題的哪些具體子面向' : 'what specific sub-aspects of each topic the cohort engaged with most this week'}
        caption={data.captions && data.captions.hotDimensions}>
        <HotDimensionsList items={data.hotDimensions || []} />
      </DiscussionSection>

      <DiscussionSection
        title={zh ? '抱怨與許願' : 'Complaints & wishes'}
        sub={zh ? '哪裡壞了、想要什麼——依觀看數排序，附樣本引文' : "what's broken, what's wanted — ranked by views, sample quote inline"}
        caption={data.captions && data.captions.complaintsAndWishes}>
        <ComplaintsWishes complaints={data.complaints || []} wishes={data.wishes || []} />
      </DiscussionSection>

      <DiscussionSection
        title={zh ? '競品地圖' : 'Competitor map'}
        sub={zh ? '這群人怎麼談每個競品——依情緒計數' : 'how the cohort talks about each competitor — count by mood'}
        caption={data.captions && data.captions.competitorMap}>
        <CompetitorHeatmap cells={data.competitorMap || []} />
      </DiscussionSection>

      <DiscussionSection
        title={zh ? '辯論串' : 'Debate threads'}
        sub={zh ? '這群人真的有來有往、各執一詞的回覆串' : 'reply chains where the cohort actively disagreed or argued a position'}
        caption={data.captions && data.captions.debateThreads}>
        <DebateThreadsList threads={data.debateThreads || []} />
      </DiscussionSection>

      <DiscussionSection
        title={zh ? '招募與加入' : 'Hiring & joining'}
        sub={zh ? '這群人裡的招募貼文與新人加入公告' : 'active recruiting posts and new joiner announcements in the cohort'}
        caption={data.captions && data.captions.hiringJoining}>
        <HiringList items={data.hiringJoining || []} />
      </DiscussionSection>

      <div style={{ marginTop: 30, padding: '16px 0', borderTop: '1px solid var(--border-subtle)', fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', lineHeight: 1.7 }}>
        {zh
          ? '彙整自 ' + data.totalTweets + ' 則推文 · 視窗 ' + data.windowDays + ' 天 · 產生於 ' + new Date((data.generatedAt || 0) * 1000).toLocaleString() + '。統計於每週 cron 重算（週一 00:00 UTC）。'
          : 'Aggregated over ' + data.totalTweets + ' tweets · window ' + data.windowDays + 'd · generated ' + new Date((data.generatedAt || 0) * 1000).toLocaleString() + '. Stats recompute on the weekly cron (Monday 00:00 UTC).'}
      </div>
    </div>
  );
}

/* ── Hero ── */
function DiscussionHero({ data, zh }) {
  return (
    <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 ? '討論' : 'Discussion'}
      </h1>
      <p style={{ fontSize: 14, color: 'var(--text-secondary)', lineHeight: 1.6, marginTop: 14, maxWidth: 720 }}>
        {zh
          ? <>這群人<em>實際上</em>在吵什麼、想要什麼、稱讚什麼、抱怨什麼？每個區塊都由逐則推文的訊號擷取（情緒 / 競品 / 開放詞彙面向）驅動，再由 LLM 從彙整數據（而非原始推文）寫成一句話的說明——所以每個文字主張都能追回一個你能重新查詢的數字。</>
          : <>What is this group <em>actually</em> arguing about, wishing for, praising, complaining about? Each section is driven by per-tweet signal extraction (mood / competitor / open-vocab dimension) and a 1-sentence LLM caption written from the aggregates — never from raw tweets — so every prose claim traces back to a number you can re-query.</>}
      </p>
    </div>
  );
}

/* ── Generic section shell ── */
function DiscussionSection({ title, sub, caption, children }) {
  return (
    <div style={{ marginBottom: 36 }}>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 4 }}>
        <h2 style={{ fontSize: 16, fontWeight: 600, color: 'var(--text-primary)', margin: 0, letterSpacing: '-0.005em' }}>{title}</h2>
        <span style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>{sub}</span>
      </div>
      {caption && (
        <p style={{
          fontSize: 13, color: 'var(--text-primary)', fontStyle: 'italic', lineHeight: 1.55,
          margin: '8px 0 18px 0', paddingLeft: 12, borderLeft: '2px solid var(--accent)',
          maxWidth: 760,
        }}>
          {caption}
        </p>
      )}
      <div style={{ marginTop: caption ? 0 : 12 }}>
        {children}
      </div>
    </div>
  );
}

/* ── Hot dimensions ── */
function HotDimensionsList({ items }) {
  var [expanded, setExpanded] = React.useState({});
  if (items.length === 0) {
    return <div style={{ fontSize: 12, color: 'var(--text-tertiary)', fontStyle: 'italic' }}>{_dzh() ? '尚未擷取任何面向——請跑 pnpm classify。' : 'No dimensions extracted yet — run pnpm classify.'}</div>;
  }
  var max = items[0] && items[0].count ? items[0].count : 1;
  function toggle(key) { setExpanded(function (p) { var n = Object.assign({}, p); n[key] = !n[key]; return n; }); }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      {items.slice(0, 16).map(function (d) {
        var key = d.topic + ':' + d.dimension;
        var pct = (d.count / max) * 100;
        var isOpen = !!expanded[key];
        var sources = d.sources || [];
        return (
          <div key={key} style={{ background: 'var(--bg-card)', border: '1px solid var(--border-subtle)', borderRadius: 6, overflow: 'hidden' }}>
            <button onClick={function () { toggle(key); }}
              style={{
                display: 'grid', gridTemplateColumns: '14px 120px 1fr 60px 96px',
                gap: 10, alignItems: 'center', padding: '7px 10px', width: '100%',
                border: 'none', background: isOpen ? 'var(--bg-elevated)' : 'transparent',
                cursor: 'pointer', textAlign: 'left', color: 'inherit',
                transition: 'background .12s',
              }}>
              <span style={{ fontSize: 9, color: 'var(--text-tertiary)', textAlign: 'center' }}>{isOpen ? '▾' : '▸'}</span>
              <span style={{ fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                #{d.topic}
              </span>
              <span style={{ fontSize: 13, fontFamily: 'var(--mono)', color: 'var(--text-primary)', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                {d.dimension}
              </span>
              <div style={{ height: 14, background: 'var(--bg-elevated)', borderRadius: 3, overflow: 'hidden' }}>
                <div style={{ height: '100%', width: pct + '%', background: 'var(--accent)' }}></div>
              </div>
              <span style={{ fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-secondary)', textAlign: 'right', fontFeatureSettings: "'tnum' 1" }}>
                {d.count} tw · {fmtViews(d.views)}
              </span>
            </button>
            {isOpen && <SourceList sources={sources} />}
          </div>
        );
      })}
    </div>
  );
}

/* ── Reusable: expanded source-tweet list (used by Hot dimensions + Comp map) ── */
function SourceList({ sources }) {
  if (!sources || sources.length === 0) {
    return <div style={{ padding: '10px 14px', fontSize: 11, color: 'var(--text-tertiary)', fontStyle: 'italic' }}>{_dzh() ? '此分類沒有擷取到來源推文。' : 'No source tweets captured for this bucket.'}</div>;
  }
  var moodColor = { praise: 'var(--accent)', complaint: 'var(--rose)', wish: 'rgba(249,115,22,0.6)', debate: 'var(--blue)', neutral: 'var(--text-tertiary)' };
  function displayText(s) {
    var t = s.text || '';
    // Best-effort strip of "RT @whoever: " prefix when the root content is shown under its real author.
    if (/^RT\s+@/i.test(t)) {
      t = t.replace(/^RT\s+@[^:\s]+:\s*/i, '');
    }
    return t;
  }
  // Legacy safety net: the committed JSON snapshots still contain the old per-tweet sources
  // (many near-identical RT cards). Group them here by cleaned text so the UI already looks
  // good on historical data. New digests (with upstream collapseSources) produce distinct
  // entries so this is mostly a no-op.
  function collapseLegacySources(srcs) {
    if (!srcs || srcs.length <= 1) return srcs || [];
    var groups = {};
    for (var i = 0; i < srcs.length; i++) {
      var s = srcs[i];
      var t = (s.text || '').replace(/^RT\s+@[^:\s]+:\s*/i, '').trim().toLowerCase();
      var key = t.slice(0, 160); // stable enough for these short excerpts
      if (!groups[key]) {
        groups[key] = { rep: s, handles: [] };
      }
      groups[key].handles.push(s.handle);
      if ((s.views || 0) > (groups[key].rep.views || 0)) {
        groups[key].rep = s;
      }
    }
    var out = [];
    var keys = Object.keys(groups);
    for (var k = 0; k < keys.length; k++) {
      var g = groups[keys[k]];
      var r = g.rep;
      var unique = [];
      var seen = {};
      for (var h = 0; h < g.handles.length; h++) {
        var hh = g.handles[h];
        if (!seen[hh]) { seen[hh] = true; unique.push(hh); }
      }
      var ampN = (r.ampCount != null ? r.ampCount : (r.amplifiers ? r.amplifiers.length : 0));
      if (ampN < 2 && unique.length > 1) {
        // synthesize for legacy data
        r = Object.assign({}, r, { amplifiers: unique, ampCount: unique.length });
      }
      out.push(r);
    }
    out.sort(function (a, b) { return (b.views || 0) - (a.views || 0); });
    return out;
  }
  var [expandedAmpId, setExpandedAmpId] = React.useState(null);
  var [hoveredExtra, setHoveredExtra] = React.useState(null); // for tooltip on +N

  var displaySources = collapseLegacySources(sources);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4, padding: '8px 12px 12px', borderTop: '1px solid var(--border-subtle)', background: 'var(--bg-surface)' }}>
      {displaySources.map(function (s) {
        var mc = moodColor[s.mood || 'neutral'] || 'var(--text-tertiary)';
        var highReach = (s.views || 0) >= 100000;
        var ampN = (s.ampCount != null ? s.ampCount : (s.amplifiers ? s.amplifiers.length : 0));
        var ampList = (s.amplifiers || []).slice(0, 3).map(function (a) { return '@' + a; }).join(' ');
        var ampExtra = (s.amplifiers && s.amplifiers.length > 3) ? (s.amplifiers.length - 3) : 0;
        var isExpanded = expandedAmpId === s.id;
        var showTooltip = hoveredExtra === s.id && ampExtra > 0;

        return (
          <a key={s.id} href={s.url} target="_blank" rel="noopener noreferrer"
            style={{
              display: 'flex', gap: 10, padding: '8px 10px',
              borderRadius: 5, background: 'var(--bg-card)',
              borderLeft: '2px solid ' + mc,
              textDecoration: 'none', color: 'inherit',
              transition: 'background .12s',
            }}
            onMouseEnter={function (e) { e.currentTarget.style.background = 'var(--bg-elevated)'; }}
            onMouseLeave={function (e) { e.currentTarget.style.background = 'var(--bg-card)'; }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: 'flex', gap: 8, fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', marginBottom: 4 }}>
                <span style={{ color: 'var(--text-primary)', fontWeight: 500 }}>@{s.handle}</span>
                {s.mood && <span style={{ color: mc, textTransform: 'uppercase', letterSpacing: '0.04em' }}>{s.mood}</span>}
                <span style={{ marginLeft: 'auto', color: highReach ? 'var(--accent)' : 'var(--text-tertiary)', fontWeight: highReach ? 600 : 400, fontFeatureSettings: "'tnum' 1" }}>👁 {fmtViews(s.views)}</span>
              </div>
              <div style={{ fontSize: 12, color: 'var(--text-primary)', lineHeight: 1.5, overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical' }}>
                {displayText(s)}
              </div>

              {/* Strengthened "in cohort" indicator — now a real button-like badge */}
              {ampN > 1 && (
                <button
                  onClick={function (e) {
                    e.preventDefault();
                    e.stopPropagation();
                    setExpandedAmpId(isExpanded ? null : s.id);
                  }}
                  onMouseEnter={function () { if (ampExtra > 0) setHoveredExtra(s.id); }}
                  onMouseLeave={function () { setHoveredExtra(null); }}
                  style={{
                    marginTop: 4,
                    fontSize: 10,
                    fontFamily: 'var(--mono)',
                    color: 'var(--text-primary)',
                    background: 'var(--bg-elevated)',
                    border: '1px solid var(--border-subtle)',
                    borderRadius: 4,
                    padding: '3px 8px',
                    cursor: 'pointer',
                    display: 'inline-flex',
                    alignItems: 'center',
                    gap: 4,
                    transition: 'all .1s'
                  }}
                  title={_dzh() ? ('點擊查看全部 ' + ampN + ' 位 cohort 內轉推者') : (ampExtra > 0 ? 'Click to see all ' + ampN + ' retweeters in cohort' : 'Click to see all ' + ampN + ' retweeters')}
                >
                  ↻ {ampN}{_dzh() ? ' 人轉推（cohort 內）' : ' in cohort'}
                  {ampList ? ' · ' + ampList : ''}
                  {ampExtra > 0 && <span style={{ color: 'var(--accent)', fontWeight: 600 }}>+{ampExtra}</span>}
                </button>
              )}

              {/* Click-expanded list of all amplifiers (with profile links) */}
              {isExpanded && ampN > 1 && (
                <div style={{
                  marginTop: 6,
                  padding: '8px 10px',
                  background: 'var(--bg-surface)',
                  border: '1px solid var(--border-subtle)',
                  borderRadius: 4,
                  fontSize: 11
                }}>
                  <div style={{ fontSize: 10, color: 'var(--text-tertiary)', marginBottom: 4, fontWeight: 600 }}>
                    {_dzh() ? ('cohort 內 ' + ampN + ' 人轉推（點帳號看個人檔案）：') : ('Retweeted by ' + ampN + ' in cohort (click handle to view profile):')}
                  </div>
                  {(s.amplifiers || []).map(function (h) {
                    return (
                      <a
                        key={h}
                        href={'https://x.com/' + h}
                        target="_blank"
                        rel="noopener noreferrer"
                        style={{ display: 'block', color: 'var(--accent)', padding: '2px 0', textDecoration: 'none' }}
                        onMouseEnter={function (e) { e.currentTarget.style.textDecoration = 'underline'; }}
                        onMouseLeave={function (e) { e.currentTarget.style.textDecoration = 'none'; }}
                      >
                        @{h}
                      </a>
                    );
                  })}
                  <div style={{ fontSize: 9, color: 'var(--text-tertiary)', marginTop: 6, lineHeight: 1.3 }}>
                    {_dzh() ? '這些 cohort 成員放大了上面這則貼文。點他們的帳號打開個人檔案進一步調查。' : 'These cohort members amplified the post above. Click their handle to open profile and investigate further.'}
                  </div>
                </div>
              )}

              {/* Simple hover tooltip for the +N extra handles */}
              {showTooltip && (
                <div style={{
                  position: 'absolute',
                  marginTop: 2,
                  background: 'var(--bg-elevated)',
                  border: '1px solid var(--border-subtle)',
                  borderRadius: 4,
                  padding: '4px 8px',
                  fontSize: 10,
                  fontFamily: 'var(--mono)',
                  color: 'var(--text-tertiary)',
                  boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
                  zIndex: 10
                }}>
                  {_dzh() ? ('另 +' + ampExtra + ' 人：') : ('+' + ampExtra + ' more: ')}{(s.amplifiers || []).slice(3).map(function (h) { return '@' + h; }).join(' ')}
                </div>
              )}
            </div>
          </a>
        );
      })}
    </div>
  );
}

/* ── Complaints + Wishes ── */
function ComplaintsWishes({ complaints, wishes }) {
  return (
    <div style={{ display: 'flex', gap: 16 }}>
      <MoodList title={_dzh() ? '抱怨' : 'Complaints'} items={complaints} color="var(--rose)" listKey="complaint" />
      <MoodList title={_dzh() ? '許願' : 'Wishes'} items={wishes} color="var(--accent)" listKey="wish" />
    </div>
  );
}

function MoodList({ title, items, color, listKey }) {
  var [expanded, setExpanded] = React.useState({});
  if (items.length === 0) {
    return (
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 11, fontFamily: 'var(--mono)', color: color, fontWeight: 600, marginBottom: 8, textTransform: 'uppercase', letterSpacing: '0.05em' }}>{title}</div>
        <div style={{ fontSize: 12, color: 'var(--text-tertiary)', fontStyle: 'italic' }}>{_dzh() ? '（本週無）' : '(none this week)'}</div>
      </div>
    );
  }
  function toggle(key) { setExpanded(function (p) { var n = Object.assign({}, p); n[key] = !n[key]; return n; }); }
  return (
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ fontSize: 11, fontFamily: 'var(--mono)', color: color, fontWeight: 600, marginBottom: 8, textTransform: 'uppercase', letterSpacing: '0.05em' }}>{title} · {items.length}</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        {items.slice(0, 6).map(function (c, i) {
          var key = listKey + ':' + (c.dimension || ('__' + i));
          var isOpen = !!expanded[key];
          var sources = c.sources || [];
          return (
            <div key={key} style={{
              borderRadius: 6, background: 'var(--bg-card)', border: '1px solid var(--border-subtle)',
              borderLeft: '3px solid ' + color, overflow: 'hidden',
            }}>
              <button onClick={function () { toggle(key); }}
                style={{
                  display: 'flex', flexDirection: 'column', gap: 6, width: '100%',
                  padding: '10px 12px', border: 'none',
                  background: isOpen ? 'var(--bg-elevated)' : 'transparent',
                  cursor: 'pointer', textAlign: 'left', color: 'inherit',
                  transition: 'background .12s',
                }}>
                <div style={{ display: 'flex', gap: 8, alignItems: 'center', fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)' }}>
                  <span style={{ fontSize: 9, color: 'var(--text-tertiary)' }}>{isOpen ? '▾' : '▸'}</span>
                  {c.dimension
                    ? <span style={{ padding: '1px 6px', borderRadius: 3, background: 'var(--bg-elevated)', color: 'var(--text-primary)' }}>{c.dimension}</span>
                    : <span style={{ color: 'var(--text-disabled)' }}>{_dzh() ? '（無面向）' : '(no dim)'}</span>}
                  <span style={{ marginLeft: 'auto', fontFeatureSettings: "'tnum' 1" }}>{c.count} × · {fmtViews(c.views)}{_dzh() ? ' 觀看' : ' views'}</span>
                </div>
                <div style={{ fontSize: 12, color: 'var(--text-primary)', lineHeight: 1.5 }}>
                  <span style={{ color: 'var(--text-tertiary)', fontFamily: 'var(--mono)' }}>@{c.sampleHandle}: </span>
                  {c.sampleQuote}
                </div>
              </button>
              {isOpen && <SourceList sources={sources} />}
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ── Competitor heatmap ── */
function CompetitorHeatmap({ cells }) {
  var [selected, setSelected] = React.useState(null); // {competitor, mood, sources}
  if (cells.length === 0) {
    return <div style={{ fontSize: 12, color: 'var(--text-tertiary)', fontStyle: 'italic' }}>{_dzh() ? '本週無競品提及。' : 'No competitor mentions this week.'}</div>;
  }
  var competitors = ['veo', 'kling', 'sora', 'seedance', 'runway', 'pika', 'midjourney'];
  var moods = ['praise', 'complaint', 'wish', 'debate', 'neutral'];
  var moodColor = { praise: 'var(--accent)', complaint: 'var(--rose)', wish: 'rgba(249,115,22,0.6)', debate: 'var(--blue)', neutral: 'var(--text-disabled)' };

  /* Index cells for both count + sources lookup. */
  var byCell = {};
  var maxVal = 0;
  for (var i = 0; i < cells.length; i++) {
    var c = cells[i];
    byCell[c.competitor + '|' + c.mood] = c;
    if (c.count > maxVal) maxVal = c.count;
  }

  function clickCell(comp, mood) {
    var c = byCell[comp + '|' + mood];
    if (!c || !c.count) return;
    if (selected && selected.competitor === comp && selected.mood === mood) setSelected(null);
    else setSelected(c);
  }

  return (
    <div>
      <div style={{ overflowX: 'auto' }}>
        <table style={{ borderCollapse: 'collapse', fontSize: 11, fontFamily: 'var(--mono)' }}>
          <thead>
            <tr>
              <th style={{ padding: '6px 10px', textAlign: 'left', color: 'var(--text-tertiary)', fontWeight: 400 }}></th>
              {moods.map(function (m) {
                return <th key={m} style={{ padding: '6px 14px', textAlign: 'center', color: moodColor[m], fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em', fontSize: 10 }}>{m}</th>;
              })}
            </tr>
          </thead>
          <tbody>
            {competitors.map(function (comp) {
              return (
                <tr key={comp}>
                  <td style={{ padding: '6px 10px', color: 'var(--text-primary)', fontWeight: 500 }}>{comp}</td>
                  {moods.map(function (m) {
                    var c = byCell[comp + '|' + m];
                    var v = (c && c.count) || 0;
                    var intensity = maxVal ? v / maxVal : 0;
                    var isSel = selected && selected.competitor === comp && selected.mood === m;
                    return (
                      <td key={comp + m} onClick={function () { clickCell(comp, m); }}
                        style={{
                          padding: '6px 14px', textAlign: 'center',
                          color: v ? 'var(--text-primary)' : 'var(--text-disabled)',
                          background: v ? 'rgba(249,115,22,' + (0.06 + intensity * 0.35) + ')' : 'transparent',
                          border: isSel ? '1px solid var(--accent)' : '1px solid transparent',
                          borderRadius: 3,
                          fontFeatureSettings: "'tnum' 1",
                          fontWeight: v ? 600 : 400,
                          cursor: v ? 'pointer' : 'default',
                        }}>{v || '·'}</td>
                    );
                  })}
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
      {selected && (
        <div style={{ marginTop: 12, background: 'var(--bg-card)', border: '1px solid var(--border-subtle)', borderRadius: 6, overflow: 'hidden' }}>
          <div style={{ padding: '8px 12px', display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-secondary)', background: 'var(--bg-elevated)' }}>
            <span style={{ color: 'var(--text-primary)', fontWeight: 600 }}>{selected.competitor}</span>
            <span style={{ color: moodColor[selected.mood], textTransform: 'uppercase', letterSpacing: '0.05em', fontSize: 10 }}>{selected.mood}</span>
            <span style={{ marginLeft: 'auto' }}>{selected.count}{_dzh() ? ' 則推文' : ' tweets'}</span>
            <button onClick={function () { setSelected(null); }} style={{ background: 'transparent', border: 'none', color: 'var(--text-tertiary)', cursor: 'pointer', fontSize: 14, lineHeight: 1, padding: 0 }}>×</button>
          </div>
          <SourceList sources={selected.sources || []} />
        </div>
      )}
    </div>
  );
}

/* ── Debate threads ── */
function DebateThreadsList({ threads }) {
  if (threads.length === 0) {
    return <div style={{ fontSize: 12, color: 'var(--text-tertiary)', fontStyle: 'italic' }}>{_dzh() ? '本週沒有浮現辯論。' : 'No debates surfaced this week.'}</div>;
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      {threads.map(function (t) {
        return (
          <a key={t.rootId} href={t.rootUrl} target="_blank" rel="noopener noreferrer"
            style={{
              display: 'flex', gap: 14, padding: '12px 14px', borderRadius: 8,
              background: 'var(--bg-card)', border: '1px solid var(--border-subtle)',
              textDecoration: 'none', color: 'inherit',
              transition: 'background .12s',
            }}
            onMouseEnter={function (e) { e.currentTarget.style.background = 'var(--bg-elevated)'; }}
            onMouseLeave={function (e) { e.currentTarget.style.background = 'var(--bg-card)'; }}>
            <div style={{ flexShrink: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2 }}>
              <span style={{ fontSize: 18, fontFamily: 'var(--mono)', color: 'var(--accent)', fontWeight: 600, fontFeatureSettings: "'tnum' 1" }}>{t.replies}</span>
              <span style={{ fontSize: 9, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>{_dzh() ? '回覆' : 'replies'}</span>
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', marginBottom: 4 }}>
                @{t.rootHandle} · {t.participants}{_dzh() ? ' 位參與者' : ' participants'}
              </div>
              <div style={{ fontSize: 12, color: 'var(--text-primary)', lineHeight: 1.5, overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical' }}>
                {t.rootText}
              </div>
            </div>
          </a>
        );
      })}
    </div>
  );
}

/* ── Hiring / joining list ── */
function HiringList({ items }) {
  if (items.length === 0) {
    return <div style={{ fontSize: 12, color: 'var(--text-tertiary)', fontStyle: 'italic' }}>{_dzh() ? '本週沒有招募或新人加入的貼文。' : 'No hiring or joiner posts this week.'}</div>;
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {items.slice(0, 20).map(function (h, i) {
        var pillColor = h.kind === 'hiring' ? 'var(--accent)' : 'var(--blue)';
        return (
          <a key={i} href={h.url} target="_blank" rel="noopener noreferrer"
            style={{
              display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px',
              borderRadius: 6, background: 'var(--bg-card)', border: '1px solid var(--border-subtle)',
              textDecoration: 'none', color: 'inherit',
              transition: 'background .12s',
            }}
            onMouseEnter={function (e) { e.currentTarget.style.background = 'var(--bg-elevated)'; }}
            onMouseLeave={function (e) { e.currentTarget.style.background = 'var(--bg-card)'; }}>
            <span style={{ flexShrink: 0, fontSize: 9, fontFamily: 'var(--mono)', color: pillColor, padding: '2px 6px', borderRadius: 3, background: 'rgba(249,115,22,0.08)', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 600 }}>
              {h.kind === 'hiring' ? (_dzh() ? '招募' : 'hiring') : (_dzh() ? '加入' : 'joined')}
            </span>
            <span style={{ flexShrink: 0, fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)' }}>{h.date}</span>
            <span style={{ flexShrink: 0, fontSize: 12, fontFamily: 'var(--mono)', color: 'var(--text-primary)' }}>@{h.handle}</span>
            <span style={{ flex: 1, minWidth: 0, fontSize: 12, color: 'var(--text-secondary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{h.text}</span>
          </a>
        );
      })}
    </div>
  );
}

function fmtViews(n) {
  if (!n) return '0';
  if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M';
  if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K';
  return String(n);
}

window.DiscussionPage = DiscussionPage;
