import { useId, type CSSProperties } from 'react';

export interface RadarSeries {
  /** Stable id — React key + accessible label. */
  id: string;
  /** One value per axis; non-finite values are treated as 0. */
  values: number[];
  /** Optional override colour (defaults walk the token palette). */
  color?: string;
  /** Optional display label (falls back to `id`). */
  label?: string;
}

export interface RadarChartProps {
  /** Axis (category) labels — defines the number of spokes. */
  axes: string[];
  /** One or more series plotted as polygons. */
  series: RadarSeries[];
  /** Total width/height in px. Default 260. */
  size?: number;
  /** Fixed maximum for the radial scale. Defaults to the largest value. */
  max?: number;
  /** Concentric grid rings. Default 4. */
  levels?: number;
  /** Accessible label. */
  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)',
];

const safe = (v: number): number => (Number.isFinite(v) ? v : 0);

/** Cartesian point for axis `i` of `n` at radius `radius`. */
function spoke(cx: number, cy: number, radius: number, i: number, n: number): [number, number] {
  const angle = -Math.PI / 2 + (i / n) * 2 * Math.PI;
  return [cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)];
}

const toPath = (pts: ReadonlyArray<[number, number]>): string =>
  pts.map(([x, y], i) => `${i === 0 ? 'M' : 'L'} ${x.toFixed(2)} ${y.toFixed(2)}`).join(' ') + ' Z';

/**
 * `<RadarChart>` — multi-axis polygon (spider) chart. Pure SVG, token-themed,
 * NaN-safe. Wave 9.A.5.
 */
export function RadarChart({
  axes,
  series,
  size = 260,
  max,
  levels = 4,
  ariaLabel,
  className,
  style,
}: RadarChartProps) {
  const titleId = useId();
  const n = axes.length;
  const cx = size / 2;
  const cy = size / 2;
  const r = (size / 2) * 0.74; // leave room for labels

  const derivedMax = max ?? Math.max(1, ...series.flatMap(s => s.values.map(v => safe(v))));
  const scale = (v: number) => (derivedMax === 0 ? 0 : (safe(v) / derivedMax) * r);

  return (
    <svg
      role="img"
      aria-labelledby={titleId}
      viewBox={`0 0 ${size} ${size}`}
      width={size}
      height={size}
      data-testid="bl-radar"
      className={className}
      style={style}
    >
      <title id={titleId}>{ariaLabel ?? 'Radar chart'}</title>

      {/* Concentric grid rings */}
      {n >= 3 &&
        Array.from({ length: levels }, (_, l) => {
          const ringR = (r * (l + 1)) / levels;
          const pts = Array.from({ length: n }, (_, i) => spoke(cx, cy, ringR, i, n));
          return (
            <path
              key={`ring-${l}`}
              d={toPath(pts)}
              fill="none"
              stroke="var(--bl-border-subtle, rgba(0,0,0,0.08))"
              data-testid="bl-radar-ring"
            />
          );
        })}

      {/* Spokes + axis labels */}
      {axes.map((label, i) => {
        const [ex, ey] = spoke(cx, cy, r, i, n);
        const [lx, ly] = spoke(cx, cy, r + 14, i, n);
        return (
          <g key={`axis-${i}`}>
            <line
              x1={cx}
              y1={cy}
              x2={ex}
              y2={ey}
              stroke="var(--bl-border-subtle, rgba(0,0,0,0.08))"
            />
            <text
              x={lx}
              y={ly}
              fontSize={11}
              textAnchor={lx > cx + 1 ? 'start' : lx < cx - 1 ? 'end' : 'middle'}
              dominantBaseline="middle"
              fill="var(--bl-text-secondary, #444)"
              fontFamily="ui-sans-serif, system-ui, sans-serif"
            >
              {label}
            </text>
          </g>
        );
      })}

      {/* Series polygons */}
      {series.map((s, si) => {
        const colour = s.color ?? TOKEN_PALETTE[si % TOKEN_PALETTE.length]!;
        const pts = axes.map((_, i) => spoke(cx, cy, scale(s.values[i] ?? 0), i, n));
        return (
          <path
            key={s.id}
            d={toPath(pts)}
            fill={colour}
            fillOpacity={0.18}
            stroke={colour}
            strokeWidth={2}
            strokeLinejoin="round"
            data-testid="bl-radar-series"
            data-series-id={s.id}
          />
        );
      })}
    </svg>
  );
}
