/* 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, fill, style }) {
  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));
      // Propaga fill quando passado — Lucide gera fill="none" por default, queremos override pra estrela preenchida etc.
      if (fill) node.setAttribute("fill", fill);
      ref.current.appendChild(node);
    } catch (e) {
      // silent — fall back to nothing
    }
  }, [name, className, strokeWidth, fill]);
  return <span ref={ref} className="inline-flex shrink-0" style={style} />;
}

// ============================================================
// 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 = "", onClick, ...rest }) {
  const variantClass = {
    primary: "btn btn-primary",
    secondary: "btn",
    ghost: "btn btn-ghost",
    danger: "btn btn-danger",
  }[variant] || "btn";

  // Auto-toast em botoes "Exportar" sem onClick definido — feedback global automatico.
  const toast = useToast();
  const isExportBtn = !onClick && (icon === "download" || icon === "file-down" ||
    (typeof children === "string" && /export/i.test(children)));
  const handleClick = isExportBtn
    ? (e) => {
        e?.preventDefault?.();
        toast.push({ tone: "success", title: "XLSX exportado com sucesso", desc: "Arquivo salvo em Downloads" });
      }
    : onClick;

  return (
    <button className={`${variantClass} ${className}`} onClick={handleClick} {...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 ToastProviderInner({ children }) {
  const [toasts, setToasts] = useState([]);
  const push = useCallback((t) => {
    const id = Date.now() + Math.random();
    // Suporta `tone` (success/error/info) como sinônimo de `kind`
    const kind = t.kind || t.tone;
    setToasts((prev) => [...prev, { id, ...t, kind }]);
    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>
  );
}

// ToastProvider wrapper que tambem ja embute PeriodProvider —
// assim toda tela que ja tinha ToastProvider ganha periodo global de graca.
function ToastProvider({ children }) {
  return (
    <PeriodProviderInternal>
      <ToastProviderInner>{children}</ToastProviderInner>
    </PeriodProviderInternal>
  );
}
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);

  // Hover tooltip — qual ponto está sob o mouse
  const [hoverIdx, setHoverIdx] = useState(null);
  const wrapperRef = useRef(null);

  // Calcula posição do mouse em coordenadas do viewBox e acha o índice mais próximo
  const handleMove = (e) => {
    if (!wrapperRef.current) return;
    const rect = wrapperRef.current.getBoundingClientRect();
    const xRel = e.clientX - rect.left;
    const xVB = (xRel / rect.width) * w; // converte pra coord do viewBox
    const idx = Math.round((xVB - pad.l) / xStep);
    if (idx >= 0 && idx < n) setHoverIdx(idx);
    else setHoverIdx(null);
  };

  return (
    <div ref={wrapperRef} className="relative w-full" style={{ height }} onMouseMove={handleMove} onMouseLeave={() => setHoverIdx(null)}>
      <svg viewBox={`0 0 ${w} ${h}`} className="w-full block" style={{ height }} preserveAspectRatio="none">
        {/* 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>
          );
        })}
        {/* Crosshair vertical no hover */}
        {hoverIdx != null && (
          <line
            x1={pad.l + hoverIdx * xStep}
            x2={pad.l + hoverIdx * xStep}
            y1={pad.t}
            y2={h - pad.b}
            stroke="var(--accent)"
            strokeWidth="1"
            strokeDasharray="3 3"
            opacity="0.5"
          />
        )}
        {/* 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={hoverIdx === i ? "5" : "2.5"} fill={c} stroke={hoverIdx === i ? "var(--panel)" : "none"} strokeWidth={hoverIdx === i ? "2" : "0"} style={{ transition: "r 120ms ease" }} />
              ))}
            </g>
          );
        })}
      </svg>

      {/* Tooltip HTML overlay */}
      {hoverIdx != null && (() => {
        const xPct = ((pad.l + hoverIdx * xStep) / w) * 100;
        const tooltipOnRight = xPct > 70;
        return (
          <div
            className="absolute pointer-events-none z-10 fade-in"
            style={{
              left: `${xPct}%`,
              top: 8,
              transform: tooltipOnRight ? "translateX(calc(-100% - 12px))" : "translateX(12px)",
            }}
          >
            <div className="panel-hi shadow-[var(--shadow-lg)] px-3 py-2 min-w-[140px]">
              <div className="text-[10px] uppercase tracking-wider text-[var(--fg-muted)] font-semibold mb-1.5">{labels[hoverIdx]}</div>
              <div className="space-y-0.5">
                {series.map((s, si) => {
                  const c = (colors && colors[si]) || s.color || ["var(--accent)", "var(--accent-2)", "var(--pink)"][si % 3];
                  return (
                    <div key={si} className="flex items-center gap-2 text-[11px]">
                      <span className="w-2 h-2 rounded-full shrink-0" style={{ background: c }} />
                      <span className="text-[var(--fg-muted)] flex-1">{s.name}</span>
                      <span className="num font-mono font-semibold">{fmtY(s.data[hoverIdx])}</span>
                    </div>
                  );
                })}
                {/* Δ% entre 1ª e 2ª série (Atual vs LY) */}
                {series.length >= 2 && (
                  <div className="flex items-center gap-2 text-[10px] pt-1 mt-1 border-t border-[var(--border)]">
                    <span className="text-[var(--fg-faint)] flex-1">Δ vs. {series[1].name}</span>
                    <span className="num font-mono font-semibold" style={{ color: series[0].data[hoverIdx] >= series[1].data[hoverIdx] ? "var(--pos)" : "var(--neg)" }}>
                      {series[1].data[hoverIdx] ? (((series[0].data[hoverIdx] - series[1].data[hoverIdx]) / series[1].data[hoverIdx]) * 100).toFixed(1) : "0.0"}%
                    </span>
                  </div>
                )}
              </div>
            </div>
          </div>
        );
      })()}
    </div>
  );
}

// ============================================================
// 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 [pos, setPos] = useState({ top: 0, left: 0, side: side });
  const ref = useRef(null);
  const timer = useRef(null);

  // Cálculo via getBoundingClientRect + auto-flip + clamp.
  // - Auto-flip: se side="top" não cabe acima do anchor, flipa pra "bottom" (e vice-versa)
  // - Clamp horizontal: tooltip nunca vaza pelas bordas esquerda/direita da viewport
  // - Tooltip é portalizado no document.body, então coords são em viewport puro
  //   (escapa de qualquer transform ancestral — necessário pra tablet preview)
  const computePos = useCallback(() => {
    if (!ref.current) return;
    const r = ref.current.getBoundingClientRect();
    const margin = 8;
    const half = width / 2;
    // Estimativa conservadora de altura do tooltip (não temos a altura real antes do render)
    const estimatedHeight = 100;

    // Auto-flip vertical
    let effSide = side;
    if (side === "top" && r.top < estimatedHeight + margin) effSide = "bottom";
    if (side === "bottom" && r.bottom + estimatedHeight + margin > window.innerHeight) effSide = "top";

    // Clamp horizontal
    let cx = r.left + r.width / 2;
    const minCx = half + margin;
    const maxCx = window.innerWidth - half - margin;
    if (cx < minCx) cx = minCx;
    if (cx > maxCx) cx = maxCx;

    const top = effSide === "top" ? r.top - 8 : r.bottom + 8;
    setPos({ top, left: cx, side: effSide });
  }, [side, width]);

  const open = useCallback(() => {
    clearTimeout(timer.current);
    timer.current = setTimeout(() => {
      computePos();
      setShow(true);
    }, delay);
  }, [delay, computePos]);
  const close = useCallback(() => {
    clearTimeout(timer.current);
    setShow(false);
  }, []);
  useEffect(() => () => clearTimeout(timer.current), []);

  // Reposiciona em scroll/resize enquanto aberto
  useEffect(() => {
    if (!show) return;
    const handler = () => computePos();
    window.addEventListener("scroll", handler, true);
    window.addEventListener("resize", handler);
    return () => {
      window.removeEventListener("scroll", handler, true);
      window.removeEventListener("resize", handler);
    };
  }, [show, computePos]);

  // Tooltip portalizado no document.body — necessário pra escapar de qualquer
  // transform ancestral (ex: tablet preview tem scale). Position: fixed dentro
  // de um ancestral com transform é resolvido relativo ao bezel transformado,
  // NÃO ao viewport. Portal pro body é a única solução correta.
  const effSide = pos.side;
  const tooltipNode = show && typeof document !== "undefined"
    ? ReactDOM.createPortal(
        <span
          className="fixed z-[9999] pointer-events-none fade-in"
          style={{
            top: pos.top,
            left: pos.left,
            transform: effSide === "top"
              ? "translate(-50%, -100%)"
              : "translate(-50%, 0)",
            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={{
              [effSide === "top" ? "bottom" : "top"]: "-5px",
              borderColor: "var(--border)",
              borderTop: effSide === "top" ? "none" : undefined,
              borderLeft: effSide === "top" ? "none" : undefined,
              borderBottom: effSide === "bottom" ? "none" : undefined,
              borderRight: effSide === "bottom" ? "none" : undefined,
            }}
          />
        </span>,
        document.body
      )
    : null;

  return (
    <span ref={ref} className="relative inline-flex" onMouseEnter={open} onMouseLeave={close} onFocus={open} onBlur={close}>
      {children}
      {tooltipNode}
    </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="info-dot inline-flex items-center justify-center w-3.5 h-3.5 rounded-full border border-[var(--accent)] text-[var(--accent)] cursor-help transition-colors hover:scale-110">
        <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) => {
            const filled = i <= stars;
            return (
              <Icon
                key={i}
                name="star"
                className="w-3.5 h-3.5"
                strokeWidth={1.6}
                fill={filled ? color : "none"}
                style={{ color: filled ? color : "var(--border)" }}
              />
            );
          })}
        </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 [hoverAxis, setHoverAxis] = useState(null);

  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 (
    <div className="relative inline-block">
    <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 com hover */}
      {valuePoints.map((p, i) => (
        <g key={i}>
          <circle cx={p[0]} cy={p[1]} r={hoverAxis === i ? "5" : "3"} fill={color} stroke={hoverAxis === i ? "var(--panel)" : "none"} strokeWidth={hoverAxis === i ? "2" : "0"} style={{ transition: "r 120ms ease" }} />
          {/* Hover target invisível maior pra facilitar mira */}
          <circle cx={p[0]} cy={p[1]} r="14" fill="transparent" style={{ cursor: "pointer" }} onMouseEnter={() => setHoverAxis(i)} onMouseLeave={() => setHoverAxis(null)} />
        </g>
      ))}
      {/* Labels */}
      {labels.map((l, i) => (
        <text key={i} x={l.x} y={l.y} fontSize="10" fill={hoverAxis === i ? "var(--accent)" : "var(--fg-muted)"} fontWeight={hoverAxis === i ? "600" : "500"} textAnchor="middle" dominantBaseline="middle" style={{ transition: "fill 120ms ease" }}>{l.label}</text>
      ))}
    </svg>

    {/* Tooltip do eixo em hover */}
    {hoverAxis != null && (() => {
      const a = axes[hoverAxis];
      const val = value[a.key] || 0;
      const tgt = target ? (target[a.key] || 0) : null;
      const point = valuePoints[hoverAxis];
      const tooltipOnRight = point[0] > cx;
      return (
        <div
          className="absolute pointer-events-none z-10 fade-in"
          style={{
            left: `${(point[0] / size) * 100}%`,
            top: `${(point[1] / size) * 100}%`,
            transform: `translate(${tooltipOnRight ? "calc(-100% - 12px)" : "12px"}, -50%)`,
          }}
        >
          <div className="panel-hi shadow-[var(--shadow-lg)] px-3 py-2 min-w-[140px]">
            <div className="text-[10px] uppercase tracking-wider text-[var(--fg-muted)] font-semibold mb-1.5">{a.label}</div>
            <div className="flex items-center gap-2 text-[11px]">
              <span className="w-2 h-2 rounded-full shrink-0" style={{ background: color }} />
              <span className="text-[var(--fg-muted)] flex-1">Atual</span>
              <span className="num font-mono font-semibold">{val.toFixed(0)} / {a.max}</span>
            </div>
            {tgt != null && (
              <div className="flex items-center gap-2 text-[11px] mt-1 pt-1 border-t border-[var(--border)]">
                <span className="w-2 h-2 rounded-full bg-[var(--fg-muted)] shrink-0" />
                <span className="text-[var(--fg-muted)] flex-1">Meta</span>
                <span className="num font-mono">{tgt.toFixed(0)}</span>
              </div>
            )}
            <div className="text-[9.5px] text-[var(--fg-faint)] mt-1.5">
              {((val / a.max) * 100).toFixed(0)}% do teto · {tgt != null && (val >= tgt ? "✓ acima da meta" : `${(((val - tgt) / tgt) * 100).toFixed(1)}% vs. meta`)}
            </div>
          </div>
        </div>
      );
    })()}
    </div>
  );
}

// ============================================================
// 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"] }) {
  // Auto-fallback: se onChange/value nao foram passados, usa o PeriodContext global
  // (assim botoes legacy passam a funcionar sem precisar reescrever as telas).
  const ctx = React.useContext(PeriodCtx);
  const effValue = value !== undefined ? value : ctx.period;
  const effOnChange = onChange || ctx.setPeriod;

  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 = effValue === opt;
        return (
          <button
            key={opt}
            onClick={() => effOnChange(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>
  );
}

// ============================================================
// PeriodContext — periodo global compartilhado entre telas.
// Multiplicador determinístico aplicado em valores monetários/quantidade
// pra simular variação por periodo selecionado (mock convincente).
// ============================================================
const PeriodCtx = React.createContext({ period: "Mês", setPeriod: () => {}, mult: 1 });

const PERIOD_MULT = {
  "Dia":    0.06,
  "Ontem":  0.05,
  "Semana": 0.23,
  "Mês":    1,
  "Mês anterior": 0.92,
  "Últimos 30 dias": 0.98,
  "Trimestre": 2.85,
  "YTD":    8.5,
};

function PeriodProviderInternal({ children }) {
  const [period, setPeriod] = useState("Mês");
  const value = useMemo(() => ({
    period,
    setPeriod,
    mult: PERIOD_MULT[period] || 1,
  }), [period]);
  return <PeriodCtx.Provider value={value}>{children}</PeriodCtx.Provider>;
}

const usePeriod = () => React.useContext(PeriodCtx);

// ============================================================
// ContactConfig — número/canal de contato comercial centralizado.
// Mudar aqui propaga pra TODOS os pontos de conversão (CTAs PlanosPage,
// FloatingCTAs, modal Suporte, etc).
// ============================================================
const CONTACT = {
  whatsappNumber: "5542999602137",      // formato internacional sem +
  whatsappDisplay: "(42) 99960-2137",   // formato BR pra exibir
  email: "contato@dashm.shop",
};

const buildWhatsAppUrl = (msg) => {
  const encoded = encodeURIComponent(msg || "Olá! Vim do DashM e gostaria de saber mais sobre os planos.");
  return `https://wa.me/${CONTACT.whatsappNumber}?text=${encoded}`;
};

// ============================================================
// WhatsAppLogo — SVG oficial inline do logo do WhatsApp.
// Lucide tem "message-circle" genérico — usamos esse pra fidelidade visual.
// Path do logo oficial (WhatsApp Inc., uso identificador, não comercial).
// ============================================================
function WhatsAppLogo({ size = 24, className = "", style = {} }) {
  return (
    <svg
      width={size}
      height={size}
      viewBox="0 0 32 32"
      xmlns="http://www.w3.org/2000/svg"
      className={className}
      style={style}
      aria-label="WhatsApp"
    >
      <path
        fill="currentColor"
        d="M16.003 0C7.222 0 .083 7.137.083 15.917c0 2.804.733 5.542 2.122 7.957L0 32l8.323-2.18a15.93 15.93 0 0 0 7.68 1.953h.007C24.79 31.773 32 24.636 32 15.857 32 7.077 24.787 0 16.003 0Zm0 29.057h-.005a13.218 13.218 0 0 1-6.737-1.844l-.484-.287-4.94 1.294 1.32-4.815-.315-.5a13.184 13.184 0 0 1-2.022-7.005c.003-7.303 5.94-13.24 13.248-13.24 3.537 0 6.86 1.378 9.36 3.882a13.144 13.144 0 0 1 3.873 9.363c-.003 7.304-5.94 13.152-13.298 13.152Zm7.273-9.875c-.4-.2-2.36-1.164-2.726-1.298-.366-.133-.633-.2-.9.2-.266.4-1.033 1.298-1.266 1.564-.233.267-.466.3-.866.1-.4-.2-1.685-.62-3.21-1.978-1.187-1.058-1.987-2.365-2.22-2.765-.233-.4-.025-.617.175-.816.18-.18.4-.467.6-.7.2-.234.266-.4.4-.667.133-.267.066-.5-.033-.7-.1-.2-.9-2.166-1.232-2.965-.324-.778-.654-.672-.9-.685-.233-.012-.5-.014-.766-.014a1.47 1.47 0 0 0-1.066.5c-.366.4-1.4 1.366-1.4 3.332s1.432 3.864 1.632 4.13c.2.267 2.82 4.306 6.83 6.038 2.534 1.094 3.526 1.187 4.793.998.772-.115 2.36-.964 2.692-1.895.333-.93.333-1.728.233-1.895-.1-.166-.367-.266-.766-.466Z"
      />
    </svg>
  );
}

Object.assign(window, { WhatsAppLogo });

// ============================================================
// ContactDialog — modal universal de captura comercial.
// Estado interno: "choice" (Whats|Form) → "form" (formulário) → fecha.
// WhatsApp abre nova aba direto pra wa.me; form simula salvar+toast.
// ============================================================
function ContactDialog({ open, onClose, context = "general", title, whatsappMessage }) {
  const toast = useToast();
  const [step, setStep] = useState("choice"); // "choice" | "form"
  const [form, setForm] = useState({ nome: "", empresa: "", email: "", telefone: "", mensagem: "" });

  useEffect(() => {
    if (!open) {
      // reset ao fechar pra próxima abertura começar limpa
      const t = setTimeout(() => {
        setStep("choice");
        setForm({ nome: "", empresa: "", email: "", telefone: "", mensagem: "" });
      }, 200);
      return () => clearTimeout(t);
    }
  }, [open]);

  const headerTitle = title || (context === "studio" ? "Falar com um especialista" : "Quero conhecer o DashM");

  const handleWhats = () => {
    window.open(buildWhatsAppUrl(whatsappMessage), "_blank", "noopener,noreferrer");
    onClose();
    toast({ tone: "success", title: "Abrindo WhatsApp", desc: "Continuamos por lá." });
  };

  const canSubmit = form.nome.trim() && form.email.trim() && form.telefone.trim();

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!canSubmit) {
      toast({ tone: "error", title: "Preencha os campos obrigatórios", desc: "Nome, e-mail e telefone." });
      return;
    }
    toast({ tone: "success", title: "Recebemos seu contato", desc: "Vamos retornar em até 1 dia útil." });
    onClose();
  };

  if (!open) return null;

  return (
    <Modal open={open} onClose={onClose} title={headerTitle} maxWidth="max-w-xl">
      {step === "choice" && (
        <div className="space-y-3">
          <p className="text-[13px] text-[var(--fg-muted)] leading-relaxed">
            Escolha como prefere falar com a gente — respondemos rápido pelos dois canais.
          </p>
          <button
            onClick={handleWhats}
            className="w-full p-4 rounded-xl border border-[var(--border)] hover:border-[#25D366] hover:bg-[#25D366]/8 transition-all text-left flex items-center gap-3 group"
          >
            <div className="w-11 h-11 rounded-xl bg-[#25D366]/12 text-[#25D366] flex items-center justify-center shrink-0">
              <WhatsAppLogo size={22} />
            </div>
            <div className="flex-1 min-w-0">
              <div className="text-[13.5px] font-semibold flex items-center gap-2">
                WhatsApp
                <span className="badge badge-pos text-[9px]">recomendado</span>
              </div>
              <div className="text-[11.5px] text-[var(--fg-muted)] mt-0.5">{CONTACT.whatsappDisplay} · resposta no mesmo dia</div>
            </div>
            <Icon name="arrow-right" className="w-4 h-4 text-[var(--fg-muted)] group-hover:translate-x-0.5 group-hover:text-[#25D366] transition-all" />
          </button>
          <button
            onClick={() => setStep("form")}
            className="w-full p-4 rounded-xl border border-[var(--border)] hover:border-[var(--accent)] hover:bg-[var(--accent-soft)] transition-all text-left flex items-center gap-3 group"
          >
            <div className="w-11 h-11 rounded-xl bg-[var(--accent-soft)] text-[var(--accent)] flex items-center justify-center shrink-0">
              <Icon name="mail" className="w-5 h-5" />
            </div>
            <div className="flex-1 min-w-0">
              <div className="text-[13.5px] font-semibold">Preencher formulário</div>
              <div className="text-[11.5px] text-[var(--fg-muted)] mt-0.5">Deixe seus dados e retornamos em até 1 dia útil</div>
            </div>
            <Icon name="arrow-right" className="w-4 h-4 text-[var(--fg-muted)] group-hover:translate-x-0.5 group-hover:text-[var(--accent)] transition-all" />
          </button>
          <p className="text-[10.5px] text-[var(--fg-faint)] text-center mt-1">
            Atendimento PT-BR · seg-sex 9h-18h · enviamos proposta personalizada
          </p>
        </div>
      )}

      {step === "form" && (
        <form onSubmit={handleSubmit} className="space-y-3">
          <button type="button" onClick={() => setStep("choice")} className="inline-flex items-center gap-1.5 text-[11.5px] text-[var(--fg-muted)] hover:text-[var(--fg)] mb-1">
            <Icon name="arrow-left" className="w-3.5 h-3.5" /> Voltar
          </button>
          <div className="grid grid-cols-2 gap-3">
            <div className="col-span-2">
              <label className="text-[10.5px] uppercase tracking-wider text-[var(--fg-muted)] font-semibold">Nome *</label>
              <input
                type="text"
                value={form.nome}
                onChange={(e) => setForm(f => ({ ...f, nome: e.target.value }))}
                className="w-full mt-1 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--panel-2)] text-[13px] focus:border-[var(--accent)] outline-none"
                placeholder="Seu nome"
              />
            </div>
            <div>
              <label className="text-[10.5px] uppercase tracking-wider text-[var(--fg-muted)] font-semibold">Empresa</label>
              <input
                type="text"
                value={form.empresa}
                onChange={(e) => setForm(f => ({ ...f, empresa: e.target.value }))}
                className="w-full mt-1 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--panel-2)] text-[13px] focus:border-[var(--accent)] outline-none"
                placeholder="Nome da rede / loja"
              />
            </div>
            <div>
              <label className="text-[10.5px] uppercase tracking-wider text-[var(--fg-muted)] font-semibold">Telefone *</label>
              <input
                type="tel"
                value={form.telefone}
                onChange={(e) => setForm(f => ({ ...f, telefone: e.target.value }))}
                className="w-full mt-1 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--panel-2)] text-[13px] focus:border-[var(--accent)] outline-none"
                placeholder="(00) 00000-0000"
              />
            </div>
            <div className="col-span-2">
              <label className="text-[10.5px] uppercase tracking-wider text-[var(--fg-muted)] font-semibold">E-mail *</label>
              <input
                type="email"
                value={form.email}
                onChange={(e) => setForm(f => ({ ...f, email: e.target.value }))}
                className="w-full mt-1 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--panel-2)] text-[13px] focus:border-[var(--accent)] outline-none"
                placeholder="voce@empresa.com"
              />
            </div>
            <div className="col-span-2">
              <label className="text-[10.5px] uppercase tracking-wider text-[var(--fg-muted)] font-semibold">Mensagem</label>
              <textarea
                value={form.mensagem}
                onChange={(e) => setForm(f => ({ ...f, mensagem: e.target.value }))}
                rows={3}
                className="w-full mt-1 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--panel-2)] text-[13px] focus:border-[var(--accent)] outline-none resize-none"
                placeholder="Quantas lojas? Qual ERP usa hoje? Algo específico?"
              />
            </div>
          </div>
          <div className="flex items-center justify-between gap-2 pt-2">
            <span className="text-[10.5px] text-[var(--fg-faint)]">Seus dados ficam protegidos. Retornamos em até 1 dia útil.</span>
            <Btn variant="primary" icon="send" iconRight onClick={handleSubmit}>Enviar contato</Btn>
          </div>
        </form>
      )}
    </Modal>
  );
}

Object.assign(window, { CONTACT, buildWhatsAppUrl, ContactDialog });
