// Shared primitives for the dashboard. Plain JSX (Babel). Exports to window.
const { useState, useEffect, useRef } = React;

/* ---------- formatting ---------- */
function money(n, opts) {
  const o = opts || {};
  return (n).toLocaleString("en-US", {
    minimumFractionDigits: o.dp == null ? 2 : o.dp,
    maximumFractionDigits: o.dp == null ? 2 : o.dp,
  });
}
function compact(n) {
  if (n >= 1000) return "$" + (n / 1000).toLocaleString("en-US", { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + "k";
  return "$" + money(n, { dp: 0 });
}

/* ---------- icons (16/24 line, currentColor) ---------- */
const ICONS = {
  users:    '<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
  wallet:   '<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/><path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/><path d="M18 12a2 2 0 0 0 0 4h4v-4Z"/>',
  flag:     '<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/>',
  coins:    '<circle cx="8" cy="8" r="6"/><path d="M18.09 10.37A6 6 0 1 1 10.34 18"/><path d="M7 6h1v4"/><path d="m16.71 13.88.7.71-2.82 2.82"/>',
  trophy:   '<path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2Z"/>',
  ticket:   '<path d="M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z"/><path d="M13 5v2"/><path d="M13 17v2"/><path d="M13 11v2"/>',
  clock:    '<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>',
  copy:     '<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>',
  external: '<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>',
  check:    '<polyline points="20 6 9 17 4 12"/>',
  medal:    '<path d="M7.21 15 2.66 7.14a2 2 0 0 1 .13-2.2L4.4 2.8A2 2 0 0 1 6 2h12a2 2 0 0 1 1.6.8l1.6 2.14a2 2 0 0 1 .14 2.2L16.79 15"/><path d="M11 12 5.12 2.2"/><path d="m13 12 5.88-9.8"/><path d="M8 7h8"/><circle cx="12" cy="17" r="5"/><path d="M12 18v-2h-.5"/>',
  spark:    '<path d="M12 2v6"/><path d="M12 16v6"/><path d="m4.93 4.93 4.24 4.24"/><path d="m14.83 14.83 4.24 4.24"/><path d="M2 12h6"/><path d="M16 12h6"/><path d="m4.93 19.07 4.24-4.24"/><path d="m14.83 9.17 4.24-4.24"/>',
};
function Icon(props) {
  const s = props.size || 16;
  return (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none"
      stroke={props.color || "currentColor"} strokeWidth={props.strokeWidth || 1.6}
      strokeLinecap="round" strokeLinejoin="round" style={{ flex: "0 0 auto", display: "block" }}
      dangerouslySetInnerHTML={{ __html: ICONS[props.name] || "" }} />
  );
}

/* ---------- live dot ---------- */
function LiveDot() {
  return (
    <span style={{ position: "relative", width: 8, height: 8, display: "inline-block" }}>
      <span style={{ position: "absolute", inset: 0, borderRadius: "50%", background: "var(--ll-neon)",
        boxShadow: "0 0 0 0 rgba(195,255,0,0.6)", animation: "ll-ping 1.6s var(--ease-out) infinite" }} />
      <span style={{ position: "absolute", inset: 0, borderRadius: "50%", background: "var(--ll-neon)" }} />
    </span>
  );
}

/* ---------- countdown to a target ISO date ---------- */
function useCountdown(targetISO) {
  const target = new Date(targetISO).getTime();
  const [now, setNow] = useState(Date.now());
  useEffect(() => {
    const id = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(id);
  }, []);
  let diff = Math.max(0, target - now);
  const d = Math.floor(diff / 86400000); diff -= d * 86400000;
  const h = Math.floor(diff / 3600000);  diff -= h * 3600000;
  const m = Math.floor(diff / 60000);    diff -= m * 60000;
  const s = Math.floor(diff / 1000);
  return { d, h, m, s, done: target - now <= 0 };
}

/* ---------- copy-to-clipboard wrapper ---------- */
function Copyable(props) {
  const [hit, setHit] = useState(false);
  function go() {
    try { navigator.clipboard.writeText(props.text); } catch (e) {}
    setHit(true); setTimeout(() => setHit(false), 1100);
  }
  return (
    <button onClick={go} title="Copy" style={{
      border: 0, background: "transparent", cursor: "pointer", color: hit ? "var(--ll-neon)" : "var(--fg-tertiary)",
      display: "inline-flex", alignItems: "center", padding: 4, borderRadius: 6, transition: "color var(--t-fast)",
    }}>
      <Icon name={hit ? "check" : "copy"} size={14} />
    </button>
  );
}

/* ---------- relative "last updated" ---------- */
function fmtUpdated(iso) {
  const d = new Date(iso);
  return d.toLocaleString("en-US", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", timeZone: "UTC" }) + " UTC";
}

Object.assign(window, { money, compact, Icon, LiveDot, useCountdown, Copyable, fmtUpdated });
