"use client";

import { useId } from "react";

/**
 * Minimal accessible SVG line/area chart — no charting library is
 * installed, and the historical data here is simple enough (one series,
 * evenly spaced by day) that a hand-rolled polyline is a better tradeoff
 * than adding a dependency for it. The `<svg>` carries an aria-label with
 * the chart's title and the underlying data is also rendered as a
 * visually-hidden table, so a screen reader (or a browser with images/SVG
 * disabled) still gets the real numbers, not just a shape. Each point has a
 * native <title> tooltip (date + value) — no JS hover-tracking library
 * needed for a "show me the number" tooltip.
 */
export function MetricChart({
  title,
  points,
  formatValue,
  color = "var(--brand-cyan)",
  emptyLabel,
  height = 120,
  area = false,
  chrome = true,
}: {
  title: string;
  points: { date: Date; value: number | null }[];
  formatValue?: (value: number) => string;
  color?: string;
  emptyLabel: string;
  /** Taller chart for a section where it's the visual centerpiece (e.g. the
   * product detail Performance section) vs. the default compact size used
   * in dashboard grids. */
  height?: number;
  /** Fills the area under the line with a fading gradient — used for the
   * single "hero" chart in a section, not for small side-by-side grids. */
  area?: boolean;
  /** false = bare sparkline: no gridlines, no min/max labels, no empty-state
   * box (just nothing rendered below the threshold). Used inline next to a
   * KPI number where a full chart frame would be visual noise. */
  chrome?: boolean;
}) {
  const gradientId = useId();
  const valid = points.filter((p): p is { date: Date; value: number } => p.value !== null);

  if (valid.length < 2) {
    if (!chrome) return null;
    return (
      <div
        className="flex items-center justify-center rounded-lg border border-dashed border-border text-xs text-muted-foreground"
        style={{ height }}
      >
        {emptyLabel}
      </div>
    );
  }

  const width = 640;
  const paddingX = 8;
  const paddingY = 12;
  const values = valid.map((p) => p.value);
  const min = Math.min(...values);
  const max = Math.max(...values);
  const range = max - min || 1;
  const fmt = (v: number) => (formatValue ? formatValue(v) : new Intl.NumberFormat().format(v));

  const coords = valid.map((p, i) => {
    const x = paddingX + (i / (valid.length - 1)) * (width - paddingX * 2);
    const y = height - paddingY - ((p.value - min) / range) * (height - paddingY * 2);
    return { x, y, point: p };
  });
  const polylinePoints = coords.map((c) => `${c.x},${c.y}`).join(" ");
  const last = coords[coords.length - 1];
  const areaPath = `M${paddingX},${height - paddingY} L${polylinePoints
    .split(" ")
    .join(" L")} L${last.x},${height - paddingY} Z`;

  return (
    <div className="flex flex-col gap-2">
      <div className="relative">
        <svg
          viewBox={`0 0 ${width} ${height}`}
          className="w-full"
          style={{ height }}
          role="img"
          aria-label={title}
          preserveAspectRatio="none"
        >
          {area && (
            <defs>
              <linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor={color} stopOpacity="0.28" />
                <stop offset="100%" stopColor={color} stopOpacity="0" />
              </linearGradient>
            </defs>
          )}
          {/* Light horizontal gridlines at 0/50/100% for a visible y-scale
              without printing numeric axis labels inside the plot area. */}
          {chrome &&
            [0, 0.5, 1].map((f) => (
              <line
                key={f}
                x1={paddingX}
                x2={width - paddingX}
                y1={paddingY + f * (height - paddingY * 2)}
                y2={paddingY + f * (height - paddingY * 2)}
                stroke="var(--border)"
                strokeWidth={1}
              />
            ))}
          {area && <path d={areaPath} fill={`url(#${gradientId})`} stroke="none" />}
          <polyline fill="none" stroke={color} strokeWidth={2} points={polylinePoints} />
          {coords.map((c, i) => (
            <circle key={i} cx={c.x} cy={c.y} r={i === coords.length - 1 ? 3 : 2.5} fill={color}>
              <title>
                {c.point.date.toISOString().slice(0, 10)}: {fmt(c.point.value)}
              </title>
            </circle>
          ))}
        </svg>
        {chrome && (
          <>
            <div className="pointer-events-none absolute top-0 right-0 text-[11px] text-muted-foreground">{fmt(max)}</div>
            <div className="pointer-events-none absolute bottom-0 right-0 text-[11px] text-muted-foreground">{fmt(min)}</div>
          </>
        )}
      </div>
      {/* sr-only on the <table> itself doesn't reliably clip to 1x1px —
          CSS table layout can expand a table's rendered box past an
          explicit height:1px once it has real rows, regardless of
          overflow:hidden/clip. That silently grew the page's scrollable
          area by the table's full unclipped height (worst with 30-90 rows
          here) without being visible — invisible on the old all-dark
          theme, but exposed as literal dead space once the workspace
          became a light surface. Scoping sr-only to a wrapping <div>
          avoids the table-specific sizing quirk entirely. */}
      <div className="sr-only">
        <table>
          <caption>{title}</caption>
          <thead>
            <tr>
              <th scope="col">Date</th>
              <th scope="col">Value</th>
            </tr>
          </thead>
          <tbody>
            {valid.map((p, i) => (
              <tr key={i}>
                <td>{p.date.toISOString().slice(0, 10)}</td>
                <td>{formatValue ? formatValue(p.value) : p.value}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
