/* Topics View (Activity > Topics) — aggregated read of the 30-day timeline.
   Two stacked sections, both bounded by the active time-range chip:

     1. Topics      — counts of tagged research/product topics (topicTags).
                      Sparse coverage (~14%) but high-signal: #grok / #release
                      / #agent / #eval / #rl etc.
     2. Attention   — most-mentioned @-handles, the targets xAI is collectively
                      paying attention to. 73% coverage, the dominant signal.

   Any chip click navigates the user back to the Timeline view with a matching
   filter applied — see TimelineView's `initialTopic` / `initialHandle` props. */

/* Inline-string note kept here so the empty-state caption stays close to the
   loader script call-out. Update when extending the taxonomy. */
var TAXONOMY_NOTE = 'closed 30-slug vocabulary, see src/topicTaxonomy.ts';

function TopicsView({ onJumpToTimeline }) {
  var [timeRange, setTimeRange] = React.useState(30);
  var data = window.TIMELINE_DATA;
  var tweets = data.tweets;

  var filtered = React.useMemo(function () {
    var cutoff = data.windowEnd - timeRange * 86400;
    return tweets.filter(function (t) { return t.ts >= cutoff; });
  }, [timeRange]);

  /* Topic aggregation — prefer LLM tags (close to 100% coverage), fall back
     to regex tags. LLM tags don't have the # prefix that legacy regex tags
     have, so we normalize when rendering. */
  var topics = React.useMemo(function () {
    var c = {};
    filtered.forEach(function (t) {
      var tags = (t.topicTagsLLM && t.topicTagsLLM.length > 0) ? t.topicTagsLLM : (t.topicTags || []);
      tags.forEach(function (tag) {
        var norm = tag.replace(/^#/, '');
        c[norm] = (c[norm] || 0) + 1;
      });
    });
    return Object.entries(c).sort(function (a, b) { return b[1] - a[1]; }).map(function (e) { return { tag: e[0], count: e[1] }; });
  }, [filtered]);
  var maxTopic = topics.length > 0 ? topics[0].count : 1;
  var taggedTweets = filtered.reduce(function (s, t) {
    var hasLLM = t.topicTagsLLM && t.topicTagsLLM.length > 0;
    var hasRegex = t.topicTags && t.topicTags.length > 0;
    return s + ((hasLLM || hasRegex) ? 1 : 0);
  }, 0);
  /* Track whether LLM classification has been applied at all so we can show
     the right empty-state message before `pnpm classify` has been run. */
  var anyLLM = filtered.some(function (t) { return t.topicTagsLLM && t.topicTagsLLM.length > 0; });

  /* Top voices per topic — for each of the highest-volume topics, who's
     posting OWN ORIGINALS with the most reach? This is the answer to
     "if I'm writing about X, who should I @?". Quote/reply views are
     excluded since they piggyback on viral splash-back, not the author's
     real audience. */
  var topVoicesPerTopic = React.useMemo(function () {
    var out = {};
    /* Skip noisy/uninteresting buckets that wouldn't tell the user anything
       useful about who to @ — these are too broad or off-topic. */
    var skip = { 'personal-chat': 1, 'other': 1, 'non-english': 1, 'meme-humor': 1 };
    var topicsForVoices = topics.filter(function (t) { return !skip[t.tag]; }).slice(0, 8);
    topicsForVoices.forEach(function (topic) {
      var byAuthor = {};
      filtered.forEach(function (tw) {
        if (tw.type !== 'original') return;
        var tags = tw.topicTagsLLM || tw.topicTags || [];
        var match = false;
        for (var i = 0; i < tags.length; i++) {
          if (tags[i].replace(/^#/, '') === topic.tag) { match = true; break; }
        }
        if (!match) return;
        var h = tw.handle.toLowerCase();
        if (!byAuthor[h]) byAuthor[h] = { handle: tw.handle, name: tw.name, posts: 0, sumViews: 0, sumLikes: 0 };
        byAuthor[h].posts++;
        byAuthor[h].sumViews += tw.views || 0;
        byAuthor[h].sumLikes += tw.likes || 0;
      });
      var voices = Object.values(byAuthor)
        .map(function (a) {
          return {
            handle: a.handle,
            name: a.name,
            posts: a.posts,
            avgViews: a.posts ? Math.round(a.sumViews / a.posts) : 0,
            avgLikes: a.posts ? Math.round(a.sumLikes / a.posts) : 0,
          };
        })
        .filter(function (a) { return a.posts >= 1; })
        .sort(function (a, b) { return b.avgViews - a.avgViews; })
        .slice(0, 3);
      if (voices.length > 0) out[topic.tag] = voices;
    });
    return out;
  }, [filtered, topics]);

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

  /* Mention aggregation — exclude cohort members so we see who's being
     *paid attention to from outside* (the dominant pattern is external).
     We still show @xai / @grok / @elonmusk in their own row up top since
     they're the dominant baselines. */
  var cohortHandles = React.useMemo(function () {
    var s = {};
    (window.COHORT.members || []).forEach(function (m) { s[m.handle.toLowerCase()] = true; });
    return s;
  }, []);
  var attention = React.useMemo(function () {
    var c = {};
    filtered.forEach(function (t) {
      (t.mentions || []).forEach(function (m) {
        var key = m.toLowerCase();
        c[key] = (c[key] || 0) + 1;
      });
    });
    var pairs = Object.entries(c).sort(function (a, b) { return b[1] - a[1]; });
    return pairs.map(function (e) {
      return { handle: e[0], count: e[1], inCohort: !!cohortHandles[e[0]] };
    });
  }, [filtered]);
  var maxAttention = attention.length > 0 ? attention[0].count : 1;

  /* Reusable bar row */
  function Bar(props) {
    var pct = props.value / Math.max(props.max, 1);
    var width = Math.max(2, pct * 100);
    return (
      <button onClick={props.onClick}
        style={{
          display: 'flex', alignItems: 'center', gap: 12, width: '100%',
          padding: '8px 12px', border: 'none', background: 'transparent',
          borderRadius: 8, cursor: 'pointer', transition: 'background .12s',
          color: 'inherit', textAlign: 'left',
        }}
        onMouseEnter={function (e) { e.currentTarget.style.background = 'var(--bg-hover)'; }}
        onMouseLeave={function (e) { e.currentTarget.style.background = 'transparent'; }}>
        <div style={{ width: 180, flexShrink: 0, fontFamily: 'var(--mono)', fontSize: 13, color: 'var(--text-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
          {props.label}
          {props.subLabel && <span style={{ marginLeft: 6, fontSize: 10, color: 'var(--text-tertiary)' }}>{props.subLabel}</span>}
        </div>
        <div style={{ flex: 1, height: 18, background: 'var(--bg-elevated)', borderRadius: 4, position: 'relative', overflow: 'hidden' }}>
          <div style={{ height: '100%', width: width + '%', background: props.color || 'var(--accent)', borderRadius: 4, transition: 'width .35s ease', opacity: 0.85 }}></div>
        </div>
        <div style={{ width: 50, flexShrink: 0, fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--text-secondary)', textAlign: 'right', fontFeatureSettings: "'tnum' 1" }}>{props.value}</div>
        <div style={{ width: 18, flexShrink: 0, fontSize: 11, color: 'var(--text-tertiary)' }}>→</div>
      </button>
    );
  }

  function TimeChip({ v, l }) {
    var active = timeRange === v;
    return (
      <button onClick={function () { setTimeRange(v); }}
        style={{
          padding: '5px 14px', borderRadius: 8,
          background: active ? 'var(--bg-elevated)' : 'transparent',
          border: '1px solid ' + (active ? 'var(--border-strong)' : 'var(--border-default)'),
          fontSize: 12, fontWeight: active ? 600 : 400,
          fontFamily: 'var(--mono)', color: active ? 'var(--text-primary)' : 'var(--text-tertiary)',
          cursor: 'pointer',
        }}>{l}</button>
    );
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
      {/* Toolbar */}
      <div style={{ padding: '10px 28px', borderBottom: '1px solid var(--border-subtle)', display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0, background: 'var(--bg-surface)' }}>
        <TimeChip v={1} l="24h" />
        <TimeChip v={7} l="7d" />
        <TimeChip v={14} l="14d" />
        <TimeChip v={30} l="30d" />
        <div style={{ flex: 1 }}></div>
        <span style={{ fontSize: 12, color: 'var(--text-tertiary)', fontFamily: 'var(--mono)', fontFeatureSettings: "'tnum' 1" }}>
          {filtered.length.toLocaleString()} tweets in window
        </span>
      </div>

      {/* Scrolling content */}
      <div style={{ flex: 1, overflowY: 'auto', padding: '24px 28px 60px' }}>

        {/* ── TOPICS ── */}
        <div style={{ marginBottom: 32 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 6 }}>
            <h2 style={{ fontSize: 14, fontWeight: 600, margin: 0, color: 'var(--text-primary)', letterSpacing: '-0.005em' }}>
              Topics
            </h2>
            <span style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>
              tagged in {taggedTweets} of {filtered.length} tweets ({Math.round(taggedTweets / Math.max(filtered.length, 1) * 100)}%)
            </span>
          </div>
          <p style={{ fontSize: 12, color: 'var(--text-tertiary)', margin: '0 0 14px 0', lineHeight: 1.55, maxWidth: 600 }}>
            {anyLLM
              ? 'Tagged by an LLM pass over the full tweet text (Claude Haiku, ' + TAXONOMY_NOTE + '). Click any topic to open the Timeline filtered to those tweets.'
              : 'Currently using only legacy regex tags (~14% coverage). Run `pnpm classify` to LLM-tag every tweet for near-complete coverage.'}
          </p>
          {topics.length === 0 ? (
            <div style={{ padding: '24px 12px', textAlign: 'center', color: 'var(--text-tertiary)', fontSize: 12 }}>
              No tagged topics in this window.
            </div>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
              {topics.map(function (t) {
                return <Bar key={t.tag} label={t.tag} value={t.count} max={maxTopic} color="var(--accent)" onClick={function () { onJumpToTimeline({ topic: t.tag }); }} />;
              })}
            </div>
          )}
        </div>

        {/* ── TOP VOICES PER TOPIC ── */}
        {Object.keys(topVoicesPerTopic).length > 0 && (
          <div style={{ marginBottom: 32 }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 6 }}>
              <h2 style={{ fontSize: 14, fontWeight: 600, margin: 0, color: 'var(--text-primary)', letterSpacing: '-0.005em' }}>
                Top voices per topic
              </h2>
              <span style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>
                who to @ if you're posting on this topic
              </span>
            </div>
            <p style={{ fontSize: 12, color: 'var(--text-tertiary)', margin: '0 0 14px 0', lineHeight: 1.55, maxWidth: 600 }}>
              Ranked by average views on the author's own originals (excluding quotes / replies / RTs, which inherit reach from other tweets). Click any handle to open the Timeline filtered by them.
            </p>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              {Object.keys(topVoicesPerTopic).map(function (topicTag) {
                var voices = topVoicesPerTopic[topicTag];
                return (
                  <div key={topicTag} style={{
                    background: 'var(--bg-card)', border: '1px solid var(--border-subtle)',
                    borderRadius: 10, padding: '12px 16px',
                  }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
                      <span style={{ fontSize: 12, fontFamily: 'var(--mono)', color: 'var(--accent)', fontWeight: 600 }}>
                        #{topicTag}
                      </span>
                      <button onClick={function () { onJumpToTimeline({ topic: topicTag }); }}
                        style={{ marginLeft: 'auto', fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', background: 'transparent', border: 'none', cursor: 'pointer', padding: 0 }}
                        onMouseEnter={function (e) { e.currentTarget.style.color = 'var(--text-primary)'; }}
                        onMouseLeave={function (e) { e.currentTarget.style.color = 'var(--text-tertiary)'; }}>
                        view all in Timeline →
                      </button>
                    </div>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                      {voices.map(function (v, i) {
                        return (
                          <button key={v.handle} onClick={function () { onJumpToTimeline({ handle: v.handle }); }}
                            style={{
                              display: 'flex', alignItems: 'center', gap: 10,
                              padding: '7px 10px', border: 'none', background: 'transparent',
                              borderRadius: 6, cursor: 'pointer', textAlign: 'left', color: 'inherit',
                            }}
                            onMouseEnter={function (e) { e.currentTarget.style.background = 'var(--bg-hover)'; }}
                            onMouseLeave={function (e) { e.currentTarget.style.background = 'transparent'; }}>
                            <span style={{ fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--text-disabled)', width: 14, textAlign: 'right', flexShrink: 0 }}>{i + 1}</span>
                            <span style={{ fontSize: 13, fontFamily: 'var(--mono)', color: 'var(--text-primary)', fontWeight: 500, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                              @{v.handle}
                            </span>
                            {v.name && <span style={{ fontSize: 11, color: 'var(--text-tertiary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', minWidth: 0 }}>{v.name}</span>}
                            <span style={{ marginLeft: 'auto', display: 'flex', gap: 12, fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', fontFeatureSettings: "'tnum' 1", flexShrink: 0 }}>
                              <span title="own originals on this topic">{v.posts} orig</span>
                              <span style={{ color: 'var(--accent)', fontWeight: 600 }} title="avg views per own original">{fmtViews(v.avgViews)} views</span>
                            </span>
                          </button>
                        );
                      })}
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        )}

        {/* ── ATTENTION ── */}
        <div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 6 }}>
            <h2 style={{ fontSize: 14, fontWeight: 600, margin: 0, color: 'var(--text-primary)', letterSpacing: '-0.005em' }}>
              Attention
            </h2>
            <span style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>
              who the cohort is collectively @-mentioning
            </span>
          </div>
          <p style={{ fontSize: 12, color: 'var(--text-tertiary)', margin: '0 0 14px 0', lineHeight: 1.55, maxWidth: 600 }}>
            73% of tweets carry at least one mention. Cohort-internal mentions are tagged <span style={{ color: 'var(--accent)', fontFamily: 'var(--mono)' }}>in</span>; everything else is the external surface the team talks at. Click a handle to filter the Timeline by it.
          </p>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
            {attention.slice(0, 40).map(function (a) {
              return <Bar
                key={a.handle}
                label={'@' + a.handle}
                subLabel={a.inCohort ? 'in' : null}
                value={a.count}
                max={maxAttention}
                color={a.inCohort ? 'rgba(249, 115, 22,0.55)' : 'rgba(255,255,255,0.55)'}
                onClick={function () { onJumpToTimeline({ handle: a.handle }); }}
              />;
            })}
          </div>
          {attention.length > 40 && (
            <div style={{ marginTop: 16, fontSize: 11, color: 'var(--text-tertiary)', textAlign: 'center' }}>
              showing top 40 of {attention.length.toLocaleString()} mentioned handles
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

window.TopicsView = TopicsView;
