/**
 * SET 21 — inline SVG run charts (no chart libraries).
 * Stage tokens, cycles-per-feature, token-burn timeline.
 */
import React, { memo, useId, useMemo } from 'react';
import {
  STAGE_ORDER,
  buildTokenBurnSeries,
  stageBuckets,
  type ChartEvent,
  type StageBucket,
} from './runChartData';

export {
  buildTokenBurnSeries,
  isMarkerEvent,
  normalizeStage,
  parseTokAnnotation,
  stageBuckets,
  STAGE_ORDER,
} from './runChartData';
export type { BurnPoint, ChartEvent, StageBucket, StageKey } from './runChartData';

function cssVar(name: string, fallback: string): string {
  if (typeof document === 'undefined') return fallback;
  const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
  return v || fallback;
}

function useChartColors() {
  return useMemo(() => ({
    ink: cssVar('--ink', '#e8e2f7'),
    dim: cssVar('--dim', '#9990b3'),
    line: cssVar('--line', '#2b2440'),
    ok: cssVar('--ok', '#3fb96f'),
    frost: cssVar('--frost', '#5fd7ee'),
    bad: cssVar('--bad', '#e5604c'),
    warn: cssVar('--warn', '#d9a441'),
    accent: cssVar('--accent', '#b14dff'),
  }), []);
}

function fmtCompact(n: number): string {
  if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
  if (n >= 10_000) return `${Math.round(n / 1000)}k`;
  if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;
  return String(Math.round(n));
}

function fmtElapsed(ms: number): string {
  const s = Math.max(0, Math.floor(ms / 1000));
  const m = Math.floor(s / 60);
  const sec = s % 60;
  if (m >= 60) {
    const h = Math.floor(m / 60);
    return `${h}h${String(m % 60).padStart(2, '0')}m`;
  }
  return `${m}:${String(sec).padStart(2, '0')}`;
}

/* ── Stage tokens: paired in/out bars ─────────────────────────────────────── */

export const StageTokensChart = memo(function StageTokensChart({
  perStage,
}: {
  perStage?: Record<string, StageBucket> | null;
}) {
  const colors = useChartColors();
  const gid = useId();
  const buckets = useMemo(() => stageBuckets(perStage), [perStage]);
  const maxTok = Math.max(
    1,
    ...STAGE_ORDER.map(k => Math.max(buckets[k].tokensIn, buckets[k].tokensOut)),
  );

  const W = 420;
  const H = 148;
  const padL = 52;
  const padR = 12;
  const padT = 18;
  const padB = 28;
  const plotW = W - padL - padR;
  const plotH = H - padT - padB;
  const groupW = plotW / STAGE_ORDER.length;
  const barW = Math.min(18, groupW * 0.28);

  return (
    <svg
      className="runchart"
      viewBox={`0 0 ${W} ${H}`}
      width="100%"
      height={H}
      role="img"
      aria-label="Stage tokens in and out"
    >
      <title>Stage tokens (in / out)</title>
      {[0, 0.5, 1].map(f => {
        const y = padT + plotH * (1 - f);
        return (
          <g key={`g-${f}`}>
            <line x1={padL} x2={W - padR} y1={y} y2={y} stroke={colors.line} strokeWidth={1} />
            <text x={padL - 6} y={y + 3} textAnchor="end" className="runchart-label" fill={colors.dim} fontSize={9}>
              {fmtCompact(maxTok * f)}
            </text>
          </g>
        );
      })}
      {STAGE_ORDER.map((stage, i) => {
        const b = buckets[stage];
        const cx = padL + groupW * i + groupW / 2;
        const hIn = (b.tokensIn / maxTok) * plotH;
        const hOut = (b.tokensOut / maxTok) * plotH;
        const xIn = cx - barW - 2;
        const xOut = cx + 2;
        return (
          <g key={stage}>
            <rect
              x={xIn}
              y={padT + plotH - hIn}
              width={barW}
              height={Math.max(0, hIn)}
              fill={colors.frost}
              opacity={0.85}
            >
              <title>{`${stage} in: ${b.tokensIn.toLocaleString()}`}</title>
            </rect>
            <rect
              x={xOut}
              y={padT + plotH - hOut}
              width={barW}
              height={Math.max(0, hOut)}
              fill={colors.ok}
              opacity={0.9}
            >
              <title>{`${stage} out: ${b.tokensOut.toLocaleString()}`}</title>
            </rect>
            <text x={cx} y={H - 10} textAnchor="middle" className="runchart-label" fill={colors.dim} fontSize={10}>
              {stage}
            </text>
          </g>
        );
      })}
      <g transform={`translate(${padL}, 8)`}>
        <rect x={0} y={0} width={8} height={8} fill={colors.frost} rx={1} />
        <text x={12} y={8} className="runchart-label" fill={colors.dim} fontSize={9}>in</text>
        <rect x={36} y={0} width={8} height={8} fill={colors.ok} rx={1} />
        <text x={48} y={8} className="runchart-label" fill={colors.dim} fontSize={9}>out</text>
      </g>
      {/* stable gradient id unused but keeps SVG identity stable across ticks */}
      <defs><clipPath id={gid}><rect x={0} y={0} width={W} height={H} /></clipPath></defs>
    </svg>
  );
});

/* ── Cycles per feature ───────────────────────────────────────────────────── */

export const CyclesPerFeatureChart = memo(function CyclesPerFeatureChart({
  passesPerFeature,
}: {
  passesPerFeature?: Record<string, number> | null;
}) {
  const colors = useChartColors();
  const entries = useMemo(
    () => Object.entries(passesPerFeature ?? {}).sort(([a], [b]) => a.localeCompare(b)),
    [passesPerFeature],
  );
  if (!entries.length) return null;

  const maxC = Math.max(1, ...entries.map(([, n]) => Number(n) || 0));
  const rowH = 18;
  const padL = 48;
  const padR = 36;
  const padT = 8;
  const padB = 8;
  const W = 280;
  const H = padT + padB + entries.length * rowH;
  const plotW = W - padL - padR;

  return (
    <svg
      className="runchart"
      viewBox={`0 0 ${W} ${H}`}
      width="100%"
      height={H}
      role="img"
      aria-label="Cycles per feature"
    >
      <title>Cycles per feature</title>
      {entries.map(([id, n], i) => {
        const y = padT + i * rowH;
        const w = ((Number(n) || 0) / maxC) * plotW;
        return (
          <g key={id}>
            <text x={padL - 6} y={y + 12} textAnchor="end" className="runchart-label" fill={colors.dim} fontSize={10}>
              {id}
            </text>
            <rect x={padL} y={y + 3} width={Math.max(0, w)} height={10} fill={colors.accent} opacity={0.8} rx={2}>
              <title>{`${id}: ${n} cycles`}</title>
            </rect>
            <text x={padL + w + 4} y={y + 12} className="runchart-label" fill={colors.ink} fontSize={10}>
              {n}
            </text>
          </g>
        );
      })}
    </svg>
  );
});

/* ── Token-burn timeline ──────────────────────────────────────────────────── */

export const TokenBurnTimeline = memo(function TokenBurnTimeline({
  events,
  startTs,
}: {
  events: ChartEvent[];
  startTs: string;
}) {
  const colors = useChartColors();
  const series = useMemo(() => buildTokenBurnSeries(events, startTs), [events, startTs]);
  const linePts = useMemo(() => series.filter(p => !p.marker), [series]);
  const markers = useMemo(() => series.filter(p => p.marker), [series]);

  if (linePts.length < 2 && markers.length === 0) {
    return (
      <div className="dim small runchart-empty">No per-call token events yet</div>
    );
  }

  const W = 520;
  const H = 160;
  const padL = 48;
  const padR = 14;
  const padT = 14;
  const padB = 28;
  const plotW = W - padL - padR;
  const plotH = H - padT - padB;

  const maxT = Math.max(1, ...series.map(p => p.tMs));
  const maxY = Math.max(1, ...series.map(p => p.cumulative));

  const xOf = (t: number) => padL + (t / maxT) * plotW;
  const yOf = (v: number) => padT + plotH * (1 - v / maxY);

  const poly = linePts
    .map((p, i) => `${i === 0 ? 'M' : 'L'}${xOf(p.tMs).toFixed(1)},${yOf(p.cumulative).toFixed(1)}`)
    .join(' ');

  return (
    <svg
      className="runchart"
      viewBox={`0 0 ${W} ${H}`}
      width="100%"
      height={H}
      role="img"
      aria-label="Cumulative tokens over elapsed time"
    >
      <title>Token burn timeline</title>
      {[0, 0.5, 1].map(f => {
        const y = padT + plotH * (1 - f);
        return (
          <g key={`by-${f}`}>
            <line x1={padL} x2={W - padR} y1={y} y2={y} stroke={colors.line} strokeWidth={1} />
            <text x={padL - 6} y={y + 3} textAnchor="end" className="runchart-label" fill={colors.dim} fontSize={9}>
              {fmtCompact(maxY * f)}
            </text>
          </g>
        );
      })}
      {[0, 0.5, 1].map(f => {
        const x = padL + plotW * f;
        return (
          <text key={`bx-${f}`} x={x} y={H - 8} textAnchor="middle" className="runchart-label" fill={colors.dim} fontSize={9}>
            {fmtElapsed(maxT * f)}
          </text>
        );
      })}
      {poly && (
        <path d={poly} fill="none" stroke={colors.frost} strokeWidth={2} strokeLinejoin="round" strokeLinecap="round" />
      )}
      {markers.map((m, i) => (
        <g key={`m-${m.tMs}-${i}`}>
          <line
            x1={xOf(m.tMs)}
            x2={xOf(m.tMs)}
            y1={padT}
            y2={padT + plotH}
            stroke={colors.bad}
            strokeWidth={1.5}
            strokeDasharray="3 3"
            opacity={0.85}
          />
          <circle cx={xOf(m.tMs)} cy={yOf(m.cumulative)} r={4} fill={colors.bad}>
            <title>{m.message ?? 'marker'}</title>
          </circle>
        </g>
      ))}
    </svg>
  );
});

/** Combined metrics charts block for Tier1View. */
export const RunMetricsCharts = memo(function RunMetricsCharts({
  perStage,
  passesPerFeature,
  events,
  startTs,
}: {
  perStage?: Record<string, StageBucket> | null;
  passesPerFeature?: Record<string, number> | null;
  events: ChartEvent[];
  startTs: string;
}) {
  const hasStages = perStage && Object.keys(perStage).length > 0;
  const hasPpf = passesPerFeature && Object.keys(passesPerFeature).length > 0;
  if (!hasStages && !hasPpf && events.length === 0) return null;

  return (
    <div className="runcharts">
      {hasStages && (
        <div className="runchart-block">
          <div className="runchart-head">Stage tokens</div>
          <StageTokensChart perStage={perStage} />
        </div>
      )}
      {hasPpf && (
        <div className="runchart-block">
          <div className="runchart-head">Cycles / feature</div>
          <CyclesPerFeatureChart passesPerFeature={passesPerFeature} />
        </div>
      )}
      <div className="runchart-block runchart-block-wide">
        <div className="runchart-head">Token burn</div>
        <TokenBurnTimeline events={events} startTs={startTs} />
      </div>
    </div>
  );
});
