"use client";
import { useState } from "react";
import { money, short } from "@/lib/format";

/** Formatters are referenced by name so server pages can pass them to client charts. */
export type Fmt = "money" | "short" | "views" | "num";
const FM: Record<Fmt, (v: number) => string> = { money, short, views: (v) => `${v} views`, num: (v) => String(Math.round(v)) };

export const PALETTE = ["#2563eb", "#06b6d4", "#7c3aed", "#f59e0b", "#10b981", "#ec4899", "#64748b"];

/* ── Speedometer gauge: minimalist half-dial with ticks, colour zones and animated needle ── */
const polar = (cx: number, cy: number, r: number, deg: number) => [cx + r * Math.cos((deg * Math.PI) / 180), cy - r * Math.sin((deg * Math.PI) / 180)];
const arc = (r: number, from: number, to: number) => {
  const [x1, y1] = polar(100, 100, r, 180 - from * 180), [x2, y2] = polar(100, 100, r, 180 - to * 180);
  return `M${x1.toFixed(2)} ${y1.toFixed(2)} A${r} ${r} 0 ${to - from > 0.5 ? 1 : 0} 1 ${x2.toFixed(2)} ${y2.toFixed(2)}`;
};
export function Gauge({ value, max = 100, label, unit = "%", format, text, sub, invert = false, className = "" }:
  { value: number; max?: number; label: string; unit?: string; format?: Fmt; text?: string; sub?: string; invert?: boolean; className?: string }) {
  const pct = Math.max(0, Math.min(1, value / (max || 1)));
  const good = invert ? 1 - pct : pct; // invert: lower is better (e.g. response time)
  const color = good >= 0.75 ? "#10b981" : good >= 0.45 ? "#2563eb" : good >= 0.25 ? "#f59e0b" : "#e11d48";
  const gid = "g" + label.replace(/\W/g, "");
  return (
    <figure className={`text-center ${className}`} aria-label={`${label}: ${text ?? (format ? FM[format](value) : value)}${unit}`}>
      <svg viewBox="0 0 200 122" className="mx-auto w-full max-w-[240px]" role="img">
        <defs><linearGradient id={gid} x1="0" x2="1"><stop offset="0" stopColor={color} stopOpacity=".55" /><stop offset="1" stopColor={color} /></linearGradient></defs>
        <path d={arc(80, 0, 1)} fill="none" stroke="#eef2f9" strokeWidth="14" strokeLinecap="round" />
        <path d={arc(80, 0, Math.max(pct, 0.004))} fill="none" stroke={`url(#${gid})`} strokeWidth="14" strokeLinecap="round" style={{ transition: "all 1s cubic-bezier(.2,.7,.2,1)" }} />
        {Array.from({ length: 21 }).map((_, i) => {
          const big = i % 5 === 0, [x1, y1] = polar(100, 100, big ? 62 : 65, 180 - (i / 20) * 180), [x2, y2] = polar(100, 100, 69, 180 - (i / 20) * 180);
          return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke={big ? "#94a3b8" : "#d5dce9"} strokeWidth={big ? 1.6 : 1} strokeLinecap="round" />;
        })}
        <g style={{ transform: `rotate(${-90 + pct * 180}deg)`, transformOrigin: "100px 100px", transition: "transform 1.1s cubic-bezier(.2,.9,.25,1.15)" }}>
          <path d="M100 100 L97.4 100 L100 40 L102.6 100 Z" fill="#0b1220" /></g>
        <circle cx="100" cy="100" r="6.5" fill="#fff" stroke="#0b1220" strokeWidth="3" />
        <text x="14" y="118" fontSize="8" fill="#94a3b8" textAnchor="middle">0</text>
        <text x="186" y="118" fontSize="8" fill="#94a3b8" textAnchor="middle">{max >= 1000 ? `${Math.round(max / 1000)}k` : max}</text>
      </svg>
      <div className="-mt-1 text-2xl font-bold tracking-tight">{text ?? (format ? FM[format](value) : Math.round(value))}<span className="ml-0.5 text-sm font-semibold text-slate-400">{unit}</span></div>
      <figcaption className="mt-0.5 text-xs font-semibold text-slate-500">{label}</figcaption>
      {sub && <div className="text-[11px] text-slate-400">{sub}</div>}
    </figure>
  );
}

/* ── Smooth area chart with hover tooltip ── */
export function AreaChart({ data, height = 220, color = "#2563eb", fmt = "num" }: { data: { label: string; value: number }[]; height?: number; color?: string; fmt?: Fmt }) {
  const [hi, setHi] = useState<number | null>(null);
  const W = 640, H = height, P = { l: 8, r: 8, t: 14, b: 22 };
  const max = Math.max(1, ...data.map((d) => d.value)) * 1.12;
  const x = (i: number) => P.l + (i / Math.max(1, data.length - 1)) * (W - P.l - P.r);
  const y = (v: number) => P.t + (1 - v / max) * (H - P.t - P.b);
  const pts = data.map((d, i) => [x(i), y(d.value)]);
  const line = pts.reduce((a, p, i) => { if (!i) return `M${p[0]} ${p[1]}`; const q = pts[i - 1], cx = (q[0] + p[0]) / 2; return `${a} C${cx} ${q[1]} ${cx} ${p[1]} ${p[0]} ${p[1]}`; }, "");
  const id = "ac" + color.slice(1);
  return (
    <div className="relative">
      <svg viewBox={`0 0 ${W} ${H}`} className="w-full" onMouseLeave={() => setHi(null)}
        onMouseMove={(e) => { const r = e.currentTarget.getBoundingClientRect(); setHi(Math.max(0, Math.min(data.length - 1, Math.round(((e.clientX - r.left) / r.width * W - P.l) / (W - P.l - P.r) * (data.length - 1))))); }}>
        <defs><linearGradient id={id} x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor={color} stopOpacity=".22" /><stop offset="1" stopColor={color} stopOpacity="0" /></linearGradient></defs>
        {[0.25, 0.5, 0.75].map((g) => <line key={g} x1={P.l} x2={W - P.r} y1={P.t + g * (H - P.t - P.b)} y2={P.t + g * (H - P.t - P.b)} stroke="#eef2f9" />)}
        {pts.length > 1 && <><path d={`${line} L${x(data.length - 1)} ${H - P.b} L${x(0)} ${H - P.b} Z`} fill={`url(#${id})`} /><path d={line} fill="none" stroke={color} strokeWidth="2.5" strokeLinecap="round" /></>}
        {data.map((d, i) => (i % Math.ceil(data.length / 7) === 0) && <text key={i} x={x(i)} y={H - 6} fontSize="10" fill="#94a3b8" textAnchor="middle">{d.label}</text>)}
        {hi !== null && <><line x1={x(hi)} x2={x(hi)} y1={P.t} y2={H - P.b} stroke={color} strokeOpacity=".25" /><circle cx={x(hi)} cy={y(data[hi].value)} r="5" fill="#fff" stroke={color} strokeWidth="2.5" /></>}
      </svg>
      {hi !== null && <div className="pointer-events-none absolute top-1 rounded-lg bg-ink px-2.5 py-1.5 text-xs font-semibold text-white shadow-lg" style={{ left: `${(x(hi) / W) * 100}%`, transform: `translateX(${hi > data.length * 0.7 ? "-105%" : "8px"})`, background: "#0b1220" }}>
        <div className="text-[10px] font-medium text-slate-300">{data[hi].label}</div>{FM[fmt](data[hi].value)}</div>}
    </div>
  );
}

export function Donut({ items, size = 150, center }: { items: { label: string; value: number }[]; size?: number; center?: string }) {
  const total = items.reduce((a, b) => a + b.value, 0) || 1; let acc = 0; const R = 52, C = 2 * Math.PI * R;
  return (
    <div className="flex flex-wrap items-center gap-5">
      <svg width={size} height={size} viewBox="0 0 140 140" role="img" aria-label="Distribution">
        <circle cx="70" cy="70" r={R} fill="none" stroke="#eef2f9" strokeWidth="16" />
        {items.map((it, i) => { const len = (it.value / total) * C, off = -acc; acc += len;
          return <circle key={i} cx="70" cy="70" r={R} fill="none" stroke={PALETTE[i % PALETTE.length]} strokeWidth="16" strokeDasharray={`${Math.max(0, len - 2)} ${C}`} strokeDashoffset={off} transform="rotate(-90 70 70)" strokeLinecap="butt" />; })}
        <text x="70" y="68" textAnchor="middle" fontSize="17" fontWeight="700" fill="#0b1220">{center}</text><text x="70" y="82" textAnchor="middle" fontSize="8" fill="#94a3b8">TOTAL</text>
      </svg>
      <ul className="min-w-[120px] flex-1 space-y-1.5 text-xs">
        {items.map((it, i) => <li key={i} className="flex items-center gap-2"><span className="h-2.5 w-2.5 rounded-full" style={{ background: PALETTE[i % PALETTE.length] }} /><span className="flex-1 truncate text-slate-600">{it.label}</span><b>{Math.round((it.value / total) * 100)}%</b></li>)}
      </ul>
    </div>
  );
}

export function BarList({ items, fmt = "num" }: { items: { label: string; value: number; sub?: string }[]; fmt?: Fmt }) {
  const max = Math.max(1, ...items.map((i) => i.value));
  return (
    <ul className="space-y-3">
      {items.map((it, i) => (
        <li key={i}><div className="mb-1 flex justify-between text-xs"><span className="font-medium text-slate-700">{it.label}</span><span className="font-semibold">{FM[fmt](it.value)}</span></div>
          <div className="h-2 overflow-hidden rounded-full bg-slate-100"><div className="h-full rounded-full" style={{ width: `${(it.value / max) * 100}%`, background: `linear-gradient(90deg, ${PALETTE[i % PALETTE.length]}, ${PALETTE[(i + 1) % PALETTE.length]})`, transition: "width 1s" }} /></div></li>
      ))}
    </ul>
  );
}

export function Spark({ values, color = "#2563eb", w = 90, h = 28 }: { values: number[]; color?: string; w?: number; h?: number }) {
  const max = Math.max(1, ...values), min = Math.min(...values);
  const p = values.map((v, i) => `${(i / Math.max(1, values.length - 1)) * w},${h - 2 - ((v - min) / (max - min || 1)) * (h - 4)}`).join(" ");
  return <svg width={w} height={h} aria-hidden><polyline points={p} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /></svg>;
}
