/* Charts.jsx — Interactive data charts for the viewer */
/* Exports: ChartModal, MiniSparkline */

// ── Sparkline: tiny inline chart for stat cards ─────────────────
// Tiny line+area sparkline. `fill` mode renders the SVG with viewBox so it
// scales to its container's width — used as the hero visual in a stat card.
// `currentIndex` (optional) clips the data to [0..currentIndex] AND rescales
// the X-axis so the visible portion fills the full width every step. The
// Y-axis scale is still derived from the FULL series so heights at any step
// are directly comparable to the eventual peak.
function MiniSparkline({ data, width=120, height=28, color='var(--accent)', onClick, fill=false, currentIndex=null }) {
  if (!data || data.length < 2) return null;
  const max = Math.max(...data);
  const min = Math.min(...data);
  const range = max - min || 1;
  const lastIdx = currentIndex != null
    ? Math.max(1, Math.min(data.length - 1, currentIndex))
    : data.length - 1;
  const visible = data.slice(0, lastIdx + 1);
  const xDenom = visible.length - 1;  // visible points span the full width
  const pts = visible.map((v, i) => {
    const x = (i / xDenom) * width;
    const y = height - 2 - ((v - min) / range) * (height - 4);
    return `${x.toFixed(1)},${y.toFixed(1)}`;
  });
  const areaPath = `M 0,${height} L ${pts.join(' L ')} L ${width},${height} Z`;
  const linePath = `M ${pts.join(' L ')}`;

  const svgProps = fill
    ? { viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: 'none',
        style: { width: '100%', height: '100%', display: 'block', cursor: onClick ? 'pointer' : 'default' } }
    : { width, height,
        style: { display: 'block', cursor: onClick ? 'pointer' : 'default', marginTop: 4 } };
  return (
    <svg {...svgProps} onClick={onClick}>
      <path d={areaPath} fill={color} opacity={fill ? 0.15 : 0.1} />
      <path d={linePath} fill="none" stroke={color} strokeWidth={fill ? 2 : 1.5} strokeLinejoin="round" vectorEffect={fill ? 'non-scaling-stroke' : undefined} />
    </svg>
  );
}

// ── Full chart modal ────────────────────────────────────────────
function ChartModal({ type, onClose, allRoundData, currentRound, leaderboard, authors }) {
  if (!type) return null;

  const charts = {
    population: { title: 'Population Displaced Per Round', render: () => <PopChart data={allRoundData} current={currentRound} /> },
    timeline: { title: 'Elimination Order', render: () => <EliminationTimeline data={allRoundData} current={currentRound} /> },
    topteams: { title: 'Top Teams by Population', render: () => <TopTeamsChart data={allRoundData} current={currentRound} /> },
    leaderboard: { title: 'Winners Leaderboard', render: () => <Leaderboard data={leaderboard} authors={authors} /> },
  };

  const chart = charts[type];
  if (!chart) return null;

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 100, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}
      onClick={onClose}>
      <div style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.3)' }}></div>
      <div style={{ position: 'relative', background: 'white', borderRadius: 16, maxWidth: 680, width: '100%', maxHeight: '80vh', overflow: 'auto', boxShadow: '0 8px 32px rgba(0,0,0,0.12)', border: '1px solid var(--line)' }}
        onClick={e => e.stopPropagation()}>
        <div style={{ display: 'flex', alignItems: 'center', padding: '16px 20px', borderBottom: '1px solid var(--line)' }}>
          <span style={{ fontSize: 15, fontWeight: 700, flex: 1 }}>{chart.title}</span>
          <button onClick={onClose} style={{ background: 'none', border: 'none', fontSize: 18, color: 'var(--muted)', cursor: 'pointer', padding: '4px 8px' }}>✕</button>
        </div>
        <div style={{ padding: '20px' }}>
          {chart.render()}
        </div>
      </div>
    </div>
  );
}

// ── Teams Alive line chart ──────────────────────────────────────
function TeamsChart({ data, current }) {
  const W = 620, H = 200, PAD = { t: 10, r: 10, b: 30, l: 36 };
  const cw = W - PAD.l - PAD.r, ch = H - PAD.t - PAD.b;

  const pts = data.map((d, i) => {
    const x = PAD.l + (i / 49) * cw;
    const y = PAD.t + ch - (d.teamCount / 50) * ch;
    return { x, y, v: d.teamCount, round: i };
  });

  const linePath = pts.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ');
  const curPt = pts[current];

  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto' }}>
      {/* Grid lines */}
      {[10, 20, 30, 40, 50].map(v => {
        const y = PAD.t + ch - (v / 50) * ch;
        return <g key={v}>
          <line x1={PAD.l} y1={y} x2={W - PAD.r} y2={y} stroke="var(--line)" strokeWidth={0.5} />
          <text x={PAD.l - 6} y={y + 3} textAnchor="end" style={{ fontSize: 9, fill: 'var(--muted)', fontFamily: 'var(--font-mono)' }}>{v}</text>
        </g>;
      })}
      {/* X axis labels */}
      {[0, 10, 20, 30, 40, 49].map(r => {
        const x = PAD.l + (r / 49) * cw;
        return <text key={r} x={x} y={H - 8} textAnchor="middle" style={{ fontSize: 9, fill: 'var(--muted)', fontFamily: 'var(--font-mono)' }}>{r}</text>;
      })}
      {/* Area fill */}
      <path d={`${linePath} L ${pts[49].x},${PAD.t + ch} L ${pts[0].x},${PAD.t + ch} Z`} fill="var(--accent)" opacity={0.08} />
      {/* Line */}
      <path d={linePath} fill="none" stroke="var(--accent)" strokeWidth={2} strokeLinejoin="round" />
      {/* Current round indicator */}
      {curPt && <>
        <line x1={curPt.x} y1={PAD.t} x2={curPt.x} y2={PAD.t + ch} stroke="var(--accent)" strokeWidth={1} strokeDasharray="3,3" opacity={0.4} />
        <circle cx={curPt.x} cy={curPt.y} r={4} fill="var(--accent)" stroke="white" strokeWidth={2} />
        <text x={curPt.x} y={curPt.y - 10} textAnchor="middle" style={{ fontSize: 11, fontWeight: 700, fill: 'var(--ink)', fontFamily: 'var(--font)' }}>{curPt.v}</text>
      </>}
      {/* Axis labels */}
      <text x={W / 2} y={H - 0} textAnchor="middle" style={{ fontSize: 10, fill: 'var(--muted)', fontFamily: 'var(--font)' }}>Round</text>
    </svg>
  );
}

// ── Per-round population displacement (bar chart) ───────────────
// Each bar = population of the team eliminated that round. Bars get
// dramatically taller in late rounds when whole multi-state teams fall.
function PopChart({ data, current }) {
  const W = 620, H = 220, PAD = { t: 12, r: 10, b: 36, l: 56 };
  const cw = W - PAD.l - PAD.r, ch = H - PAD.t - PAD.b;
  const maxPop = Math.max(1, ...data.map(d => d.displacedPop || 0));
  const barW = cw / 50 - 1.5;

  const fmtPop = n => n >= 1e6 ? (n/1e6).toFixed(0)+'M' : n >= 1e3 ? (n/1e3).toFixed(0)+'K' : String(n);

  // y-axis grid lines at nice round values
  const tickVals = [maxPop*0.25, maxPop*0.5, maxPop*0.75, maxPop].map(v => Math.round(v));

  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto' }}>
      {tickVals.map(v => {
        const y = PAD.t + ch - (v / maxPop) * ch;
        return <g key={v}>
          <line x1={PAD.l} y1={y} x2={W - PAD.r} y2={y} stroke="var(--line)" strokeWidth={0.5} />
          <text x={PAD.l - 6} y={y + 3} textAnchor="end" style={{ fontSize: 9, fill: 'var(--muted)', fontFamily: 'var(--font-mono)' }}>{fmtPop(v)}</text>
        </g>;
      })}
      {[1, 10, 20, 30, 40, 50].map(stepN => {
        const x = PAD.l + ((stepN - 1) / 49) * cw + barW / 2;
        return <text key={stepN} x={x} y={H - 18} textAnchor="middle" style={{ fontSize: 9, fill: 'var(--muted)', fontFamily: 'var(--font-mono)' }}>{stepN}</text>;
      })}
      {data.map((d, i) => {
        const pop = d.displacedPop || 0;
        const x = PAD.l + (i / 49) * cw;
        const h = pop > 0 ? (pop / maxPop) * ch : 0;
        const isCurrent = i === current;
        return <rect key={i} x={x} y={PAD.t + ch - h} width={Math.max(barW, 2)} height={h}
          fill={isCurrent ? 'var(--accent)' : 'var(--blue)'}
          opacity={isCurrent ? 1 : 0.55} />;
      })}
      {current >= 0 && data[current]?.displacedPop > 0 && (
        <text x={PAD.l + (current / 49) * cw + barW / 2}
          y={PAD.t + ch - (data[current].displacedPop / maxPop) * ch - 4}
          textAnchor="middle"
          style={{ fontSize: 11, fontWeight: 700, fill: 'var(--ink)', fontFamily: 'var(--font)' }}>
          {fmtPop(data[current].displacedPop)}
        </text>
      )}
      <text x={W / 2} y={H - 4} textAnchor="middle" style={{ fontSize: 10, fill: 'var(--muted)', fontFamily: 'var(--font)' }}>Step</text>
    </svg>
  );
}

// ── Top Teams horizontal bar chart ──────────────────────────────
function TopTeamsChart({ data, current }) {
  const rd = data[current];
  if (!rd || !rd.topTeams) return <div style={{ color: 'var(--muted)', fontSize: 13 }}>No team data for this round.</div>;

  const maxPop = rd.topTeams[0]?.pop || 1;
  const CHART_COLORS = [
    'oklch(0.65 0.11 25)',  // warm
    'oklch(0.65 0.11 200)', // teal
    'oklch(0.65 0.11 280)', // blue
    'oklch(0.65 0.11 130)', // green
    'oklch(0.65 0.11 340)', // pink
    'oklch(0.65 0.11 60)',  // yellow
    'oklch(0.65 0.11 310)', // purple
  ];

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      {rd.topTeams.map((t, i) => (
        <div key={t.code} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ width: 90, fontSize: 12, fontWeight: 600, textAlign: 'right', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
            {t.loreName || t.name}
          </div>
          <div style={{ flex: 1, height: 24, background: 'var(--surface-2)', borderRadius: 4, overflow: 'hidden', position: 'relative' }}>
            <div style={{ height: '100%', width: (t.pop / maxPop * 100) + '%', background: CHART_COLORS[i % CHART_COLORS.length], borderRadius: 4, transition: 'width 250ms', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', paddingRight: 6 }}>
              {t.pop / maxPop > 0.25 && <span style={{ fontSize: 10, fontWeight: 600, color: 'white', fontFamily: 'var(--font-mono)' }}>{formatPopChart(t.pop)}</span>}
            </div>
          </div>
          <div style={{ width: 36, fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--muted)', textAlign: 'right' }}>{t.members}st</div>
        </div>
      ))}
    </div>
  );
}

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

// ── Elimination Timeline ────────────────────────────────────────
// Joins a list of names with commas and an "and" before the last item.
function joinList(items) {
  if (!items?.length) return '';
  if (items.length === 1) return items[0];
  if (items.length === 2) return `${items[0]} and ${items[1]}`;
  return `${items.slice(0, -1).join(', ')}, and ${items[items.length - 1]}`;
}

function EliminationTimeline({ data, current }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 2, maxHeight: 480, overflowY: 'auto' }}>
      {data.slice(1).map((rd, i) => {
        const r = i + 1;
        const isCurrent = r === current;
        const isPast = r <= current;
        const absorbers = rd.absorberNames || [];
        return (
          <div key={r} style={{
            display: 'flex', alignItems: 'flex-start', gap: 10, padding: '8px 10px',
            borderRadius: 6, background: isCurrent ? 'var(--accent-soft)' : 'transparent',
            opacity: isPast ? 1 : 0.4,
          }}>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--muted)', width: 24, textAlign: 'right', flexShrink: 0, paddingTop: 2 }}>R{r}</span>
            <span style={{ width: 10, height: 10, borderRadius: 3, background: rd.deletedColor || 'var(--line)', flexShrink: 0, marginTop: 3 }}></span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13, fontWeight: isCurrent ? 700 : 600, color: isCurrent ? 'var(--accent)' : 'var(--ink)', lineHeight: 1.3 }}>
                {rd.deletedName || '—'}
              </div>
              {absorbers.length > 0 && (
                <div style={{ fontSize: 11, color: 'var(--ink-2)', marginTop: 1, lineHeight: 1.4 }}>
                  conceded to <span style={{ color: 'var(--ink)' }}>{joinList(absorbers)}</span>
                </div>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ── Leaderboard ─────────────────────────────────────────────────
function Leaderboard({ data, authors }) {
  if (!data) return <div style={{ color: 'var(--muted)' }}>No leaderboard data.</div>;
  const rows = Object.entries(data)
    .map(([author, s]) => ({ author, ...s }))
    .sort((a, b) => b.wins - a.wins || b.total_win_score - a.total_win_score);
  const maxWins = rows[0]?.wins || 1;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 1, maxHeight: 480, overflowY: 'auto' }}>
      {rows.map((r, i) => {
        const key = (r.author || '').replace(/^u\//, '');
        const a = authors?.[key];
        const icon = (a?.icon_local || a?.icon_img || '').replace(/&amp;/g, '&');
        return (
          <div key={r.author} style={{
            display: 'flex', alignItems: 'center', gap: 10, padding: '6px 8px',
            borderRadius: 6, background: i % 2 ? 'transparent' : 'var(--surface-2)',
          }}>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--muted)', width: 20, textAlign: 'right' }}>{i + 1}</span>
            {icon
              ? <img src={icon} alt="" style={{ width: 22, height: 22, borderRadius: 999, flexShrink: 0, objectFit: 'cover', background: 'var(--surface-2)' }} onError={e => e.target.style.display = 'none'} />
              : <div style={{ width: 22, height: 22, borderRadius: 999, background: 'var(--surface-2)', flexShrink: 0 }} />}
            <a href={`https://www.reddit.com/user/${key}`} target="_blank" rel="noopener"
              style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink)', flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
              {r.author}
            </a>
            <div style={{ flex: 1, height: 6, background: 'var(--surface-2)', borderRadius: 3, overflow: 'hidden', maxWidth: 120 }}>
              <div style={{ height: '100%', width: (r.wins / maxWins * 100) + '%', background: 'var(--accent)' }}></div>
            </div>
            <span style={{ fontSize: 11, fontWeight: 600, width: 24, textAlign: 'right' }}>{r.wins}×</span>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--muted)', width: 50, textAlign: 'right' }}>
              ▲ {(r.total_win_score || 0).toLocaleString()}
            </span>
          </div>
        );
      })}
      <div style={{ fontSize: 11, color: 'var(--muted)', textAlign: 'center', padding: '10px 0 4px', fontStyle: 'italic' }}>
        + 1 deleted account (won rounds 2 &amp; 44)
      </div>
    </div>
  );
}

window.ChartModal = ChartModal;
window.MiniSparkline = MiniSparkline;
