/* primitives.jsx — small reusable visual building blocks */

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ============================================================
// useDarkMode — reactively tells us if the .dark class is on <html>
// ============================================================
function useDarkMode() {
  const [dark, setDark] = useState(() => typeof document !== "undefined" && document.documentElement.classList.contains("dark"));
  useEffect(() => {
    const obs = new MutationObserver(() => {
      setDark(document.documentElement.classList.contains("dark"));
    });
    obs.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
    return () => obs.disconnect();
  }, []);
  return dark;
}

// ============================================================
// Icon (lucide) wrapper — falls back to a square if not found
// ============================================================
function Icon({ name, className = "w-4 h-4", strokeWidth = 1.75 }) {
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current || !window.lucide) return;
    ref.current.innerHTML = "";
    const pascal = String(name).replace(/(^|-)(\w)/g, (_, __, c) => c.toUpperCase());
    const iconNode =
      window.lucide.icons?.[pascal] ||
      window.lucide.icons?.[name] ||
      window.lucide[pascal] ||
      window.lucide.icons?.Square;
    if (!iconNode) return;
    try {
      const node = window.lucide.createElement(iconNode);
      node.setAttribute("class", className);
      node.setAttribute("stroke-width", String(strokeWidth));
      ref.current.appendChild(node);
    } catch (e) {
      // silent — fall back to nothing
    }
  }, [name, className, strokeWidth]);
  return <span ref={ref} className="inline-flex shrink-0" />;
}

// ============================================================
// Formatters (white-label generic, BRL-style numbers)
// ============================================================
const fmt = {
  money: (v, opts = {}) => {
    if (v == null) return "—";
    const { compact = false, currency = true } = opts;
    if (compact && Math.abs(v) >= 1000) {
      if (Math.abs(v) >= 1e9) return `${currency ? "R$ " : ""}${(v / 1e9).toFixed(2).replace(".", ",")}B`;
      if (Math.abs(v) >= 1e6) return `${currency ? "R$ " : ""}${(v / 1e6).toFixed(2).replace(".", ",")}M`;
      if (Math.abs(v) >= 1e3) return `${currency ? "R$ " : ""}${(v / 1e3).toFixed(1).replace(".", ",")}k`;
    }
    return new Intl.NumberFormat("pt-BR", { style: currency ? "currency" : "decimal", currency: "BRL", minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(v);
  },
  int: (v) => v == null ? "—" : new Intl.NumberFormat("pt-BR").format(Math.round(v)),
  pct: (v, opts = {}) => {
    if (v == null) return "—";
    const { signed = false, dec = 1 } = opts;
    const sign = signed && v > 0 ? "+" : "";
    return `${sign}${v.toFixed(dec).replace(".", ",")}%`;
  },
  num: (v, dec = 2) => v == null ? "—" : v.toFixed(dec).replace(".", ","),
};

// ============================================================
// Mask helpers — placeholders that scream "white-label demo"
// ============================================================
const PH = {
  stores: ["Filial 01", "Filial 02", "Filial 03", "Filial 04", "Filial 05", "Filial 06"],
  regions: ["Sul", "Sudeste", "Centro-Oeste", "Nordeste", "Norte"],
  reps: ["Operador A", "Operador B", "Operador C", "Operador D", "Operador E"],
  groups: ["Grupo Alpha", "Grupo Beta", "Grupo Gama", "Grupo Delta", "Grupo Épsilon"],
  products: [
    "SKU-1042 · Item Padrão A", "SKU-1187 · Item Padrão B", "SKU-2210 · Item Premium C",
    "SKU-2451 · Item Promo D", "SKU-3309 · Item Sazonal E", "SKU-4012 · Item Top F",
    "SKU-5101 · Item Linha G", "SKU-6033 · Item Outlet H",
  ],
  suppliers: ["Fornecedor 01", "Fornecedor 02", "Fornecedor 03", "Fornecedor 04"],
};

// ============================================================
// PrimaryButton, SecondaryButton, IconButton
// ============================================================
function Btn({ children, variant = "secondary", icon, iconRight, className = "", ...rest }) {
  const variantClass = {
    primary: "btn btn-primary",
    secondary: "btn",
    ghost: "btn btn-ghost",
    danger: "btn btn-danger",
  }[variant] || "btn";
  return (
    <button className={`${variantClass} ${className}`} {...rest}>
      {icon && <Icon name={icon} className="w-4 h-4" />}
      {children}
      {iconRight && <Icon name={iconRight} className="w-4 h-4" />}
    </button>
  );
}

function IconBtn({ icon, label, onClick, className = "", active = false }) {
  return (
    <button
      onClick={onClick}
      title={label}
      aria-label={label}
      className={`w-9 h-9 rounded-lg flex items-center justify-center border transition-colors ${active ? "border-[var(--accent)] text-[var(--accent)] bg-[var(--accent-soft)]" : "border-[var(--border)] text-[var(--fg-muted)] hover:text-[var(--fg)] hover:bg-[var(--panel-hi)]"} ${className}`}
    >
      <Icon name={icon} className="w-4 h-4" />
    </button>
  );
}

// ============================================================
// Section header
// ============================================================
function SectionHead({ title, subtitle, kicker, action, icon }) {
  return (
    <div className="flex items-end justify-between gap-4 mb-4">
      <div>
        {kicker && (
          <div className="flex items-center gap-2 mb-1.5">
            <span className="neon-dot" />
            <span className="text-[10px] uppercase tracking-[0.18em] text-[var(--accent)] font-semibold">{kicker}</span>
          </div>
        )}
        <h2 className="text-xl font-semibold tracking-tight flex items-center gap-2.5">
          {icon && <Icon name={icon} className="w-5 h-5 text-[var(--fg-muted)]" />}
          {title}
        </h2>
        {subtitle && <p className="text-[13px] text-[var(--fg-muted)] mt-1 max-w-2xl">{subtitle}</p>}
      </div>
      {action}
    </div>
  );
}

// ============================================================
// Delta indicator (positive/negative %)
// ============================================================
function Delta({ value, suffix = "", inline = false, dec = 1 }) {
  if (value == null) return <span className="text-[var(--fg-faint)] text-xs">—</span>;
  const pos = value >= 0;
  const cls = pos ? "text-[var(--pos)]" : "text-[var(--neg)]";
  const arrow = pos ? "trending-up" : "trending-down";
  return (
    <span className={`inline-flex items-center gap-1 font-mono text-[11px] font-semibold ${cls} num`}>
      <Icon name={arrow} className="w-3 h-3" />
      {pos ? "+" : ""}{value.toFixed(dec).replace(".", ",")}%{suffix}
    </span>
  );
}

// ============================================================
// KPI Tile
// ============================================================
function KPI({ label, value, delta, hint, icon, accent = false, compact = false, format = "money", target, info }) {
  const display = useMemo(() => {
    if (typeof value === "string") return value;
    if (format === "money") return fmt.money(value, { compact });
    if (format === "int") return fmt.int(value);
    if (format === "pct") return fmt.pct(value);
    if (format === "num") return fmt.num(value);
    return value;
  }, [value, format, compact]);

  return (
    <div className={`kpi ${accent ? "kpi-accent" : ""} group`}>
      <div className="flex items-center justify-between text-[var(--fg-muted)]">
        <div className="flex items-center gap-1.5 text-[11px] font-medium uppercase tracking-wider">
          {icon && <Icon name={icon} className="w-3.5 h-3.5" />}
          <span>{label}</span>
          {info && (
            <InfoDot
              content={
                <div>
                  <div className="font-semibold text-[12px] mb-1">{info.title}</div>
                  <div className="text-[var(--fg-muted)]">{info.desc}</div>
                </div>
              }
            />
          )}
        </div>
        {target && <span className="badge">meta {target}</span>}
      </div>
      <div className={`num font-semibold tracking-tight ${compact ? "text-xl" : "text-2xl md:text-[26px]"} text-[var(--fg)] mt-1`}>
        {display}
      </div>
      <div className="flex items-center gap-2 mt-0.5">
        {delta != null && <Delta value={delta} />}
        {hint && <span className="text-[11px] text-[var(--fg-faint)]">{hint}</span>}
      </div>
    </div>
  );
}

// ============================================================
// Tabs
// ============================================================
function Tabs({ items, value, onChange, className = "" }) {
  return (
    <div className={`inline-flex p-1 rounded-xl border border-[var(--border)] bg-[var(--panel-2)] gap-0.5 ${className}`}>
      {items.map((it) => {
        const id = typeof it === "string" ? it : it.id;
        const label = typeof it === "string" ? it : it.label;
        const count = typeof it === "string" ? null : it.count;
        const active = value === id;
        return (
          <button
            key={id}
            onClick={() => onChange(id)}
            className={`px-3 py-1.5 text-[12px] font-medium rounded-lg flex items-center gap-1.5 transition-all ${active ? "bg-[var(--panel-hi)] text-[var(--fg)] shadow-[var(--shadow-sm)]" : "text-[var(--fg-muted)] hover:text-[var(--fg)]"}`}
          >
            {label}
            {count != null && (
              <span className={`text-[10px] px-1.5 py-0.5 rounded-full ${active ? "bg-[var(--accent-soft)] text-[var(--accent)]" : "bg-[var(--panel)] text-[var(--fg-muted)]"}`}>
                {count}
              </span>
            )}
          </button>
        );
      })}
    </div>
  );
}

// ============================================================
// Modal
// ============================================================
function Modal({ open, onClose, title, children, footer, maxWidth = "max-w-2xl" }) {
  useEffect(() => {
    if (!open) return;
    const onEsc = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", onEsc);
    return () => document.removeEventListener("keydown", onEsc);
  }, [open, onClose]);

  if (!open) return null;
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-4 fade-in" onClick={onClose}>
      <div className="absolute inset-0 bg-black/60 backdrop-blur-sm" />
      <div
        className={`relative w-full ${maxWidth} panel-hi slide-up shadow-[var(--shadow-lg)]`}
        onClick={(e) => e.stopPropagation()}
      >
        <div className="flex items-center justify-between px-5 py-4 border-b border-[var(--border)]">
          <h3 className="font-semibold text-[15px] tracking-tight">{title}</h3>
          <button onClick={onClose} className="text-[var(--fg-muted)] hover:text-[var(--fg)] p-1">
            <Icon name="x" className="w-4 h-4" />
          </button>
        </div>
        <div className="p-5 max-h-[70vh] overflow-y-auto">{children}</div>
        {footer && <div className="px-5 py-3.5 border-t border-[var(--border)] flex justify-end gap-2 bg-[var(--panel-2)] rounded-b-[14px]">{footer}</div>}
      </div>
    </div>
  );
}

// ============================================================
// Toast helper (single instance)
// ============================================================
const ToastCtx = React.createContext({ push: () => {} });
function ToastProvider({ children }) {
  const [toasts, setToasts] = useState([]);
  const push = useCallback((t) => {
    const id = Date.now() + Math.random();
    setToasts((prev) => [...prev, { id, ...t }]);
    setTimeout(() => setToasts((prev) => prev.filter((x) => x.id !== id)), t.duration || 3200);
  }, []);
  return (
    <ToastCtx.Provider value={{ push }}>
      {children}
      <div className="fixed top-4 right-4 z-[60] flex flex-col gap-2 pointer-events-none">
        {toasts.map((t) => (
          <div key={t.id} className={`pointer-events-auto panel-hi flex items-start gap-3 px-4 py-3 min-w-[280px] shadow-[var(--shadow-lg)] slide-up ${t.kind === "error" ? "border-[var(--neg)]" : t.kind === "success" ? "border-[var(--pos)]" : ""}`}>
            <Icon name={t.kind === "error" ? "alert-triangle" : t.kind === "success" ? "check-circle-2" : "info"} className={`w-4 h-4 mt-0.5 ${t.kind === "error" ? "text-[var(--neg)]" : t.kind === "success" ? "text-[var(--pos)]" : "text-[var(--accent)]"}`} />
            <div className="flex-1">
              <p className="text-[13px] font-medium">{t.title}</p>
              {t.desc && <p className="text-[12px] text-[var(--fg-muted)] mt-0.5">{t.desc}</p>}
            </div>
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}
const useToast = () => React.useContext(ToastCtx);

// ============================================================
// Spark line — tiny SVG
// ============================================================
function Spark({ points, color = "var(--accent)", height = 32, width = 90, fill = true }) {
  if (!points || points.length === 0) return null;
  const min = Math.min(...points), max = Math.max(...points);
  const span = max - min || 1;
  const step = width / (points.length - 1);
  const pts = points.map((p, i) => [i * step, height - ((p - min) / span) * (height - 4) - 2]);
  const d = pts.map((p, i) => `${i === 0 ? "M" : "L"}${p[0].toFixed(1)},${p[1].toFixed(1)}`).join(" ");
  const fillPath = fill ? `${d} L ${width},${height} L 0,${height} Z` : null;
  return (
    <svg width={width} height={height} className="overflow-visible">
      {fillPath && (
        <>
          <defs>
            <linearGradient id={`g-${color.replace(/[^a-z]/gi, "")}`} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={color} stopOpacity="0.35" />
              <stop offset="100%" stopColor={color} stopOpacity="0" />
            </linearGradient>
          </defs>
          <path d={fillPath} fill={`url(#g-${color.replace(/[^a-z]/gi, "")})`} />
        </>
      )}
      <path d={d} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="2.5" fill={color} />
    </svg>
  );
}

// ============================================================
// Bar chart (categorical, vertical) — pure SVG
// ============================================================
function BarChart({ data, height = 220, valueKey = "value", labelKey = "label", color = "var(--accent)", showValues = true, format }) {
  const dark = useDarkMode();
  const max = Math.max(...data.map((d) => d[valueKey])) || 1;
  return (
    <div className="w-full" style={{ height }}>
      <div className="flex items-end gap-2 h-full">
        {data.map((d, i) => {
          const h = (d[valueKey] / max) * (height - 36);
          const v = d[valueKey];
          return (
            <div key={i} className="flex-1 flex flex-col items-center gap-1.5 min-w-0 group">
              {showValues && (
                <span className="text-[10px] font-mono font-medium text-[var(--fg-muted)] num">
                  {format ? format(v) : v}
                </span>
              )}
              <div
                className="w-full rounded-t-md transition-all relative overflow-hidden"
                style={{
                  height: `${h}px`,
                  background: d.color || color,
                  boxShadow: dark ? `0 0 16px ${d.color || "var(--accent-glow)"}` : "none",
                  minHeight: 4,
                }}
              >
                <div className="absolute inset-0 bg-gradient-to-t from-white/0 to-white/20 dark:to-white/10" />
              </div>
              <span className="text-[10px] text-[var(--fg-muted)] truncate w-full text-center">{d[labelKey]}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ============================================================
// Line chart — pure SVG with grid + axis
// ============================================================
function LineChart({ series, labels, height = 220, colors, formatY }) {
  // series: [{ name, data: [n] }]
  const w = 800, h = height, pad = { l: 36, r: 12, t: 10, b: 22 };
  const allVals = series.flatMap((s) => s.data);
  const max = Math.max(...allVals) * 1.1 || 1;
  const min = Math.min(0, Math.min(...allVals));
  const span = max - min || 1;
  const n = labels.length;
  const xStep = (w - pad.l - pad.r) / (n - 1);
  const yTo = (v) => pad.t + (h - pad.t - pad.b) * (1 - (v - min) / span);
  const fmtY = formatY || ((v) => fmt.money(v, { compact: true }));

  const ticks = 4;
  const tickVals = Array.from({ length: ticks + 1 }, (_, i) => min + (span * i) / ticks);

  return (
    <svg viewBox={`0 0 ${w} ${h}`} className="w-full" style={{ height }}>
      {/* Grid lines */}
      {tickVals.map((tv, i) => (
        <g key={i}>
          <line x1={pad.l} x2={w - pad.r} y1={yTo(tv)} y2={yTo(tv)} stroke="var(--border-soft)" strokeWidth="1" strokeDasharray="2 3" />
          <text x={pad.l - 6} y={yTo(tv) + 3} fontSize="9" fill="var(--fg-faint)" textAnchor="end" fontFamily="Geist Mono">
            {fmtY(tv)}
          </text>
        </g>
      ))}
      {/* X labels */}
      {labels.map((lbl, i) => {
        if (i % Math.ceil(n / 10) !== 0 && i !== n - 1) return null;
        return (
          <text key={i} x={pad.l + i * xStep} y={h - 6} fontSize="9" fill="var(--fg-faint)" textAnchor="middle" fontFamily="Geist Mono">
            {lbl}
          </text>
        );
      })}
      {/* Series */}
      {series.map((s, si) => {
        const c = (colors && colors[si]) || s.color || ["var(--accent)", "var(--accent-2)", "var(--pink)"][si % 3];
        const d = s.data.map((v, i) => `${i === 0 ? "M" : "L"} ${pad.l + i * xStep} ${yTo(v)}`).join(" ");
        const fillD = `${d} L ${pad.l + (n - 1) * xStep} ${yTo(min)} L ${pad.l} ${yTo(min)} Z`;
        return (
          <g key={si}>
            <defs>
              <linearGradient id={`ln-${si}`} x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor={c} stopOpacity="0.25" />
                <stop offset="100%" stopColor={c} stopOpacity="0" />
              </linearGradient>
            </defs>
            {si === 0 && <path d={fillD} fill={`url(#ln-${si})`} />}
            <path d={d} fill="none" stroke={c} strokeWidth={si === 0 ? "2" : "1.5"} strokeDasharray={s.dashed ? "5 4" : "0"} strokeLinecap="round" />
            {s.data.map((v, i) => (
              <circle key={i} cx={pad.l + i * xStep} cy={yTo(v)} r="2.5" fill={c} />
            ))}
          </g>
        );
      })}
    </svg>
  );
}

// ============================================================
// Progress bar
// ============================================================
function Progress({ value, max = 100, color = "var(--accent)", label, height = 6, showVal = false }) {
  const dark = useDarkMode();
  const pct = Math.min(100, Math.max(0, (value / max) * 100));
  return (
    <div className="w-full">
      {(label || showVal) && (
        <div className="flex justify-between text-[11px] mb-1 text-[var(--fg-muted)]">
          {label && <span>{label}</span>}
          {showVal && <span className="num font-mono">{pct.toFixed(0)}%</span>}
        </div>
      )}
      <div className="w-full rounded-full overflow-hidden" style={{ height, background: "var(--border-soft)" }}>
        <div className="h-full rounded-full transition-all" style={{ width: `${pct}%`, background: color, boxShadow: dark ? `0 0 8px ${color}` : "none" }} />
      </div>
    </div>
  );
}

// ============================================================
// Empty state
// ============================================================
function Empty({ icon = "inbox", title, desc, action }) {
  return (
    <div className="flex flex-col items-center justify-center text-center py-12 px-6">
      <div className="w-12 h-12 rounded-2xl bg-[var(--panel-2)] border border-[var(--border)] flex items-center justify-center mb-3">
        <Icon name={icon} className="w-5 h-5 text-[var(--fg-muted)]" />
      </div>
      <p className="font-medium">{title}</p>
      {desc && <p className="text-[12px] text-[var(--fg-muted)] mt-1 max-w-sm">{desc}</p>}
      {action && <div className="mt-3">{action}</div>}
    </div>
  );
}

// ============================================================
// Donut chart (single value)
// ============================================================
function Donut({ value, max = 100, size = 100, stroke = 8, color = "var(--accent)", label, sub }) {
  const dark = useDarkMode();
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const pct = Math.min(100, Math.max(0, (value / max) * 100));
  const dash = (pct / 100) * c;
  return (
    <div className="relative inline-flex items-center justify-center" style={{ width: size, height: size }}>
      <svg width={size} height={size} className="-rotate-90">
        <circle cx={size / 2} cy={size / 2} r={r} stroke="var(--border)" strokeWidth={stroke} fill="none" />
        <circle
          cx={size / 2} cy={size / 2} r={r}
          stroke={color}
          strokeWidth={stroke}
          fill="none"
          strokeDasharray={`${dash} ${c}`}
          strokeLinecap="round"
          style={{ filter: dark ? `drop-shadow(0 0 6px ${color})` : "none", transition: "stroke-dasharray .4s ease" }}
        />
      </svg>
      <div className="absolute inset-0 flex flex-col items-center justify-center">
        <span className="text-base font-semibold num">{label || `${pct.toFixed(0)}%`}</span>
        {sub && <span className="text-[9px] text-[var(--fg-muted)] uppercase tracking-wider">{sub}</span>}
      </div>
    </div>
  );
}

// Export to window so other babel files can use
Object.assign(window, {
  fmt, PH, Icon, Btn, IconBtn, SectionHead, Delta, KPI, Tabs, Modal, ToastProvider, useToast,
  Spark, BarChart, LineChart, Progress, Empty, Donut, useDarkMode,
  DualDelta, KPIDual, HealthScore, RadarChart, Narrative, PeriodPills,
  Tooltip, InfoDot, GLOSSARY,
});

// ============================================================
// Tooltip — lightweight hover/focus popup (positioned on top)
// ============================================================
function Tooltip({ children, content, side = "top", width = 260, delay = 200 }) {
  const [show, setShow] = useState(false);
  const ref = useRef(null);
  const timer = useRef(null);
  const open = useCallback(() => {
    clearTimeout(timer.current);
    timer.current = setTimeout(() => setShow(true), delay);
  }, [delay]);
  const close = useCallback(() => {
    clearTimeout(timer.current);
    setShow(false);
  }, []);
  useEffect(() => () => clearTimeout(timer.current), []);

  return (
    <span ref={ref} className="relative inline-flex" onMouseEnter={open} onMouseLeave={close} onFocus={open} onBlur={close}>
      {children}
      {show && (
        <span
          className="absolute z-[200] pointer-events-none fade-in"
          style={{
            bottom: side === "top" ? "calc(100% + 8px)" : "auto",
            top: side === "bottom" ? "calc(100% + 8px)" : "auto",
            left: "50%",
            transform: "translateX(-50%)",
            width,
          }}
        >
          <span className="block px-3 py-2 rounded-lg text-[11.5px] leading-relaxed border bg-[var(--panel-hi)] text-[var(--fg)] shadow-[var(--shadow-lg)]" style={{ borderColor: "var(--border)" }}>
            {content}
          </span>
          {/* arrow */}
          <span
            className="absolute left-1/2 -translate-x-1/2 w-2 h-2 rotate-45 border bg-[var(--panel-hi)]"
            style={{
              [side === "top" ? "bottom" : "top"]: "-5px",
              borderColor: "var(--border)",
              borderTop: side === "top" ? "none" : undefined,
              borderLeft: side === "top" ? "none" : undefined,
              borderBottom: side === "bottom" ? "none" : undefined,
              borderRight: side === "bottom" ? "none" : undefined,
            }}
          />
        </span>
      )}
    </span>
  );
}

// ============================================================
// InfoDot — small (i) icon that shows a tooltip with the explanation
// ============================================================
function InfoDot({ children, content, side = "top", width = 280 }) {
  return (
    <Tooltip content={content} side={side} width={width}>
      <span className="inline-flex items-center justify-center w-3.5 h-3.5 rounded-full border border-[var(--border)] text-[var(--fg-faint)] hover:text-[var(--accent)] hover:border-[var(--accent)] cursor-help transition-colors">
        <Icon name="info" className="w-2.5 h-2.5" strokeWidth={2} />
        <span className="sr-only">Info</span>
      </span>
    </Tooltip>
  );
}

// ============================================================
// GLOSSARY — central source of truth for metric definitions
// Used by Tooltip / InfoDot throughout the app.
// ============================================================
const GLOSSARY = {
  pa:        { title: "P.A. · Peças por Atendimento",  desc: "Média de peças vendidas por cliente atendido. Quanto maior, melhor o cross-sell." },
  tkm:       { title: "T.K.M. · Ticket Médio do Atendimento", desc: "Faturamento total ÷ número de atendimentos. Indica o valor médio gasto por cliente." },
  pm:        { title: "P.M. · Preço Médio",            desc: "Faturamento total ÷ peças vendidas. Reflete posicionamento e mix vendido." },
  mkp:       { title: "MKP · Markup",                   desc: "Preço de venda ÷ custo. 2,42× significa que o preço é 2,42 vezes o custo. Quanto maior, melhor a margem." },
  yoy:       { title: "YoY · Year over Year",           desc: "Comparativo com o mesmo período do ano anterior. Indica o crescimento real, descontada a sazonalidade." },
  cobertura: { title: "Cobertura de estoque",           desc: "Estoque atual ÷ venda média diária. Em quantos dias o estoque atual aguenta se a venda continuar no ritmo médio." },
  ruptura:   { title: "Ruptura",                        desc: "SKUs com estoque zerado ÷ SKUs ativos. Mede a indisponibilidade da rede e impacto direto em vendas perdidas." },
  conv:      { title: "Conversão",                      desc: "Atendimentos com venda ÷ total de atendimentos. Mede a eficiência da equipe em fechar a venda." },
  mape:      { title: "MAPE · Mean Absolute Percentage Error", desc: "Erro médio absoluto em % entre o previsto e o realizado. Quanto menor, mais preciso o modelo." },
  meta:      { title: "Meta",                           desc: "Objetivo de venda definido para o período. Cobrança proporcional ao dia/semana corrente." },
  margem:    { title: "Margem",                         desc: "(Venda - custo) ÷ venda. Diferente de MKP, expressa o percentual de lucro sobre o preço final." },
  health:    { title: "Saúde da operação", desc: (
    <div>
      <div className="mb-1.5">Nota composta de 0 a 100, atualizada a cada 15 min:</div>
      <ul className="space-y-0.5 text-[11px]">
        <li>• Vendas vs. meta · <span className="font-mono">30%</span></li>
        <li>• Crescimento YoY · <span className="font-mono">25%</span></li>
        <li>• Ruptura (inversa) · <span className="font-mono">20%</span></li>
        <li>• Cobertura · <span className="font-mono">15%</span></li>
        <li>• MKP médio · <span className="font-mono">10%</span></li>
      </ul>
    </div>
  ) },
  confianca: { title: "Confiança da previsão",          desc: "Probabilidade de o valor real cair dentro do intervalo previsto. 90% significa que em 9 de 10 períodos a venda real ficará entre os limites Lo e Hi." },
};

// ============================================================
// DualDelta — two stacked YoY values (vs período anterior + vs ano anterior)
// ============================================================
function DualDelta({ vsPrev, vsYear, prevLabel = "vs. anterior", yearLabel = "vs. 2025", inversed = false }) {
  // inversed: when "down is good" (e.g., ruptura)
  const colorOf = (v) => {
    const positive = inversed ? v <= 0 : v >= 0;
    return positive ? "var(--pos)" : "var(--neg)";
  };
  const arrowOf = (v) => {
    if (inversed) return v <= 0 ? "trending-down" : "trending-up";
    return v >= 0 ? "trending-up" : "trending-down";
  };
  const Row = ({ v, label }) => (
    <div className="flex items-center gap-1 num font-mono text-[10.5px]">
      <Icon name={arrowOf(v)} className="w-2.5 h-2.5" style={{ color: colorOf(v) }} />
      <span className="font-semibold" style={{ color: colorOf(v) }}>{v > 0 ? "+" : ""}{v.toFixed(1)}%</span>
      <span className="text-[var(--fg-faint)] ml-0.5">{label}</span>
    </div>
  );
  return (
    <div className="flex flex-col gap-0.5">
      {vsPrev != null && <Row v={vsPrev} label={prevLabel} />}
      {vsYear != null && <Row v={vsYear} label={yearLabel} />}
    </div>
  );
}

// ============================================================
// KPIDual — KPI tile with dual YoY (vs prev + vs year)
// ============================================================
function KPIDual({ label, value, vsPrev, vsYear, icon, accent = false, format = "money", compact = true, hint, inversed = false, info }) {
  const display = typeof value === "string" ? value
    : format === "money" ? fmt.money(value, { compact })
    : format === "int"   ? fmt.int(value)
    : format === "pct"   ? fmt.pct(value)
    : format === "num"   ? fmt.num(value)
    : value;
  return (
    <div className={`kpi ${accent ? "kpi-accent" : ""}`}>
      <div className="flex items-center gap-1.5 text-[10.5px] font-medium uppercase tracking-wider text-[var(--fg-muted)]">
        {icon && <Icon name={icon} className="w-3.5 h-3.5" />}
        <span>{label}</span>
        {info && (
          <InfoDot
            content={
              <div>
                <div className="font-semibold text-[12px] mb-1">{info.title}</div>
                <div className="text-[var(--fg-muted)]">{info.desc}</div>
              </div>
            }
          />
        )}
      </div>
      <div className="num font-semibold tracking-tight text-[22px] md:text-[24px] mt-0.5">{display}</div>
      <DualDelta vsPrev={vsPrev} vsYear={vsYear} inversed={inversed} />
      {hint && <div className="text-[10px] text-[var(--fg-faint)] mt-0.5">{hint}</div>}
    </div>
  );
}

// ============================================================
// HealthScore — single visual indicator (gauge + stars)
// ============================================================
function HealthScore({ score = 78, size = 120, label = "Saúde da operação" }) {
  const dark = useDarkMode();
  // score 0-100
  const stroke = 9;
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const dash = (Math.min(100, Math.max(0, score)) / 100) * c;
  const color = score >= 80 ? "var(--pos)" : score >= 60 ? "var(--accent)" : score >= 40 ? "var(--warn)" : "var(--neg)";
  const label_ = score >= 90 ? "Excepcional" : score >= 80 ? "Muito boa" : score >= 70 ? "Saudável" : score >= 60 ? "Atenção" : score >= 40 ? "Risco" : "Crítica";
  const stars = Math.round((score / 100) * 5);

  return (
    <div className="flex items-center gap-4">
      <div className="relative" style={{ width: size, height: size }}>
        <svg width={size} height={size} className="-rotate-90">
          <circle cx={size / 2} cy={size / 2} r={r} stroke="var(--border)" strokeWidth={stroke} fill="none" />
          <circle
            cx={size / 2} cy={size / 2} r={r}
            stroke={color}
            strokeWidth={stroke}
            fill="none"
            strokeDasharray={`${dash} ${c}`}
            strokeLinecap="round"
            style={{ filter: dark ? `drop-shadow(0 0 6px ${color})` : "none", transition: "stroke-dasharray .6s ease" }}
          />
        </svg>
        <div className="absolute inset-0 flex flex-col items-center justify-center">
          <span className="num text-[26px] font-semibold tracking-tight">{score}</span>
          <span className="text-[9px] uppercase tracking-wider text-[var(--fg-muted)]">/100</span>
        </div>
      </div>
      <div>
        <div className="text-[10px] uppercase tracking-[0.16em] text-[var(--fg-muted)] font-semibold">{label}</div>
        <div className="text-[18px] font-semibold tracking-tight mt-0.5" style={{ color }}>{label_}</div>
        <div className="flex gap-0.5 mt-1.5">
          {[1, 2, 3, 4, 5].map((i) => (
            <Icon key={i} name={i <= stars ? "star" : "star"} className="w-3.5 h-3.5" strokeWidth={1.6}
              style={{ color: i <= stars ? color : "var(--border)", fill: i <= stars ? color : "transparent" }} />
          ))}
        </div>
        <div className="text-[10px] text-[var(--fg-muted)] mt-2 leading-tight max-w-[220px]">
          Combina vendas, meta, ruptura, cobertura e MKP em uma única nota — atualizada a cada 15 min.
        </div>
      </div>
    </div>
  );
}

// ============================================================
// RadarChart — multi-dim performance spider
// ============================================================
function RadarChart({ axes, value, target, size = 240, color = "var(--accent)" }) {
  const dark = useDarkMode();
  // axes: [{ key, label, max }]
  // value: { key: number, ... } (current)
  // target: { key: number, ... } (optional baseline/target)
  const cx = size / 2, cy = size / 2;
  const radius = (size / 2) - 28;
  const n = axes.length;

  const pointFor = (val, max, i) => {
    const angle = (Math.PI * 2 * i) / n - Math.PI / 2;
    const r = (Math.min(val, max) / max) * radius;
    return [cx + r * Math.cos(angle), cy + r * Math.sin(angle)];
  };

  const valuePoints = axes.map((a, i) => pointFor(value[a.key] || 0, a.max, i));
  const targetPoints = target ? axes.map((a, i) => pointFor(target[a.key] || 0, a.max, i)) : null;

  const polyPath = (pts) => pts.map((p, i) => `${i === 0 ? "M" : "L"} ${p[0]} ${p[1]}`).join(" ") + " Z";

  const labels = axes.map((a, i) => {
    const angle = (Math.PI * 2 * i) / n - Math.PI / 2;
    const r = radius + 16;
    return { x: cx + r * Math.cos(angle), y: cy + r * Math.sin(angle), label: a.label, key: a.key };
  });

  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ overflow: "visible" }}>
      {/* Concentric rings */}
      {[0.25, 0.5, 0.75, 1.0].map((s, i) => (
        <polygon
          key={i}
          points={axes.map((_, j) => {
            const angle = (Math.PI * 2 * j) / n - Math.PI / 2;
            return `${cx + radius * s * Math.cos(angle)},${cy + radius * s * Math.sin(angle)}`;
          }).join(" ")}
          fill="none"
          stroke="var(--border-soft)"
          strokeWidth="1"
          strokeDasharray={i === 3 ? "0" : "2 3"}
        />
      ))}
      {/* Spokes */}
      {axes.map((_, i) => {
        const angle = (Math.PI * 2 * i) / n - Math.PI / 2;
        return <line key={i} x1={cx} y1={cy} x2={cx + radius * Math.cos(angle)} y2={cy + radius * Math.sin(angle)} stroke="var(--border-soft)" strokeWidth="1" />;
      })}
      {/* Target polygon */}
      {targetPoints && (
        <path d={polyPath(targetPoints)} fill="var(--fg-muted)" fillOpacity="0.08" stroke="var(--fg-muted)" strokeWidth="1" strokeDasharray="3 3" />
      )}
      {/* Value polygon */}
      <path d={polyPath(valuePoints)} fill={color} fillOpacity={dark ? 0.22 : 0.18} stroke={color} strokeWidth="1.8" style={{ filter: dark ? `drop-shadow(0 0 6px ${color})` : "none" }} />
      {/* Points */}
      {valuePoints.map((p, i) => <circle key={i} cx={p[0]} cy={p[1]} r="3" fill={color} />)}
      {/* Labels */}
      {labels.map((l, i) => (
        <text key={i} x={l.x} y={l.y} fontSize="10" fill="var(--fg-muted)" textAnchor="middle" dominantBaseline="middle" fontWeight="500">{l.label}</text>
      ))}
    </svg>
  );
}

// ============================================================
// Narrative — storytelling banner with auto-generated sentence
// ============================================================
function Narrative({ tone = "neutral", icon = "sparkles", children, kicker, action }) {
  const tones = {
    positive: { bg: "color-mix(in oklch, var(--pos) 8%, var(--panel))", border: "color-mix(in oklch, var(--pos) 30%, var(--border))", dot: "var(--pos)" },
    warn:     { bg: "color-mix(in oklch, var(--warn) 8%, var(--panel))", border: "color-mix(in oklch, var(--warn) 30%, var(--border))", dot: "var(--warn)" },
    negative: { bg: "color-mix(in oklch, var(--neg) 8%, var(--panel))",  border: "color-mix(in oklch, var(--neg) 30%, var(--border))",  dot: "var(--neg)" },
    neutral:  { bg: "var(--panel)", border: "var(--border)", dot: "var(--accent)" },
  };
  const t = tones[tone] || tones.neutral;
  return (
    <div className="flex items-start gap-3 p-4 rounded-xl border" style={{ background: t.bg, borderColor: t.border }}>
      <div className="w-9 h-9 rounded-lg shrink-0 flex items-center justify-center" style={{ background: "var(--panel)", border: `1px solid ${t.border}`, color: t.dot }}>
        <Icon name={icon} className="w-4 h-4" />
      </div>
      <div className="flex-1 min-w-0">
        {kicker && <div className="text-[10px] uppercase tracking-[0.16em] font-semibold mb-1" style={{ color: t.dot }}>{kicker}</div>}
        <div className="text-[13px] text-[var(--fg)] leading-relaxed">{children}</div>
      </div>
      {action}
    </div>
  );
}

// ============================================================
// PeriodPills — Dia / Semana / Mês / YTD selector
// ============================================================
function PeriodPills({ value, onChange, options = ["Dia", "Semana", "Mês", "YTD"] }) {
  return (
    <div className="inline-flex p-0.5 rounded-lg border border-[var(--border)] bg-[var(--panel-2)] gap-0.5">
      {options.map((opt) => {
        const active = value === opt;
        return (
          <button
            key={opt}
            onClick={() => onChange(opt)}
            className={`px-3 py-1 text-[11.5px] font-medium rounded-md transition-all ${active ? "bg-[var(--panel-hi)] text-[var(--fg)] shadow-[var(--shadow-sm)]" : "text-[var(--fg-muted)] hover:text-[var(--fg)]"}`}
          >
            {opt}
          </button>
        );
      })}
    </div>
  );
}
