/* Baby Names Almanac — chart, sparkline, name card, raw pivot.
   Adapted from the design bundle. Operates on series passed in as props
   (no global window.BABY_DATA — data is fetched via API and injected by App). */

const PALETTES = {
  F: ['#a23a4a', '#c97a55', '#7c5e3c', '#5a7159', '#8a4d6b', '#b89455'],
  M: ['#2f4a6b', '#5a7159', '#7c5e3c', '#8a4d4d', '#3d6b73', '#5e4f7a'],
};

function fmt(n) {
  if (n == null || isNaN(n)) return '—';
  if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M';
  if (n >= 1000) return (n / 1000).toFixed(n >= 10000 ? 0 : 1) + 'k';
  return Math.round(n).toLocaleString();
}
function fmtFull(n) { return n == null ? '—' : Math.round(n).toLocaleString(); }
function ord(n) {
  if (n == null) return '—';
  const s = ['th','st','nd','rd'], v = n % 100;
  return n + (s[(v - 20) % 10] || s[v] || s[0]);
}

// ----- Trend Chart -----
function TrendChart({ series, metric, yearRange, mode, chartStyle }) {
  const [hover, setHover] = React.useState(null);
  const wrapRef = React.useRef(null);

  const W = 1100, H = 360;
  const PAD = { l: 56, r: 24, t: 18, b: 36 };
  const innerW = W - PAD.l - PAD.r;
  const innerH = H - PAD.t - PAD.b;

  const [y0, y1] = yearRange;
  const palette = PALETTES[mode];

  const filtered = series.map((s, i) => ({
    name: s.name,
    color: s.color || palette[i % palette.length],
    points: (s.series || [])
      .filter(p => p.year >= y0 && p.year <= y1)
      .map(p => ({ year: p.year, val: p[metric.key] }))
      .filter(p => p.val != null && !isNaN(p.val)),
  }));

  let yMin = Infinity, yMax = -Infinity;
  filtered.forEach(s => s.points.forEach(p => {
    if (p.val < yMin) yMin = p.val;
    if (p.val > yMax) yMax = p.val;
  }));
  if (!isFinite(yMin)) { yMin = 0; yMax = 1; }
  if (metric.key === 'rank') {
    yMin = Math.max(1, Math.floor(yMin * 0.7));
    yMax = Math.ceil(yMax * 1.05);
  } else {
    yMin = 0;
    yMax = yMax * 1.08 || 1;
  }

  const xScale = year => PAD.l + ((year - y0) / Math.max(1, (y1 - y0))) * innerW;
  const yScale = val => {
    if (metric.key === 'rank') {
      return PAD.t + ((val - yMin) / (yMax - yMin)) * innerH;
    }
    return PAD.t + (1 - (val - yMin) / (yMax - yMin)) * innerH;
  };

  const xTicks = [];
  const yearSpan = y1 - y0;
  const step = yearSpan > 100 ? 20 : yearSpan > 50 ? 10 : yearSpan > 20 ? 5 : 2;
  for (let y = Math.ceil(y0 / step) * step; y <= y1; y += step) xTicks.push(y);

  const yTicks = [];
  const yTickCount = 5;
  for (let i = 0; i <= yTickCount; i++) {
    const v = yMin + (yMax - yMin) * (i / yTickCount);
    yTicks.push(metric.key === 'rank' ? Math.round(v) : v);
  }

  function pathFor(points) {
    if (points.length === 0) return '';
    return points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${xScale(p.year).toFixed(2)} ${yScale(p.val).toFixed(2)}`).join(' ');
  }
  function areaFor(points) {
    if (points.length === 0) return '';
    const baseY = metric.key === 'rank' ? yScale(yMax) : H - PAD.b;
    return points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${xScale(p.year).toFixed(2)} ${yScale(p.val).toFixed(2)}`).join(' ')
      + ` L ${xScale(points[points.length - 1].year).toFixed(2)} ${baseY} L ${xScale(points[0].year).toFixed(2)} ${baseY} Z`;
  }

  function onMove(e) {
    const svg = e.currentTarget;
    const rect = svg.getBoundingClientRect();
    const x = (e.clientX - rect.left) * (W / rect.width);
    if (x < PAD.l || x > W - PAD.r) { setHover(null); return; }
    const yearF = y0 + ((x - PAD.l) / innerW) * (y1 - y0);
    const year = Math.round(yearF);
    setHover({ year, clientX: e.clientX - rect.left, clientY: e.clientY - rect.top, rect });
  }

  function fmtVal(v) {
    if (v == null) return '—';
    if (metric.key === 'count') return fmtFull(v);
    if (metric.key === 'rank') return '#' + Math.round(v);
    if (metric.key === 'share') return (v * 100).toFixed(3) + '%';
    if (metric.key === 'per10k') return v.toFixed(1) + ' / 10k';
    if (metric.key === 'percentile') return v.toFixed(1) + '%';
    return v;
  }

  const hoverData = hover ? filtered.map(s => {
    const pt = s.points.find(p => p.year === hover.year);
    return pt ? { name: s.name, color: s.color, val: pt.val } : { name: s.name, color: s.color, val: null };
  }) : null;

  return (
    <div className="chart-svg-wrap" ref={wrapRef}>
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" onMouseMove={onMove} onMouseLeave={() => setHover(null)}>
        {yTicks.map((t, i) => {
          const yp = yScale(t);
          return (
            <g key={'y' + i}>
              <line x1={PAD.l} x2={W - PAD.r} y1={yp} y2={yp} stroke="#d8cfb8" strokeWidth="0.5" strokeDasharray={i === 0 ? '0' : '2 3'} />
              <text x={PAD.l - 8} y={yp + 3} textAnchor="end" fontFamily="JetBrains Mono, monospace" fontSize="10" fill="#8a7f70">
                {metric.key === 'count' ? fmt(t) :
                 metric.key === 'rank' ? '#' + Math.round(t) :
                 metric.key === 'share' ? (t * 100).toFixed(2) + '%' :
                 metric.key === 'per10k' ? t.toFixed(1) :
                 metric.key === 'percentile' ? t.toFixed(0) + '%' : t}
              </text>
            </g>
          );
        })}
        {xTicks.map((t, i) => {
          const xp = xScale(t);
          return (
            <g key={'x' + i}>
              <line x1={xp} x2={xp} y1={H - PAD.b} y2={H - PAD.b + 4} stroke="#a89b7e" strokeWidth="0.5" />
              <text x={xp} y={H - PAD.b + 16} textAnchor="middle" fontFamily="JetBrains Mono, monospace" fontSize="10" fill="#8a7f70">{t}</text>
            </g>
          );
        })}
        <line x1={PAD.l} x2={W - PAD.r} y1={H - PAD.b} y2={H - PAD.b} stroke="#1a1714" strokeWidth="1" />
        <line x1={PAD.l} x2={PAD.l} y1={PAD.t} y2={H - PAD.b} stroke="#1a1714" strokeWidth="1" />

        {chartStyle === 'area' && filtered.map((s, i) => (
          <path key={'a' + i} d={areaFor(s.points)} fill={s.color} fillOpacity="0.12" stroke="none" />
        ))}

        {filtered.map((s, i) => (
          <g key={'l' + i}>
            <path d={pathFor(s.points)} fill="none" stroke={s.color} strokeWidth="1.8" strokeLinejoin="round" strokeLinecap="round" />
            {chartStyle === 'dots' && s.points.map((p, j) => (
              <circle key={j} cx={xScale(p.year)} cy={yScale(p.val)} r="2.5" fill={s.color} />
            ))}
          </g>
        ))}

        {hover && (
          <g>
            <line x1={xScale(hover.year)} x2={xScale(hover.year)} y1={PAD.t} y2={H - PAD.b} stroke="#1a1714" strokeWidth="0.5" strokeDasharray="3 3" />
            {hoverData.map((h, i) => h.val != null ? (
              <circle key={i} cx={xScale(hover.year)} cy={yScale(h.val)} r="4" fill={h.color} stroke="#f4efe4" strokeWidth="1.5" />
            ) : null)}
          </g>
        )}
      </svg>

      {hover && hoverData && (
        <div className="chart-tip" style={{ left: hover.clientX, top: hover.clientY }}>
          <div className="row"><strong>{hover.year}</strong></div>
          {hoverData.map((h, i) => (
            <div className="row" key={i}>
              <span className="nm" style={{ color: h.color }}>{h.name}</span>
              <span>{fmtVal(h.val)}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ----- Sparkline -----
function Sparkline({ points, color }) {
  if (!points || points.length === 0) return null;
  const W = 280, H = 50;
  let max = -Infinity, min = Infinity;
  points.forEach(p => { if (p.val > max) max = p.val; if (p.val < min) min = p.val; });
  const yr0 = points[0].year, yr1 = points[points.length - 1].year;
  const xs = y => ((y - yr0) / Math.max(1, yr1 - yr0)) * W;
  const ys = v => H - 4 - ((v - min) / Math.max(1, (max - min))) * (H - 8);
  const path = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${xs(p.year).toFixed(1)} ${ys(p.val).toFixed(1)}`).join(' ');
  const area = path + ` L ${xs(points[points.length - 1].year).toFixed(1)} ${H} L ${xs(points[0].year).toFixed(1)} ${H} Z`;
  return (
    <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none">
      <path d={area} fill={color} fillOpacity="0.14" />
      <path d={path} fill="none" stroke={color} strokeWidth="1.5" />
    </svg>
  );
}

// ----- Trend label -----
function computeTrendLabel(series) {
  if (!series || series.length < 2) return { label: 'Rarely used', cls: 'rare' };
  const last = series[series.length - 1];
  const peakRow = series.reduce((a, b) => (b.count > a.count ? b : a), series[0]);
  const recent = series.slice(-10);
  const earlier = series.slice(-25, -10);
  const recentAvg = recent.reduce((a, r) => a + r.count, 0) / Math.max(1, recent.length);
  const earlierAvg = earlier.reduce((a, r) => a + r.count, 0) / Math.max(1, earlier.length);

  if (last.count < 100 && peakRow.count > 5000 && peakRow.year < 1960) {
    if (recentAvg > earlierAvg * 1.3) return { label: 'Coming back', cls: 'vintage' };
    return { label: 'Rarely used', cls: 'rare' };
  }
  if (peakRow.year < 1960 && last.count > peakRow.count * 0.4 && (recentAvg > earlierAvg * 1.4)) {
    return { label: 'Coming back', cls: 'vintage' };
  }
  if (recentAvg > earlierAvg * 1.25) return { label: 'Getting more popular', cls: 'rising' };
  if (recentAvg < earlierAvg * 0.75) return { label: 'Getting less popular', cls: 'falling' };
  if (last.count < 200) return { label: 'Rarely used', cls: 'rare' };
  return { label: 'Holding steady', cls: 'stable' };
}

// ----- Name card -----
function NameOrigin({ name, info }) {
  if (!info) {
    return (
      <div className="name-origin pending">
        <div className="origin-eyebrow">Origin & meaning</div>
        <p>Loading origin details…</p>
      </div>
    );
  }
  if (!info.available) {
    return (
      <div className="name-origin muted">
        <div className="origin-eyebrow">Origin & meaning</div>
        <p>Origin and meaning are not available yet.</p>
      </div>
    );
  }
  const originLabel = (info.origins || []).join(', ') || 'Origin uncertain';
  return (
    <div className="name-origin">
      <div className="origin-eyebrow">Origin & meaning</div>
      <p>{info.description || `${name} is commonly linked to ${originLabel}.`}</p>
      <div className="origin-facts">
        <span><strong>Origin</strong>{originLabel}</span>
        <span><strong>Meaning</strong>{info.meaning || 'Meaning uncertain'}</span>
      </div>
      <div className="origin-source">LLM-generated note · {info.confidence || 'medium'} confidence</div>
    </div>
  );
}

function NameCard({ name, series, color, ord: idx, nameInfo, showSparkline }) {
  if (!series || series.length === 0) {
    return (
      <div className="name-card" style={{ '--card-color': color }}>
        <div className="top">
          <div className="ord">No. {String(idx + 1).padStart(2, '0')}</div>
          <div className="name"><span className="sw"></span>{name}</div>
          <div className="trend-tag rare">Not in dataset</div>
        </div>
        <NameOrigin name={name} info={nameInfo} />
      </div>
    );
  }
  const last = series[series.length - 1];
  const peak = series.reduce((a, b) => (b.count > a.count ? b : a), series[0]);
  const bestRank = series.reduce((a, b) => (b.rank < a.rank ? b : a), series[0]);
  const trend = computeTrendLabel(series);
  const sparkPts = series.map(s => ({ year: s.year, val: s.count }));

  return (
    <div className="name-card" style={{ '--card-color': color }}>
      <div className="top">
        <div className="spread">
          <div className="ord">No. {String(idx + 1).padStart(2, '0')} · {last.year}</div>
          <span className={`trend-tag ${trend.cls}`}>{trend.label}</span>
        </div>
        <div className="name"><span className="sw"></span>{name}</div>
      </div>
      <div className="stats name-card-stats">
        <div className="stat stat-primary">
          <div className="lbl">Current popularity</div>
          <div className="val">{last.rank ? '#' + last.rank : '—'}</div>
        </div>
        <div className="stat stat-primary">
          <div className="lbl">Babies named {name}</div>
          <div className="val">{fmt(last.count)} <span className="unit">babies</span></div>
        </div>
        <div className="stat stat-primary">
          <div className="lbl">Biggest year</div>
          <div className="val">{peak.year}</div>
          <div className="hint">{fmt(peak.count)} babies</div>
        </div>
      </div>
      <div className="name-card-details">
        <div><span>Best popularity</span><strong>#{bestRank.rank}</strong> <em>{bestRank.year}</em></div>
        <div><span>More popular than</span><strong>{last.percentile != null ? last.percentile.toFixed(1) + '%' : '—'}</strong></div>
      </div>
      <NameOrigin name={name} info={nameInfo} />
      {showSparkline !== false && (
        <div className="spark"><Sparkline points={sparkPts} color={color} /></div>
      )}
    </div>
  );
}

// ----- Raw data pivot (selected names only) -----
function RawTable({ series, mode, density }) {
  const valid = series.filter(s => s.series && s.series.length);
  const [search, setSearch] = React.useState('');
  const [yearStart, setYearStart] = React.useState(2000);
  const [yearEnd, setYearEnd] = React.useState(2025);
  const [sortBy, setSortBy] = React.useState('recent');

  const years = [];
  for (let y = yearEnd; y >= yearStart; y--) years.push(y);

  const allRows = React.useMemo(() => {
    return valid.map(s => {
      const counts = {};
      let total = 0, peak = 0, peakYear = null, bestRank = Infinity, latestCount = 0;
      s.series.forEach(p => {
        if (p.year >= yearStart && p.year <= yearEnd) {
          counts[p.year] = p.count;
          total += p.count;
          if (p.count > peak) { peak = p.count; peakYear = p.year; }
          if (p.rank < bestRank) bestRank = p.rank;
          if (p.year === yearEnd) latestCount = p.count;
        }
      });
      return { name: s.name, counts, total, peak, peakYear, bestRank, latestCount };
    });
  }, [valid, yearStart, yearEnd]);

  const filtered = React.useMemo(() => {
    let r = allRows;
    if (search.trim()) {
      const q = search.toLowerCase();
      r = r.filter(x => x.name.toLowerCase().includes(q));
    }
    r = [...r];
    if (sortBy === 'recent') r.sort((a, b) => b.latestCount - a.latestCount);
    else if (sortBy === 'peak') r.sort((a, b) => b.peak - a.peak);
    else if (sortBy === 'best-rank') r.sort((a, b) => a.bestRank - b.bestRank);
    else if (sortBy === 'total') r.sort((a, b) => b.total - a.total);
    else if (sortBy === 'name') r.sort((a, b) => a.name.localeCompare(b.name));
    return r;
  }, [allRows, search, sortBy]);

  const maxCount = React.useMemo(() => {
    let m = 0;
    filtered.forEach(r => Object.values(r.counts).forEach(v => { if (v > m) m = v; }));
    return m;
  }, [filtered]);

  const accent = mode === 'F' ? '162, 58, 74' : '47, 74, 107';

  function exportCSV() {
    const head = ['name', ...years].join(',');
    const lines = filtered.map(r => [r.name, ...years.map(y => r.counts[y] || '')].join(','));
    const csv = [head, ...lines].join('\n');
    const blob = new Blob([csv], { type: 'text/csv' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `baby-names-${mode === 'F' ? 'girls' : 'boys'}-${yearStart}-${yearEnd}.csv`;
    a.click();
    URL.revokeObjectURL(url);
  }

  return (
    <div>
      <div className="toolbar">
        <label>
          Find a name
          <input type="text" placeholder="type a name…" value={search} onChange={e => setSearch(e.target.value)} />
        </label>
        <label>
          From
          <select value={yearStart} onChange={e => setYearStart(+e.target.value)}>
            {Array.from({ length: 145 }, (_, i) => 1880 + i).map(y => <option key={y} value={y}>{y}</option>)}
          </select>
        </label>
        <label>
          To
          <select value={yearEnd} onChange={e => setYearEnd(+e.target.value)}>
            {Array.from({ length: 145 }, (_, i) => 1880 + i).map(y => <option key={y} value={y}>{y}</option>)}
          </select>
        </label>
        <label>
          Sort by
          <select value={sortBy} onChange={e => setSortBy(e.target.value)}>
            <option value="recent">Most babies in latest year</option>
            <option value="peak">Biggest year</option>
            <option value="best-rank">Best popularity</option>
            <option value="total">Total in period</option>
            <option value="name">Name (A–Z)</option>
          </select>
        </label>
        <div style={{ flex: 1 }}></div>
        <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: '#8a7f70', letterSpacing: '0.15em', textTransform: 'uppercase' }}>
          {filtered.length} of {allRows.length} selected names
        </span>
        <button className="btn" onClick={exportCSV} disabled={!filtered.length}>Export CSV</button>
      </div>

      {valid.length === 0 ? (
        <div style={{ padding: '60px 20px', textAlign: 'center', color: 'var(--ink-muted)', fontFamily: 'var(--display)', fontStyle: 'italic', fontSize: 22, background: 'var(--paper)', border: '1px solid var(--rule-strong)' }}>
          Add a name above to see yearly counts.
        </div>
      ) : (
        <div className="table-wrap">
          <table className="pivot">
            <thead>
              <tr>
                <th className="name-col">Name</th>
                {years.map(y => <th key={y}>{y}</th>)}
              </tr>
            </thead>
            <tbody>
              {filtered.map(row => (
                <tr key={row.name}>
                  <td className="name-col">{row.name}</td>
                  {years.map(y => {
                    const c = row.counts[y];
                    const intensity = c ? Math.min(1, c / (maxCount * 0.5)) : 0;
                    return (
                      <td key={y} style={{ background: c ? `rgba(${accent}, ${intensity * 0.18})` : 'transparent' }}>
                        {c ? c.toLocaleString() : '·'}
                      </td>
                    );
                  })}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      <p className="note">The Social Security list does not include names given to fewer than 5 babies in a year. Dots mean the name was not listed for that year.</p>
    </div>
  );
}

Object.assign(window, { TrendChart, Sparkline, NameCard, RawTable, computeTrendLabel, fmt, fmtFull, ord, PALETTES });
