/* global React */
const { useState, useEffect, useRef } = React;

/* ============================ ICONS ============================ */
/* Simple stroke icons — geometric, 24x24, currentColor */
const I = {
  grid: "M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z",
  gauge: "M12 13l4-4M5.5 18a9 9 0 1113 0",
  search: "M11 11m-7 0a7 7 0 1014 0a7 7 0 10-14 0M21 21l-5-5",
  sparks: "M12 3l1.8 4.7L18.5 9l-4.7 1.8L12 15l-1.8-4.2L5.5 9l4.7-1.3zM18 14l.9 2.3L21 17l-2.1.9L18 20l-.9-2.1L15 17l2.1-.7z",
  play: "M5 4v16l13-8z",
  shield: "M12 3l8 3v6c0 5-4 8-8 9-4-1-8-4-8-9V6z",
  globe: "M12 3a9 9 0 100 18 9 9 0 000-18M3 12h18M12 3c2.5 2.5 3.5 6 3.5 9s-1 6.5-3.5 9c-2.5-2.5-3.5-6-3.5-9S9.5 5.5 12 3z",
  layers: "M12 3l9 5-9 5-9-5zM3 13l9 5 9-5",
  doc: "M6 3h8l4 4v14H6zM14 3v4h4",
  bell: "M6 9a6 6 0 1112 0c0 5 2 6 2 6H4s2-1 2-6M10 21h4",
  bolt: "M13 3L4 14h6l-1 7 9-11h-6z",
  arrowUp: "M12 19V5M5 12l7-7 7 7",
  arrowDown: "M12 5v14M5 12l7 7 7-7",
  check: "M4 12l5 5L20 6",
  pause: "M8 5v14M16 5v14",
  dot: "",
  chevron: "M9 6l6 6-6 6",
  settings: "M12 9a3 3 0 100 6 3 3 0 000-6M12 2l1.6 3.1 3.4.5-2.5 2.4.6 3.4L12 14.4 8.9 11.8l.6-3.4L7 6l3.4-.5z",
  flask: "M9 3h6M10 3v6l-5 9a2 2 0 002 3h10a2 2 0 002-3l-5-9V3",
};

function Icon({ name, size = 18, stroke = 1.7, fill = false, style = {} }) {
  const d = I[name] || "";
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill ? "currentColor" : "none"}
      stroke={fill ? "none" : "currentColor"} strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"
      style={{ flexShrink: 0, ...style }}>
      <path d={d} />
    </svg>
  );
}

/* ============================ PRIMITIVES ============================ */

function Badge({ children, tone = "neutral", soft = true }) {
  const map = {
    good: ["var(--positive)", "color-mix(in oklch, var(--positive) 16%, transparent)"],
    bad: ["var(--negative)", "color-mix(in oklch, var(--negative) 16%, transparent)"],
    warn: ["var(--warn)", "color-mix(in oklch, var(--warn) 16%, transparent)"],
    accent: ["var(--accent)", "color-mix(in oklch, var(--accent) 16%, transparent)"],
    neutral: ["var(--text-dim)", "color-mix(in oklch, var(--text-dim) 12%, transparent)"],
  };
  const [fg, bg] = map[tone] || map.neutral;
  return (
    <span className="badge" style={{ color: fg, background: soft ? bg : "transparent" }}>
      {children}
    </span>
  );
}

function Delta({ value, invert = false }) {
  const up = value >= 0;
  const good = invert ? !up : up;
  return (
    <span className="delta" style={{ color: good ? "var(--positive)" : "var(--negative)" }}>
      <Icon name={up ? "arrowUp" : "arrowDown"} size={13} stroke={2.2} />
      {Math.abs(value).toFixed(1)}%
    </span>
  );
}

function AutonomyPill({ level }) {
  const map = {
    full: ["Autonome", "good"],
    review: ["Validation", "warn"],
    paused: ["En pause", "neutral"],
  };
  const [label, tone] = map[level] || map.review;
  return <Badge tone={tone}>{label}</Badge>;
}

function StatusDot({ status }) {
  const color = status === "active" ? "var(--accent)" : status === "paused" ? "var(--text-faint)" : "var(--warn)";
  return (
    <span style={{ display: "inline-flex", alignItems: "center" }}>
      <span className={status === "active" ? "pulse-dot" : ""} style={{
        width: 8, height: 8, borderRadius: "50%", background: color,
        boxShadow: status === "active" ? `0 0 0 0 ${color}` : "none",
      }} />
    </span>
  );
}

/* ============================ CHARTS ============================ */

function Sparkline({ data, w = 120, h = 36, color = "var(--accent)", fill = true, strokeW = 2 }) {
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * w;
    const y = h - 4 - ((v - min) / range) * (h - 8);
    return [x, y];
  });
  const line = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const area = line + ` L${w} ${h} L0 ${h} Z`;
  const gid = "sg" + Math.random().toString(36).slice(2, 8);
  return (
    <svg width={w} height={h} style={{ display: "block", overflow: "visible" }}>
      {fill && (
        <>
          <defs>
            <linearGradient id={gid} 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>
          <path d={area} fill={`url(#${gid})`} />
        </>
      )}
      <path d={line} fill="none" stroke={color} strokeWidth={strokeW} strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="2.6" fill={color} />
    </svg>
  );
}

/* Animated count-up number */
function CountUp({ value, duration = 900 }) {
  const [display, setDisplay] = useState(value);
  const ref = useRef();
  useEffect(() => {
    // parse numeric portion
    const numMatch = String(value).replace(/\s/g, "").replace(",", ".").match(/[\d.]+/);
    if (!numMatch) { setDisplay(value); return; }
    const target = parseFloat(numMatch[0]);
    const decimals = (numMatch[0].split(".")[1] || "").length;
    let start = null;
    cancelAnimationFrame(ref.current);
    const step = (t) => {
      if (!start) start = t;
      const p = Math.min((t - start) / duration, 1);
      const eased = 1 - Math.pow(1 - p, 3);
      const cur = target * eased;
      const formatted = cur.toLocaleString("fr-FR", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
      setDisplay(String(value).replace(numMatch[0], formatted));
      if (p < 1) ref.current = requestAnimationFrame(step);
    };
    ref.current = requestAnimationFrame(step);
    return () => cancelAnimationFrame(ref.current);
  }, [value]);
  return <span>{display}</span>;
}

function ViewHeader({ title, sub, action }) {
  return (
    <div className="view-header">
      <div>
        <h1 className="view-title">{title}</h1>
        {sub && <p className="view-sub">{sub}</p>}
      </div>
      {action && <div className="view-action">{action}</div>}
    </div>
  );
}

Object.assign(window, { Icon, Badge, Delta, AutonomyPill, StatusDot, Sparkline, CountUp, ViewHeader });
