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;
}

/**
 * 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.
 *
 * Every colour is read from the token layer at paint time rather than passed in
 * as a literal, so the chart follows the theme toggle without a re-render.
 */
export default function MetricChart({
  data,
  baseline,
  height,
  animate,
  digits = 3,
}: MetricChartProps) {
  return (
    <div style={{ height }} className="w-full">
      <ResponsiveContainer width="100%" height="100%">
        <LineChart data={data} margin={{ top: 8, right: 12, bottom: 4, left: 4 }}>
          <CartesianGrid stroke="hsl(var(--border))" strokeDasharray="2 4" vertical={false} />
          <XAxis
            dataKey="x"
            tick={{ fill: 'hsl(var(--muted))', fontSize: 11 }}
            tickLine={false}
            axisLine={{ stroke: 'hsl(var(--border))' }}
            minTickGap={12}
          />
          <YAxis
            tick={{ fill: 'hsl(var(--muted))', fontSize: 11 }}
            tickLine={false}
            axisLine={false}
            width={40}
            tickFormatter={(value: number) => formatNumber(value, digits > 2 ? 2 : digits)}
          />
          {baseline ? (
            <ReferenceLine
              y={baseline.value}
              stroke="hsl(var(--muted))"
              strokeDasharray="5 4"
              label={{
                value: baseline.label,
                position: 'insideTopLeft',
                fill: 'hsl(var(--muted))',
                fontSize: 11,
              }}
            />
          ) : null}
          <Tooltip
            cursor={{ stroke: 'hsl(var(--border))' }}
            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="hsl(var(--accent))"
            strokeWidth={2}
            dot={{ r: 2.5, fill: 'hsl(var(--accent))', strokeWidth: 0 }}
            activeDot={{ r: 4 }}
            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="card px-2.5 py-1.5 text-xs shadow-md">
      <p className="nums text-muted">{String(label)}</p>
      <p className="nums font-mono font-semibold">
        {typeof value === 'number' ? formatNumber(value, digits) : '—'}
      </p>
    </div>
  );
}
