// CRI-score-over-time chart with least-squares trend line + 95% CI band.
// Renders below the leaderboard. Reads window.MODELS.
const { useState: useTcState, useMemo: useTcMemo } = React;

const TC = {
  W: 1000, H: 460,
  ml: 58, mr: 24, mt: 28, mb: 52,
};

function parseMonth(s) {
  // "YYYY-MM" -> absolute month index
  const [y, m] = s.split("-").map(Number);
  return y * 12 + (m - 1);
}

const MONTH_ABBR = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
function fmtMonth(idx) {
  const y = Math.floor(idx / 12);
  const m = idx % 12;
  return `${MONTH_ABBR[m]} '${String(y).slice(2)}`;
}

function TrendChart({ orgColors, teal }) {
  const [hover, setHover] = useTcState(null);
  const [dsFilter, setDsFilter] = useTcState("Overall");

  const model = useTcMemo(() => {
    const getScore = (m) => dsFilter === "Overall" ? m.overall : m.scores[dsFilter];
    const pts = window.MODELS.map((m) => ({
      x: parseMonth(m.released),
      y: getScore(m),
      name: m.name,
      org: m.org,
      released: m.released,
    }));
    const xs = pts.map((p) => p.x);
    const minX = Math.min(...xs), maxX = Math.max(...xs);
    const ys = pts.map((p) => p.y);

    // least-squares linear regression
    const n = pts.length;
    const xbar = xs.reduce((a, b) => a + b, 0) / n;
    const ybar = ys.reduce((a, b) => a + b, 0) / n;
    let Sxx = 0, Sxy = 0;
    for (const p of pts) { Sxx += (p.x - xbar) ** 2; Sxy += (p.x - xbar) * (p.y - ybar); }
    const slope = Sxy / Sxx;
    const intercept = ybar - slope * xbar;
    const yhat = (x) => intercept + slope * x;

    // residual standard error
    let sse = 0;
    for (const p of pts) sse += (p.y - yhat(p.x)) ** 2;
    const s = Math.sqrt(sse / (n - 2));
    const t = 1.96; // ~95% for large-ish n

    // CI of the mean response at x
    const se = (x) => s * Math.sqrt(1 / n + ((x - xbar) ** 2) / Sxx);

    return { pts, minX, maxX, slope, intercept, yhat, se, t, n };
  }, [dsFilter]);

  // y domain — round to nice bounds
  const yMin = 40, yMax = 90;
  const xPad = 1; // months of horizontal breathing room
  const x0 = model.minX - xPad, x1 = model.maxX + xPad;

  const px = (x) => TC.ml + ((x - x0) / (x1 - x0)) * (TC.W - TC.ml - TC.mr);
  const py = (y) => TC.mt + (1 - (y - yMin) / (yMax - yMin)) * (TC.H - TC.mt - TC.mb);

  // build trend + band sample paths
  const samples = [];
  const steps = 60;
  for (let i = 0; i <= steps; i++) {
    const x = x0 + (i / steps) * (x1 - x0);
    const yc = model.yhat(x);
    const half = model.t * model.se(x);
    samples.push({ x, yc, hi: yc + half, lo: yc - half });
  }
  const linePath = samples.map((s, i) => `${i ? "L" : "M"}${px(s.x).toFixed(1)},${py(s.yc).toFixed(1)}`).join(" ");
  const bandPath =
    samples.map((s, i) => `${i ? "L" : "M"}${px(s.x).toFixed(1)},${py(s.hi).toFixed(1)}`).join(" ") +
    " " +
    samples.slice().reverse().map((s) => `L${px(s.x).toFixed(1)},${py(s.lo).toFixed(1)}`).join(" ") +
    " Z";

  // axis ticks
  const yTicks = [40, 50, 60, 70, 80, 90];
  const xTicks = [];
  for (let m = Math.ceil(x0 / 3) * 3; m <= x1; m += 3) xTicks.push(m);

  const orgsPresent = Array.from(new Set(model.pts.map((p) => p.org)))
    .sort((a, b) => window.ORGS.indexOf(a) - window.ORGS.indexOf(b));

  const colorFor = (org) => (orgColors && orgColors[org]) || teal;

  return (
    <section className="trend-wrap" id="trend">
      <div className="trend-head">
        <div>
          <div className="eyebrow">Trend</div>
        </div>
        <div className="filter-group trend-filter">
          <div className="filter-label">Dataset</div>
          <div className="filter-opts">
            {["Overall", ...window.DATASETS].map((opt) => (
              <button
                key={opt}
                className={"filter-chip" + (dsFilter === opt ? " is-active" : "")}
                onClick={() => setDsFilter(opt)}>
                {opt}
              </button>
            ))}
          </div>
        </div>
      </div>

      <div className="trend-plot">
        <svg viewBox={`0 0 ${TC.W} ${TC.H}`} className="trend-svg" preserveAspectRatio="xMidYMid meet">
          {/* gridlines + y labels */}
          {yTicks.map((v) => (
            <g key={`y${v}`}>
              <line x1={TC.ml} x2={TC.W - TC.mr} y1={py(v)} y2={py(v)} className="tc-grid" />
              <text x={TC.ml - 12} y={py(v)} className="tc-ylabel" dominantBaseline="middle" textAnchor="end">{v}</text>
            </g>
          ))}
          {/* x labels */}
          {xTicks.map((m) => (
            <g key={`x${m}`}>
              <line x1={px(m)} x2={px(m)} y1={TC.H - TC.mb} y2={TC.H - TC.mb + 6} className="tc-tick" />
              <text x={px(m)} y={TC.H - TC.mb + 22} className="tc-xlabel" textAnchor="middle">{fmtMonth(m)}</text>
            </g>
          ))}
          {/* axes baseline */}
          <line x1={TC.ml} x2={TC.W - TC.mr} y1={TC.H - TC.mb} y2={TC.H - TC.mb} className="tc-axis" />

          {/* CI band + trend line */}
          <path d={bandPath} fill="var(--teal)" fillOpacity="0.10" stroke="none" />
          <path d={linePath} fill="none" stroke="var(--teal)" strokeWidth="2" />

          {/* points */}
          {model.pts.map((p, i) => (
            <circle
              key={i}
              cx={px(p.x)}
              cy={py(p.y)}
              r={hover === i ? 6 : 4}
              fill={colorFor(p.org)}
              className="tc-pt"
              onMouseEnter={() => setHover(i)}
              onMouseLeave={() => setHover(null)}
            />
          ))}

          <text
            className="tc-axis-title"
            x={20}
            y={TC.mt + (TC.H - TC.mt - TC.mb) / 2}
            textAnchor="middle"
            dominantBaseline="middle">
            {dsFilter === "Overall" ? "CRI" : dsFilter}
          </text>
        </svg>

        {hover != null && (() => {
          const p = model.pts[hover];
          const leftPct = (px(p.x) / TC.W) * 100;
          const topPct = (py(p.y) / TC.H) * 100;
          return (
            <div
              className="tc-tooltip"
              style={{ left: `${leftPct}%`, top: `${topPct}%` }}>
              <div className="tc-tt-name">{p.name}</div>
              <div className="tc-tt-meta mono-small">{p.org} · {fmtMonth(p.x)}</div>
              <div className="tc-tt-score" style={{ color: colorFor(p.org) }}>{p.y.toFixed(1)}</div>
            </div>
          );
        })()}
      </div>

      <div className="trend-legend">
        {orgsPresent.map((org) => (
          <span key={org} className="tc-leg">
            <span className="tc-leg-dot" style={{ background: colorFor(org) }} />
            {org}
          </span>
        ))}
      </div>
    </section>
  );
}

window.TrendChart = TrendChart;
