import { useId, type CSSProperties } from 'react';
import { compactNumber, extent, filterFinite, linearScale, smoothPath } from './utils.js';

export interface LineSeries {
  /** Stable id — React key + accessible series label. */
  id: string;
  /** Y-values (X is the array index, evenly spaced). */
  values: number[];
  /** Optional override colour. Defaults walk the token palette. */
  color?: string;
}

export interface LineChartProps {
  /** One or more series, plotted in z-order. */
  series: LineSeries[];
  /** Chart width in px. Default 480. */
  width?: number;
  /** Chart height in px. Default 240. */
  height?: number;
  /** Smooth (catmull-rom) vs straight polyline. Default smooth. */
  smooth?: boolean;
  /** Show subtle Y grid lines (3 ticks). Default true. */
  grid?: boolean;
  /** Accessible label for the SVG. */
  ariaLabel?: string;
  className?: string;
  style?: CSSProperties;
}

const TOKEN_PALETTE = [
  'var(--bl-accent, #6366f1)',
  'var(--bl-success, #10b981)',
  'var(--bl-warning, #f59e0b)',
  'var(--bl-info, #0ea5e9)',
  'var(--bl-danger, #ef4444)',
];

/**
 * `<LineChart>` — multi-series SVG line chart with optional smoothing.
 *
 * Pure-React, dependency-free. The series share a common Y extent;
 * legend / tooltip overlays are intentionally out-of-scope — wrap a
 * `<LineChart>` in a host that handles those if needed.
 *
 * Wave 9.A.1.
 */
export function LineChart({
  series,
  width = 480,
  height = 240,
  smooth = true,
  grid = true,
  ariaLabel,
  className,
  style,
}: LineChartProps) {
  const titleId = useId();
  const padL = 36;
  const padR = 12;
  const padT = 12;
  const padB = 24;
  const innerW = Math.max(0, width - padL - padR);
  const innerH = Math.max(0, height - padT - padB);

  const allValues = series.flatMap((s) => s.values);
  const [yMin, yMax] = extent(allValues);
  // Find the longest series for the X domain.
  const maxLen = Math.max(1, ...series.map((s) => s.values.length));

  const yScale = linearScale(yMin, yMax, innerH, 0);
  const xScale = (i: number) =>
    maxLen > 1 ? (i / (maxLen - 1)) * innerW : innerW / 2;

  const yTicks = grid ? niceTicks(yMin, yMax, 3) : [];

  return (
    <svg
      role="img"
      aria-labelledby={titleId}
      viewBox={`0 0 ${width} ${height}`}
      width={width}
      height={height}
      data-testid="bl-line-chart"
      className={className}
      style={style}
    >
      <title id={titleId}>{ariaLabel ?? 'Line chart'}</title>
      {/* Grid */}
      <g transform={`translate(${padL} ${padT})`}>
        {yTicks.map((t, i) => (
          <g key={`t${i}`}>
            <line
              x1={0}
              x2={innerW}
              y1={yScale(t)}
              y2={yScale(t)}
              stroke="var(--bl-border-subtle, rgba(0,0,0,0.06))"
              strokeWidth={1}
            />
            <text
              x={-6}
              y={yScale(t)}
              textAnchor="end"
              dominantBaseline="middle"
              fontSize={10}
              fill="var(--bl-text-tertiary, #888)"
              fontFamily="ui-sans-serif, system-ui, sans-serif"
            >
              {compactNumber(t)}
            </text>
          </g>
        ))}
        {series.map((s, idx) => {
          const colour = s.color ?? TOKEN_PALETTE[idx % TOKEN_PALETTE.length]!;
          // Drop NaN / Infinity so the SVG path stays well-formed.
          const points: Array<[number, number]> = filterFinite(s.values).map(
            ([i, v]) => [xScale(i), yScale(v)],
          );
          if (points.length === 0) return null;
          const d = smooth
            ? smoothPath(points)
            : `M ${points.map(([x, y]) => `${x} ${y}`).join(' L ')}`;
          return (
            <g key={s.id} data-testid="bl-line-chart-series" data-series-id={s.id}>
              <path
                d={d}
                fill="none"
                stroke={colour}
                strokeWidth={2}
                strokeLinejoin="round"
                strokeLinecap="round"
              />
              {points.map(([x, y], i) => (
                <circle
                  key={`p-${i}`}
                  cx={x}
                  cy={y}
                  r={2.4}
                  fill={colour}
                  opacity={0.85}
                />
              ))}
            </g>
          );
        })}
      </g>
    </svg>
  );
}

/** Pick ~`n` nice ticks across `[lo, hi]`. */
function niceTicks(lo: number, hi: number, n: number): number[] {
  if (lo === hi) return [lo];
  const step = (hi - lo) / Math.max(1, n - 1);
  return Array.from({ length: n }, (_, i) => lo + step * i);
}

