import { Box } from "@mantine/core";

import {
  overviewAccentGradients,
  type OverviewAccent,
} from "@/components/overview/overview.styles";

/**
 * Tiny inline-SVG mini graphs shared by every KPI / stat card across the app.
 * No charting dependency — crisp and cheap to render in long card grids.
 *
 * - `MiniSparkline` (variant "area" | "line") draws a smooth decorative trend.
 * - `MiniRing` draws a circular percentage gauge.
 *
 * The sparkline series is deterministic (seeded from a string) so a given card
 * always renders the same shape — purely decorative, not a real time-series.
 */

/** Deterministic, gently-rising series seeded by a string (purely decorative). */
export function sparkHeights(seed: string, baseline: number, count = 9): number[] {
  let h = 2166136261;
  for (let i = 0; i < seed.length; i += 1) {
    h ^= seed.charCodeAt(i);
    h = Math.imul(h, 16777619) >>> 0;
  }
  const out: number[] = [];
  let v = 0.35 + (baseline > 0 ? Math.min(0.35, baseline * 0.35) : 0.15);
  for (let i = 0; i < count; i += 1) {
    h = (Math.imul(h, 1103515245) + 12345) >>> 0;
    const delta = ((h % 1000) / 1000 - 0.42) * 0.28;
    v = Math.min(1, Math.max(0.22, v + delta));
    out.push(v);
  }
  // Nudge the final point up so the series reads as an upward trend.
  out[out.length - 1] = Math.min(1, out[out.length - 1] + 0.15);
  return out;
}

/** Build a smooth (Catmull-Rom → bezier) path string through y-points in [0,1]. */
function smoothPath(values: number[], width: number, height: number, pad = 2): string {
  const n = values.length;
  if (n === 0) return "";
  const innerW = width - pad * 2;
  const innerH = height - pad * 2;
  const pts = values.map((v, i) => ({
    x: pad + (n === 1 ? 0 : (i / (n - 1)) * innerW),
    y: pad + (1 - v) * innerH,
  }));
  if (n === 1) return `M ${pts[0].x} ${pts[0].y}`;
  let d = `M ${pts[0].x} ${pts[0].y}`;
  for (let i = 0; i < n - 1; i += 1) {
    const p0 = pts[i - 1] ?? pts[i];
    const p1 = pts[i];
    const p2 = pts[i + 1];
    const p3 = pts[i + 2] ?? p2;
    const c1x = p1.x + (p2.x - p0.x) / 6;
    const c1y = p1.y + (p2.y - p0.y) / 6;
    const c2x = p2.x - (p3.x - p1.x) / 6;
    const c2y = p2.y - (p3.y - p1.y) / 6;
    d += ` C ${c1x} ${c1y} ${c2x} ${c2y} ${p2.x} ${p2.y}`;
  }
  return d;
}

export type SparklineVariant = "area" | "line";

/**
 * Smooth decorative trend. `area` fills under the curve with an accent gradient;
 * `line` is a clean stroke with a highlighted dot at the latest point.
 */
export function MiniSparkline({
  variant,
  accent = "default",
  seed,
  baseline = 0,
  height = 38,
}: {
  variant: SparklineVariant;
  accent?: OverviewAccent;
  seed: string;
  baseline?: number;
  height?: number;
}) {
  const [light, deep] = overviewAccentGradients[accent] ?? overviewAccentGradients.default;
  const values = sparkHeights(seed, baseline);
  const width = 120;
  const pad = 3;
  const line = smoothPath(values, width, height, pad);
  const last = values[values.length - 1];
  const lastX = pad + ((values.length - 1) / (values.length - 1 || 1)) * (width - pad * 2);
  const lastY = pad + (1 - last) * (height - pad * 2);
  // Unique gradient id per seed+accent so multiple cards don't collide.
  const gid = `spark-${variant}-${accent}-${seed.replace(/[^a-zA-Z0-9]/g, "")}`;

  return (
    <Box style={{ width: "100%" }}>
      <svg
        width="100%"
        height={height}
        viewBox={`0 0 ${width} ${height}`}
        preserveAspectRatio="none"
        style={{ display: "block", overflow: "visible" }}
      >
        <defs>
          <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={deep} stopOpacity={variant === "area" ? 0.32 : 0} />
            <stop offset="100%" stopColor={light} stopOpacity={0} />
          </linearGradient>
        </defs>
        {variant === "area" ? (
          <path
            d={`${line} L ${width - pad} ${height - pad} L ${pad} ${height - pad} Z`}
            fill={`url(#${gid})`}
            stroke="none"
          />
        ) : null}
        <path
          d={line}
          fill="none"
          stroke={deep}
          strokeWidth={2}
          strokeLinecap="round"
          strokeLinejoin="round"
          vectorEffect="non-scaling-stroke"
        />
        {variant === "line" ? (
          <circle cx={lastX} cy={lastY} r={3} fill={deep} stroke="white" strokeWidth={1.5} />
        ) : null}
      </svg>
    </Box>
  );
}

/** Circular percentage gauge with an accent stroke. */
export function MiniRing({
  pct,
  accent = "default",
  size = 52,
  stroke = 5,
  children,
}: {
  pct: number | null | undefined;
  accent?: OverviewAccent;
  size?: number;
  stroke?: number;
  children?: React.ReactNode;
}) {
  const [, deep] = overviewAccentGradients[accent] ?? overviewAccentGradients.default;
  const radius = (size - stroke) / 2;
  const circumference = 2 * Math.PI * radius;
  const clamped = pct != null ? Math.min(100, Math.max(0, Math.round(pct))) : null;
  const dash = clamped != null ? (clamped / 100) * circumference : 0;

  return (
    <Box style={{ position: "relative", width: size, height: size, flexShrink: 0 }}>
      <svg width={size} height={size} style={{ transform: "rotate(-90deg)", display: "block" }}>
        <circle
          cx={size / 2}
          cy={size / 2}
          r={radius}
          fill="none"
          stroke="var(--mantine-color-gray-2)"
          strokeWidth={stroke}
        />
        {clamped != null ? (
          <circle
            cx={size / 2}
            cy={size / 2}
            r={radius}
            fill="none"
            stroke={deep}
            strokeWidth={stroke}
            strokeLinecap="round"
            strokeDasharray={`${dash} ${circumference}`}
            style={{ transition: "stroke-dasharray 400ms ease" }}
          />
        ) : null}
      </svg>
      <Box
        style={{
          position: "absolute",
          inset: 0,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          color: deep,
        }}
      >
        {children}
      </Box>
    </Box>
  );
}
