// ui.jsx — AFEX PAY shared UI primitives & charts
const { useState, useEffect, useRef, useMemo } = React;
const I = window.Icons;

/* ---------- formatting ---------- */
const BRL = (n, opts = {}) =>
  (n < 0 ? "-" : "") + "R$ " + Math.abs(n).toLocaleString("pt-BR", { minimumFractionDigits: opts.cents === false ? 0 : 2, maximumFractionDigits: 2 });
const NF = (n) => n.toLocaleString("pt-BR");
const PCT = (n, d = 1) => n.toLocaleString("pt-BR", { minimumFractionDigits: d, maximumFractionDigits: d }) + "%";
/* contract helpers: cents -> BRL, and Metric{value,unit,deltaPct} formatting */
const cBRL = (cents, opts = {}) => BRL((cents || 0) / 100, opts);
const fmtMetric = (m, opts = {}) => {
  if (!m) return "—";
  if (m.unit === "cents") return cBRL(m.value, opts);
  if (m.unit === "percent") return PCT(m.value, opts.d ?? 1);
  return NF(m.value);
};

/* tiny data-fetch hook for the mock API client */
function useApi(fn, deps = []) {
  const [state, setState] = React.useState({ loading: true, data: null });
  React.useEffect(() => {
    let on = true;
    setState(s => ({ ...s, loading: true }));
    Promise.resolve(fn()).then(d => { if (on) setState({ loading: false, data: d }); }).catch(() => { if (on) setState({ loading: false, data: null }); });
    return () => { on = false; };
  }, deps);
  return state;
}

/* ---------- AFEX triangular "A" mark ---------- */
function AfexMark({ size = 28, color = "#fff" }) {
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" fill="none" style={{ display: "block" }}>
      <g stroke={color} strokeWidth="11.5" strokeLinejoin="round" strokeLinecap="round">
        <path d="M50 21 L81 79 L19 79 Z" />
        <path d="M34 61 H66" />
      </g>
    </svg>
  );
}

/* ---------- Wordmark (theme-aware brand logo image) ---------- */
function Wordmark({ height = 28 }) {
  return (
    <span style={{ display: "inline-flex", alignItems: "center" }}>
      <img className="wm-for-dark" src="assets/afex-wordmark-light.png" alt="AFEX Pay" style={{ height, width: "auto", display: "block" }} />
      <img className="wm-for-light" src="assets/afex-wordmark-dark.png" alt="AFEX Pay" style={{ height, width: "auto", display: "none" }} />
    </span>
  );
}

/* ---------- Logo ---------- */
function Logo({ size = 30, text = true, sub = false, tile = true }) {
  return (
    <div className="row gap-11" style={{ alignItems: "center", gap: 11 }}>
      {tile ? (
        <img src="assets/afex-icon.png" alt="AFEX Pay" style={{
          width: size, height: size, borderRadius: size * 0.26,
          boxShadow: "0 4px 14px rgba(255,90,0,0.38)", flexShrink: 0, display: "block"
        }} />
      ) : <AfexMark size={size} color="var(--accent)" />}
      {text && (
        <div className="col" style={{ lineHeight: 1 }}>
          <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: size * 0.56, letterSpacing: "0.02em" }}>
            AFEX<span style={{ color: "var(--accent)", marginLeft: 1 }}>Pay</span>
          </div>
          {sub && <div style={{ fontSize: 10, color: "var(--ink-faint)", letterSpacing: "0.22em", marginTop: 4, textTransform: "uppercase" }}>Payments</div>}
        </div>
      )}
    </div>
  );
}

/* ---------- Avatar ---------- */
const AV_COLORS = ["#FF5A00", "#3B82F6", "#22C55E", "#8B5CF6", "#F59E0B", "#EC4899", "#06B6D4"];
function Avatar({ name = "?", size = 36, src }) {
  const initials = name.split(" ").filter(Boolean).slice(0, 2).map(s => s[0]).join("").toUpperCase();
  const color = AV_COLORS[(name.charCodeAt(0) + name.length) % AV_COLORS.length];
  return (
    <div className="avatar" style={{ width: size, height: size, fontSize: size * 0.4, background: `linear-gradient(150deg, ${color}cc, ${color})` }}>
      {initials}
    </div>
  );
}

/* ---------- Status / method ---------- */
const STATUS = {
  aprovada: ["badge-green", "Aprovada"], aprovado: ["badge-green", "Aprovado"], ativo: ["badge-green", "Ativo"],
  pago: ["badge-green", "Pago"], conectado: ["badge-green", "Conectado"], liberado: ["badge-green", "Liberado"],
  recusada: ["badge-red", "Recusada"], rejeitado: ["badge-red", "Rejeitado"], bloqueado: ["badge-red", "Bloqueado"],
  chargeback: ["badge-red", "Chargeback"], falhou: ["badge-red", "Falhou"],
  pendente: ["badge-amber", "Pendente"], "em análise": ["badge-amber", "Em análise"], analise: ["badge-amber", "Em análise"],
  processando: ["badge-blue", "Processando"], agendado: ["badge-blue", "Agendado"], "a liberar": ["badge-blue", "A liberar"],
  reembolsada: ["badge-violet", "Reembolsada"], estornada: ["badge-violet", "Estornada"],
  ajustes: ["badge-amber", "Necessita ajustes"], desconectado: ["badge-gray", "Desconectado"],
  // contract enums (EN)
  approved: ["badge-green", "Aprovada"], active: ["badge-green", "Ativo"],
  refused: ["badge-red", "Recusada"], blocked: ["badge-red", "Bloqueado"],
  refunded: ["badge-violet", "Reembolsada"], analyzing: ["badge-amber", "Em análise"],
  pending: ["badge-amber", "Pendente"],
};
function Status({ s }) {
  const [cls, label] = STATUS[(s || "").toLowerCase()] || ["badge-gray", s];
  return <span className={"badge " + cls}><span className="dot"></span>{label}</span>;
}
const METHOD = {
  pix: ["pix", "PIX", "var(--green)"], credito: ["card", "Crédito", "var(--blue)"], cartao: ["card", "Crédito", "var(--blue)"],
  debito: ["card", "Débito", "var(--violet)"], boleto: ["barcode", "Boleto", "var(--ink-soft)"],
  credit: ["card", "Crédito", "var(--blue)"], card: ["card", "Crédito", "var(--blue)"],
};
function Method({ m }) {
  const [icon, label, color] = METHOD[(m || "").toLowerCase()] || ["money", m, "var(--ink-soft)"];
  const Comp = I[icon] || I.money;
  return <span className="tag-method" style={{ color: "var(--ink)" }}><Comp size={16} style={{ color }} />{label}</span>;
}

/* ---------- KPI ---------- */
function KPI({ label, value, delta, icon, accent = "var(--ink-soft)", hint, sub }) {
  const Comp = icon ? I[icon] : null;
  return (
    <div className="card card-pad col gap-12" style={{ minWidth: 0 }}>
      <div className="row between">
        <span className="kpi-label">{label}</span>
        {Comp && <span style={{ color: accent, display: "flex" }}><Comp size={18} /></span>}
      </div>
      <div className="col gap-6">
        <div className="kpi-value">{value}</div>
        <div className="row gap-8" style={{ minHeight: 18 }}>
          {delta != null && (
            <span className={"delta " + (delta >= 0 ? "delta-up" : "delta-down")}>
              {delta >= 0 ? <I.arrowUp size={13} /> : <I.arrowDown size={13} />}{Math.abs(delta).toLocaleString("pt-BR", { minimumFractionDigits: 1, maximumFractionDigits: 1 })}%
            </span>
          )}
          {(hint || sub) && <span className="faint" style={{ fontSize: 12.5 }}>{hint || sub}</span>}
        </div>
      </div>
    </div>
  );
}

/* ---------- Charts ---------- */
function AreaChart({ data, color = "var(--accent)", height = 130, fill = true, grid = true }) {
  const w = 600, h = height, pad = 6;
  const max = Math.max(...data) * 1.12, min = Math.min(...data, 0);
  const range = max - min || 1;
  const pts = data.map((v, i) => [pad + (i / (data.length - 1)) * (w - pad * 2), h - pad - ((v - min) / range) * (h - pad * 2)]);
  const line = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const area = line + ` L${w - pad} ${h} L${pad} ${h} Z`;
  const id = "g" + Math.random().toString(36).slice(2, 7);
  return (
    <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ width: "100%", height, display: "block", overflow: "visible" }}>
      <defs>
        <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.28" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      {grid && [0.25, 0.5, 0.75].map(g => <line key={g} x1={pad} x2={w - pad} y1={h * g} y2={h * g} stroke="var(--line)" strokeWidth="1" />)}
      {fill && <path d={area} fill={`url(#${id})`} />}
      <path d={line} fill="none" stroke={color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="3.5" fill={color} />
    </svg>
  );
}

function Bars({ data, labels, color = "var(--accent)", height = 150, money = false }) {
  const max = Math.max(...data) * 1.1 || 1;
  return (
    <div className="row" style={{ alignItems: "flex-end", gap: 10, height, paddingTop: 8 }}>
      {data.map((v, i) => (
        <div key={i} className="col grow" style={{ alignItems: "center", gap: 8, height: "100%", justifyContent: "flex-end" }}>
          <div className="grow row" style={{ alignItems: "flex-end", width: "100%", justifyContent: "center" }}>
            <div title={money ? BRL(v) : NF(v)} style={{
              width: "62%", maxWidth: 30, height: `${(v / max) * 100}%`, minHeight: 4,
              background: i === data.length - 1 ? color : "var(--surface-3)",
              borderRadius: "6px 6px 3px 3px", transition: "height .5s cubic-bezier(.2,.7,.2,1)"
            }} />
          </div>
          {labels && <span className="faint" style={{ fontSize: 11 }}>{labels[i]}</span>}
        </div>
      ))}
    </div>
  );
}

function Donut({ segments, size = 132, thickness = 16, center }) {
  const total = segments.reduce((s, x) => s + x.value, 0) || 1;
  const r = (size - thickness) / 2, c = 2 * Math.PI * r;
  let off = 0;
  return (
    <div style={{ position: "relative", width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: "rotate(-90deg)" }}>
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--surface-3)" strokeWidth={thickness} />
        {segments.map((s, i) => {
          const len = (s.value / total) * c;
          const el = <circle key={i} cx={size / 2} cy={size / 2} r={r} fill="none" stroke={s.color} strokeWidth={thickness}
            strokeDasharray={`${len} ${c - len}`} strokeDashoffset={-off} strokeLinecap="round" />;
          off += len; return el;
        })}
      </svg>
      {center && <div style={{ position: "absolute", inset: 0, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>{center}</div>}
    </div>
  );
}

function Spark({ data, color = "var(--green)", w = 90, h = 30 }) {
  const max = Math.max(...data), min = Math.min(...data), range = max - min || 1;
  const pts = data.map((v, i) => `${(i / (data.length - 1)) * w},${h - ((v - min) / range) * h}`).join(" ");
  return <svg width={w} height={h} style={{ display: "block" }}><polyline points={pts} fill="none" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" /></svg>;
}

/* ---------- Toggle ---------- */
function Toggle({ on, onChange, size = 1 }) {
  return (
    <button onClick={() => onChange(!on)} style={{
      width: 44 * size, height: 26 * size, borderRadius: 999, border: "none", padding: 3 * size,
      background: on ? "var(--accent)" : "var(--surface-3)", transition: "background .2s", display: "flex",
      justifyContent: on ? "flex-end" : "flex-start", alignItems: "center"
    }}>
      <span style={{ width: 20 * size, height: 20 * size, borderRadius: "50%", background: "#fff", transition: "all .2s", boxShadow: "0 1px 3px rgba(0,0,0,.4)" }} />
    </button>
  );
}

/* ---------- Modal ---------- */
function Modal({ open, onClose, children, width = 480, title, sub }) {
  useEffect(() => {
    if (!open) return;
    const h = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, [open]);
  if (!open) return null;
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 200, background: "rgba(0,0,0,0.6)", backdropFilter: "blur(4px)", display: "flex", alignItems: "center", justifyContent: "center", padding: 24 }} className="fade-in">
      <div onClick={e => e.stopPropagation()} className="card" style={{ width, maxWidth: "100%", maxHeight: "90vh", overflow: "auto", boxShadow: "var(--shadow-lg)" }}>
        {title && (
          <div className="row between" style={{ padding: "20px 22px", borderBottom: "1px solid var(--line)" }}>
            <div className="col gap-4">
              <div className="section-title">{title}</div>
              {sub && <div className="faint" style={{ fontSize: 13 }}>{sub}</div>}
            </div>
            <button className="iconbtn" onClick={onClose}><I.x size={18} /></button>
          </div>
        )}
        {children}
      </div>
    </div>
  );
}

/* ---------- QR (deterministic pseudo-PIX) ---------- */
function QR({ size = 180, seed = "afex" }) {
  const n = 25;
  const cells = useMemo(() => {
    let h = 0; for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) >>> 0;
    const rnd = () => { h = (h * 1103515245 + 12345) & 0x7fffffff; return h / 0x7fffffff; };
    const g = [];
    for (let y = 0; y < n; y++) for (let x = 0; x < n; x++) {
      const finder = (x < 7 && y < 7) || (x >= n - 7 && y < 7) || (x < 7 && y >= n - 7);
      g.push({ x, y, on: finder ? false : rnd() > 0.5, finder });
    }
    return g;
  }, [seed]);
  const cs = size / n;
  return (
    <div style={{ width: size, height: size, background: "#fff", borderRadius: 12, padding: cs, position: "relative" }}>
      <svg width={size - cs * 2} height={size - cs * 2} viewBox={`0 0 ${n} ${n}`}>
        {cells.filter(c => c.on).map((c, i) => <rect key={i} x={c.x} y={c.y} width="1" height="1" rx="0.2" fill="#0A0A0A" />)}
        {[[0, 0], [n - 7, 0], [0, n - 7]].map(([fx, fy], i) => (
          <g key={i}>
            <rect x={fx} y={fy} width="7" height="7" rx="1.6" fill="none" stroke="#0A0A0A" strokeWidth="1" />
            <rect x={fx + 2} y={fy + 2} width="3" height="3" rx="0.8" fill="#0A0A0A" />
          </g>
        ))}
      </svg>
    </div>
  );
}

/* ---------- Empty / segmented ---------- */
function Segmented({ options, value, onChange }) {
  return (
    <div className="row" style={{ background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: "var(--r-sm)", padding: 3, gap: 2 }}>
      {options.map(o => {
        const v = typeof o === "string" ? o : o.value, l = typeof o === "string" ? o : o.label;
        return (
          <button key={v} onClick={() => onChange(v)} style={{
            height: 32, padding: "0 14px", borderRadius: 6, border: "none", fontSize: 13.5, fontWeight: 600,
            background: value === v ? "var(--surface-3)" : "transparent", color: value === v ? "var(--ink)" : "var(--ink-faint)", transition: "all .14s"
          }}>{l}</button>
        );
      })}
    </div>
  );
}

// Client-side CSV export from an array of flat objects. `;` separator + BOM so
// Excel pt-BR opens it cleanly. Triggers a download.
function exportCsv(name, rows) {
  if (!rows || !rows.length) { alert("Nada para exportar ainda."); return; }
  const cols = Object.keys(rows[0]);
  const esc = (v) => { const s = v == null ? "" : String(v); return /[",;\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s; };
  const csv = [cols.join(";"), ...rows.map(r => cols.map(c => esc(r[c])).join(";"))].join("\n");
  const blob = new Blob(["﻿" + csv], { type: "text/csv;charset=utf-8" });
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = name + "-" + new Date().toISOString().slice(0, 10) + ".csv";
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(() => URL.revokeObjectURL(a.href), 1000);
}

function PageHead({ title, sub, children }) {
  return (
    <div className="row between wrap gap-16" style={{ marginBottom: 24 }}>
      <div className="col gap-6">
        <h1 className="page-title">{title}</h1>
        {sub && <div className="muted" style={{ fontSize: 14.5 }}>{sub}</div>}
      </div>
      {children && <div className="row gap-10 wrap">{children}</div>}
    </div>
  );
}

Object.assign(window, { BRL, NF, PCT, cBRL, fmtMetric, useApi, Logo, Wordmark, AfexMark, Avatar, Status, Method, KPI, AreaChart, Bars, Donut, Spark, Toggle, Modal, QR, Segmented, PageHead, exportCsv });
