import {
  CartesianGrid,
  Line,
  LineChart,
  ReferenceLine,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from 'recharts';
import type { TooltipProps } from 'recharts';
import { formatNumber } from './format';

export interface MetricPoint {
  /** Whatever the x axis is counting: checkpoint, step, arm name. */
  x: string | number;
  y: number;
}

export interface MetricChartProps {
  data: MetricPoint[];
  /** The rule the headline number is being compared against. */
  baseline?: { value: number; label: string };
  height: number;
  /** Off under `prefers-reduced-motion`; recharts animates on mount by default. */
  animate: boolean;
  digits?: number;
}

/*
 * Every colour is an `hsl(var(--…))` string read from the token layer at paint
 * time, so the chart follows the theme toggle without a re-render and no hex
 * ever lands in this file. The series takes `--tab-underline`, which is the
 * one token that is the accent fill in dark and the accent INK in light — a
 * 2px line on the page ground is a state indicator, and the raw accent is
 * 1.47:1 against white.
 */
const SERIES = 'hsl(var(--tab-underline))';
const GRID = 'hsl(var(--border))';
const BASELINE = 'hsl(var(--border-strong))';
const TICK = 'hsl(var(--muted))';

/**
 * The chart, in its own module so `React.lazy` can hold recharts out of the
 * entry chunk. Nothing else in the shell may import this file directly — an
 * ordinary import here defeats the whole arrangement and the entry chunk grows
 * by ~100 kB without anyone noticing.
 */
export default function MetricChart({
  data,
  baseline,
  height,
  animate,
  digits = 3,
}: MetricChartProps) {
  return (
    <div style={{ height }} className="w-full font-mono">
      <ResponsiveContainer width="100%" height="100%">
        <LineChart data={data} margin={{ top: 8, right: 12, bottom: 4, left: 4 }}>
          <CartesianGrid stroke={GRID} strokeDasharray="2 4" vertical={false} />
          <XAxis
            dataKey="x"
            tick={{ fill: TICK, fontSize: 11, fontFamily: 'inherit' }}
            tickLine={false}
            axisLine={{ stroke: GRID }}
            minTickGap={12}
          />
          <YAxis
            tick={{ fill: TICK, fontSize: 11, fontFamily: 'inherit' }}
            tickLine={false}
            axisLine={false}
            width={40}
            tickFormatter={(value: number) => formatNumber(value, digits > 2 ? 2 : digits)}
          />
          {baseline ? (
            <ReferenceLine
              y={baseline.value}
              stroke={BASELINE}
              strokeDasharray="5 4"
              // Right-anchored: a baseline near zero sits on the x axis, and
              // a left-anchored label lands on the first tick's text.
              label={{
                value: baseline.label,
                position: 'insideTopRight',
                fill: TICK,
                fontSize: 11,
                fontFamily: 'inherit',
              }}
            />
          ) : null}
          <Tooltip
            cursor={{ stroke: BASELINE }}
            content={(props: TooltipProps<number, string>) => (
              <ChartTooltip {...props} digits={digits} />
            )}
          />
          <Line
            // `linear`, not `monotone`: a spline invents curvature between two
            // measured points, and on a categorical axis (one point per
            // recorded arm) that curve is a claim nobody measured.
            type="linear"
            dataKey="y"
            stroke={SERIES}
            strokeWidth={2}
            dot={{ r: 3, fill: SERIES, strokeWidth: 0 }}
            activeDot={{ r: 4.5, fill: SERIES, strokeWidth: 0 }}
            isAnimationActive={animate}
            animationDuration={400}
          />
        </LineChart>
      </ResponsiveContainer>
    </div>
  );
}

function ChartTooltip({
  active,
  payload,
  label,
  digits,
}: TooltipProps<number, string> & { digits: number }) {
  if (!active || !payload || payload.length === 0) return null;
  const value = payload[0]?.value;
  return (
    <div className="rounded-md border border-border bg-surface px-2.5 py-1.5 font-mono text-caption shadow-overlay">
      <p className="text-muted">{String(label)}</p>
      <p className="font-semibold text-fg">
        {typeof value === 'number' ? formatNumber(value, digits) : '—'}
      </p>
    </div>
  );
}
