/* Scatter View — Followers × Priority Score quadrant chart.
   X axis is the Phase-2 scoring engine output (Layer-1 candidate filter →
   Layer-2 light score → Layer-3 heavy score for top-100). Non-candidates
   default to 0. The old followers×following diet plot didn't tell us much
   about who's worth talking to; this one ranks visibility vs. opportunity. */

function fmtScatterNum(n) { return n >= 1e6 ? (n / 1e6).toFixed(1) + 'M' : n >= 1e3 ? (n / 1e3).toFixed(1) + 'K' : String(n); }
function fmtScore(s) { return (Math.round(s * 1000) / 1000).toFixed(2); }

/* ═══════ SCATTER PLOT ═══════ */
function ScatterView() {
  var [hovered, setHovered] = React.useState(null);
  var [selected, setSelected] = React.useState(null);
  var [logScale, setLogScale] = React.useState(true);  /* log/linear toggle now applies to Y (followers) only */
  var [colorBy, setColorBy] = React.useState('surface'); /* surface | activity | none */
  var svgRef = React.useRef(null);

  var members = window.COHORT.members;
  var personal = React.useMemo(function () {
    return members.filter(function (m) { return !m.isOfficial && m.status === 'ok'; });
  }, []);

  /* Pull priority scores from the scoring engine. Non-candidates → 0. */
  var scoreByHandle = React.useMemo(function () {
    var byH = (window.SCORING && window.SCORING.getDefault().byHandle) || {};
    var out = {};
    personal.forEach(function (m) {
      out[m.handle] = byH[m.handle] ? byH[m.handle].priorityScore : 0;
    });
    return out;
  }, [personal]);
  function score(m) { return scoreByHandle[m.handle] || 0; }

  /* Scale functions */
  var maxFollowers = React.useMemo(function () { return Math.max.apply(null, personal.map(function (m) { return m.followers; })); }, [personal]);
  /* Priority score domain is the cohort's actual top — anchored at 1 so future
     reshuffles don't make today's max look artificially "perfect". */
  var maxScore = 1;

  /* Chart dimensions — viewBox coords. The SVG element below uses width:100% so
     the actual rendered size fills the container; these numbers just set the
     internal coordinate system and the labels/spacing aspect ratio. */
  var W = 1400, H = 700;
  var PAD = { top: 30, right: 30, bottom: 50, left: 60 };
  var plotW = W - PAD.left - PAD.right;
  var plotH = H - PAD.top - PAD.bottom;

  /* X is always linear (score is naturally 0–1). Y respects the log toggle. */
  function scaleX(v) {
    return PAD.left + (v / maxScore) * plotW;
  }
  function scaleY(v) {
    if (logScale) return PAD.top + plotH - (Math.log10(Math.max(1, v) + 1) / Math.log10(maxFollowers + 2)) * plotH;
    return PAD.top + plotH - (v / Math.max(maxFollowers, 1)) * plotH;
  }

  /* Quadrant thresholds */
  var followersMed = React.useMemo(function () {
    var sorted = personal.map(function (m) { return m.followers; }).sort(function (a, b) { return a - b; });
    return sorted[Math.floor(sorted.length / 2)];
  }, [personal]);
  /* Median of *scored* members only — including all the zero non-candidates
     would pin the median near 0 and the right-half would be empty. */
  var scoreMed = React.useMemo(function () {
    var scored = personal.map(score).filter(function (s) { return s > 0; }).sort(function (a, b) { return a - b; });
    return scored.length > 0 ? scored[Math.floor(scored.length / 2)] : 0.3;
  }, [personal, scoreByHandle]);

  /* Color mapping */
  function dotColor(m) {
    if (colorBy === 'surface') {
      if (m.surfaceTier === 'high') return 'var(--accent)';
      if (m.surfaceTier === 'low') return 'var(--text-disabled)';
      return 'rgba(255,255,255,0.45)';
    }
    if (colorBy === 'activity') {
      if (m.activityPersona === 'heavy' || m.activityPersona === 'medium') return 'var(--accent)';
      if (m.activityPersona === 'light') return 'rgba(255,255,255,0.55)';
      if (m.activityPersona === 'lurker') return 'rgba(255,255,255,0.25)';
      return 'var(--text-disabled)';
    }
    return 'rgba(255,255,255,0.40)';
  }
  function dotRadius(m) {
    if (m.external) return 6;
    if (m.followers > 10000) return 5;
    if (m.followers > 1000) return 4;
    return 3;
  }

  /* Y-axis ticks */
  var yTicks = logScale
    ? [0, 10, 100, 1000, 10000, 100000].filter(function (t) { return t <= maxFollowers * 1.1; })
    : (function () { var s = maxFollowers > 50000 ? 10000 : maxFollowers > 5000 ? 2000 : 500; var a = []; for (var i = 0; i <= maxFollowers; i += s) a.push(i); return a; })();
  var xTicks = [0, 0.2, 0.4, 0.6, 0.8, 1.0];

  /* Quadrant labels — interpret what each corner means.
     Right side (high priority) is where the actually-interesting people are. */
  var qLabels = [
    { label: 'Low reach · Off-target',  x: PAD.left + plotW * 0.15, y: PAD.top + plotH * 0.85 },
    { label: 'Hidden gem',              x: PAD.left + plotW * 0.75, y: PAD.top + plotH * 0.85 },
    { label: 'Visible noise',           x: PAD.left + plotW * 0.15, y: PAD.top + plotH * 0.15 },
    { label: 'Core target',             x: PAD.left + plotW * 0.75, y: PAD.top + plotH * 0.15 },
  ];

  var hovPerson = hovered ? personal.find(function (m) { return m.handle === hovered; }) : null;
  var selPerson = selected ? members.find(function (m) { return m.handle === selected; }) : null;

  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: 12, flexShrink: 0, background: 'var(--bg-surface)' }}>
        {/* Scale toggle */}
        <div style={{ display: 'flex', background: 'var(--bg-card)', borderRadius: 10, border: '1px solid var(--border-default)', overflow: 'hidden' }}>
          {[{ v: true, l: 'Log' }, { v: false, l: 'Linear' }].map(function (s) {
            var active = logScale === s.v;
            return <button key={s.l} onClick={function () { setLogScale(s.v); }}
              style={{ padding: '5px 14px', border: 'none', fontSize: 12, fontWeight: active ? 600 : 400, background: active ? 'var(--bg-elevated)' : 'transparent', color: active ? 'var(--text-primary)' : 'var(--text-tertiary)', cursor: 'pointer', fontFamily: 'var(--sans)', transition: 'all .12s' }}>{s.l}</button>;
          })}
        </div>

        {/* Color by */}
        <span style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>Color:</span>
        <div style={{ display: 'flex', background: 'var(--bg-card)', borderRadius: 10, border: '1px solid var(--border-default)', overflow: 'hidden' }}>
          {[{ v: 'surface', l: 'Surface Tier' }, { v: 'activity', l: 'Activity' }, { v: 'none', l: 'None' }].map(function (s) {
            var active = colorBy === s.v;
            return <button key={s.v} onClick={function () { setColorBy(s.v); }}
              style={{ padding: '5px 14px', border: 'none', fontSize: 12, fontWeight: active ? 600 : 400, background: active ? 'var(--bg-elevated)' : 'transparent', color: active ? 'var(--text-primary)' : 'var(--text-tertiary)', cursor: 'pointer', fontFamily: 'var(--sans)', transition: 'all .12s' }}>{s.l}</button>;
          })}
        </div>

        <div style={{ flex: 1 }}></div>
        <span style={{ fontSize: 12, color: 'var(--text-tertiary)', fontFamily: 'var(--mono)', fontFeatureSettings: "'tnum' 1" }}>
          {personal.length} profiles
        </span>
      </div>

      {/* Chart + optional drawer */}
      <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
        <div style={{ flex: 1, overflowY: 'auto', padding: '20px 28px' }}>
          <svg ref={svgRef} viewBox={'0 0 ' + W + ' ' + H} preserveAspectRatio="xMidYMid meet" style={{ width: '100%', height: 'auto', display: 'block' }}>
            {/* Background */}
            <rect x={PAD.left} y={PAD.top} width={plotW} height={plotH} fill="var(--bg-card)" rx="4" />

            {/* Quadrant dividers */}
            <line x1={scaleX(scoreMed)} y1={PAD.top} x2={scaleX(scoreMed)} y2={PAD.top + plotH}
              stroke="var(--border-default)" strokeWidth="1" strokeDasharray="4,4" />
            <line x1={PAD.left} y1={scaleY(followersMed)} x2={PAD.left + plotW} y2={scaleY(followersMed)}
              stroke="var(--border-default)" strokeWidth="1" strokeDasharray="4,4" />

            {/* Quadrant labels */}
            {qLabels.map(function (q) {
              return <text key={q.label} x={q.x} y={q.y} fill="var(--text-disabled)" fontSize="10" fontFamily="var(--sans)" textAnchor="middle">{q.label}</text>;
            })}

            {/* Y-axis ticks */}
            {yTicks.map(function (t) {
              var y = scaleY(t);
              return (
                <React.Fragment key={'y' + t}>
                  <line x1={PAD.left} y1={y} x2={PAD.left + plotW} y2={y} stroke="var(--border-subtle)" strokeWidth="0.5" />
                  <text x={PAD.left - 8} y={y + 4} fill="var(--text-disabled)" fontSize="10" fontFamily="var(--mono)" textAnchor="end">{fmtScatterNum(t)}</text>
                </React.Fragment>
              );
            })}

            {/* X-axis ticks — priority score 0..1 */}
            {xTicks.map(function (t) {
              var x = scaleX(t);
              return (
                <React.Fragment key={'x' + t}>
                  <line x1={x} y1={PAD.top} x2={x} y2={PAD.top + plotH} stroke="var(--border-subtle)" strokeWidth="0.5" />
                  <text x={x} y={PAD.top + plotH + 18} fill="var(--text-disabled)" fontSize="10" fontFamily="var(--mono)" textAnchor="middle">{t.toFixed(1)}</text>
                </React.Fragment>
              );
            })}

            {/* Axis labels */}
            <text x={PAD.left + plotW / 2} y={H - 6} fill="var(--text-tertiary)" fontSize="12" fontFamily="var(--sans)" textAnchor="middle" fontWeight="500">Priority Score →</text>
            <text x={14} y={PAD.top + plotH / 2} fill="var(--text-tertiary)" fontSize="12" fontFamily="var(--sans)" textAnchor="middle" fontWeight="500" transform={'rotate(-90, 14, ' + (PAD.top + plotH / 2) + ')'}>Followers →</text>

            {/* Dots */}
            {personal.map(function (m) {
              var cx = scaleX(score(m));
              var cy = scaleY(m.followers);
              var r = dotRadius(m);
              var isHov = hovered === m.handle;
              var isSel = selected === m.handle;
              var isExt = !!m.external;
              return (
                <circle key={m.handle} cx={cx} cy={cy} r={isHov ? r + 2 : r}
                  fill={dotColor(m)}
                  stroke={isExt ? 'var(--accent)' : isHov ? '#fff' : 'none'}
                  strokeWidth={isExt ? 1.5 : isHov ? 1 : 0}
                  opacity={hovered && !isHov ? 0.25 : 0.85}
                  style={{ cursor: 'pointer', transition: 'opacity .15s, r .1s' }}
                  onMouseEnter={function () { setHovered(m.handle); }}
                  onMouseLeave={function () { setHovered(null); }}
                  onClick={function () { setSelected(m.handle); }}
                />
              );
            })}

            {/* Hover tooltip */}
            {hovPerson && (function () {
              var cx = scaleX(score(hovPerson));
              var cy = scaleY(hovPerson.followers);
              var tx = cx + 12, ty = cy - 12;
              if (tx + 180 > W) tx = cx - 190;
              if (ty < PAD.top + 10) ty = cy + 12;
              return (
                <g>
                  <rect x={tx} y={ty} width="180" height="68" rx="8" fill="var(--bg-elevated)" stroke="var(--border-strong)" strokeWidth="1" />
                  <text x={tx + 10} y={ty + 18} fill="var(--text-primary)" fontSize="12" fontFamily="var(--mono)" fontWeight="600">@{hovPerson.handle}</text>
                  {hovPerson.name && <text x={tx + 10} y={ty + 32} fill="var(--text-tertiary)" fontSize="11" fontFamily="var(--sans)">{hovPerson.name}</text>}
                  <text x={tx + 10} y={ty + 48} fill="var(--text-secondary)" fontSize="11" fontFamily="var(--mono)">
                    {fmtScatterNum(hovPerson.followers)} followers
                  </text>
                  <text x={tx + 10} y={ty + 60} fill="var(--accent)" fontSize="11" fontFamily="var(--mono)">
                    score {fmtScore(score(hovPerson))}
                  </text>
                </g>
              );
            })()}

            {/* Median labels */}
            <text x={scaleX(scoreMed) + 4} y={PAD.top + 12} fill="var(--text-disabled)" fontSize="9" fontFamily="var(--mono)">med: {fmtScore(scoreMed)}</text>
            <text x={PAD.left + 4} y={scaleY(followersMed) - 4} fill="var(--text-disabled)" fontSize="9" fontFamily="var(--mono)">med: {followersMed}</text>
          </svg>

          {/* Legend */}
          <div style={{ display: 'flex', gap: 16, marginTop: 12, flexWrap: 'wrap', alignItems: 'center' }}>
            {colorBy === 'surface' && (
              <React.Fragment>
                <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-tertiary)' }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--text-disabled)' }}></span> Low surface
                </span>
                <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-tertiary)' }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'rgba(255,255,255,0.45)' }}></span> Mid surface
                </span>
                <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-tertiary)' }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--accent)' }}></span> High surface
                </span>
              </React.Fragment>
            )}
            {colorBy === 'activity' && (
              <React.Fragment>
                <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-tertiary)' }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--text-disabled)' }}></span> Dormant
                </span>
                <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-tertiary)' }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'rgba(255,255,255,0.25)' }}></span> Lurker
                </span>
                <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-tertiary)' }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'rgba(255,255,255,0.55)' }}></span> Light
                </span>
                <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-tertiary)' }}>
                  <span style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--accent)' }}></span> Medium / Heavy
                </span>
              </React.Fragment>
            )}
            <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: 'var(--text-tertiary)', marginLeft: 'auto' }}>
              <span style={{ width: 10, height: 10, borderRadius: '50%', border: '1.5px solid var(--accent)', background: 'transparent' }}></span> External target
            </span>
            <span style={{ fontSize: 11, color: 'var(--text-disabled)', fontStyle: 'italic' }}>
              Click a dot to open profile drawer
            </span>
          </div>
        </div>

        {/* Person Drawer */}
        {selPerson && <PersonDrawer person={selPerson} onClose={function () { setSelected(null); }} />}
      </div>
    </div>
  );
}

window.ScatterView = ScatterView;
