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

export interface SparklineProps {
  /** Series values. Length 2+. */
  data: number[];
  /** Width in px. Default 120. */
  width?: number;
  /** Height in px. Default 36. */
  height?: number;
  /** Stroke color. Default `var(--bl-accent)`. */
  stroke?: string;
  /** Stroke width. Default 1.75. */
  strokeWidth?: number;
  /** Fill the area under the line. Default true. */
  fill?: boolean;
  /** Highlight the final point. Default true. */
  showLastPoint?: boolean;
  /** Aria label. */
  ariaLabel?: string;
  className?: string;
  style?: CSSProperties;
}

/**
 * `<Sparkline>` — tiny inline trend line. Pure SVG, no runtime layout
 * cost. Auto-scales the Y axis to the data range; clamps tiny ranges
 * so flat lines still render visibly.
 */
export function Sparkline({
  data,
  width = 120,
  height = 36,
  stroke = 'var(--bl-accent, #6366f1)',
  strokeWidth = 1.75,
  fill = true,
  showLastPoint = true,
  ariaLabel,
  className,
  style,
}: SparklineProps) {
  const { path, areaPath, lastX, lastY } = useMemo(() => {
    if (data.length < 2) {
      return { path: '', areaPath: '', lastX: 0, lastY: 0 };
    }
    const min = Math.min(...data);
    const max = Math.max(...data);
    const range = max - min || 1;
    const pad = strokeWidth + 1;
    const innerW = width - pad * 2;
    const innerH = height - pad * 2;
    const stepX = innerW / (data.length - 1);
    const pts = data.map((v, i) => {
      const x = pad + i * stepX;
      const y = pad + innerH - ((v - min) / range) * innerH;
      return [x, y] as const;
    });
    const path = pts.map(([x, y], i) => (i === 0 ? `M${x},${y}` : `L${x},${y}`)).join(' ');
    const areaPath =
      pts.length > 1
        ? `${path} L${pts[pts.length - 1]![0]},${height} L${pts[0]![0]},${height} Z`
        : '';
    const [lx, ly] = pts[pts.length - 1]!;
    return { path, areaPath, lastX: lx, lastY: ly };
  }, [data, width, height, strokeWidth]);

  // useId() is SSR-stable; using Math.random() here would mismatch on hydration.
  const reactId = useId();
  const gradId = `bl-spark-${reactId.replace(/[^a-zA-Z0-9_-]/g, '')}`;

  return (
    <svg
      data-testid="bl-sparkline"
      role="img"
      aria-label={ariaLabel ?? 'Sparkline'}
      width={width}
      height={height}
      viewBox={`0 0 ${width} ${height}`}
      className={className}
      style={{ overflow: 'visible', ...style }}
    >
      {fill && (
        <>
          <defs>
            <linearGradient id={gradId} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={stroke} stopOpacity={0.32} />
              <stop offset="100%" stopColor={stroke} stopOpacity={0} />
            </linearGradient>
          </defs>
          <path d={areaPath} fill={`url(#${gradId})`} stroke="none" />
        </>
      )}
      <path
        d={path}
        fill="none"
        stroke={stroke}
        strokeWidth={strokeWidth}
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      {showLastPoint && data.length >= 2 && (
        <circle
          cx={lastX}
          cy={lastY}
          r={strokeWidth + 1.25}
          fill={stroke}
          stroke="var(--bl-surface-card, #fff)"
          strokeWidth={1.5}
        />
      )}
    </svg>
  );
}
