// theclaudetrader — utilities & formatters

const fmtUSD = (n, opts = {}) => {
  if (n === null || n === undefined || Number.isNaN(n)) return "—";
  const abs = Math.abs(n);
  const { compact = false, decimals } = opts;
  if (compact && abs >= 1000) {
    if (abs >= 1e9) return `$${(n / 1e9).toFixed(2)}B`;
    if (abs >= 1e6) return `$${(n / 1e6).toFixed(2)}M`;
    if (abs >= 1e3) return `$${(n / 1e3).toFixed(1)}K`;
  }
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD",
    minimumFractionDigits: decimals ?? 2,
    maximumFractionDigits: decimals ?? 2,
  }).format(n);
};

const fmtPct = (n, opts = {}) => {
  if (n === null || n === undefined || Number.isNaN(n)) return "—";
  const { decimals = 2, signed = true } = opts;
  const sign = signed && n > 0 ? "+" : "";
  return `${sign}${(n * 100).toFixed(decimals)}%`;
};

const fmtNum = (n, decimals = 2) => {
  if (n === null || n === undefined || Number.isNaN(n)) return "—";
  return new Intl.NumberFormat("en-US", {
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  }).format(n);
};

const fmtDate = (iso, opts = {}) => {
  if (!iso) return "—";
  const d = new Date(iso);
  const { style = "medium" } = opts;
  if (style === "short") {
    return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
  }
  if (style === "long") {
    return d.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
  }
  return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
};

const fmtTime = (iso) => {
  if (!iso) return "—";
  const d = new Date(iso);
  const now = new Date();
  const diffMin = (now - d) / 60000;
  if (diffMin < 1) return "just now";
  if (diffMin < 60) return `${Math.round(diffMin)}m ago`;
  if (diffMin < 60 * 24) return `${Math.round(diffMin / 60)}h ago`;
  const diffDays = Math.round(diffMin / 60 / 24);
  if (diffDays < 7) return `${diffDays}d ago`;
  return fmtDate(iso, { style: "short" });
};

const fmtDateTime = (iso) => {
  if (!iso) return "—";
  const d = new Date(iso);
  return `${d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })} · ${d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", hour12: true })} UTC`;
};

// classNames helper
const cx = (...args) => args.filter(Boolean).join(" ");

// Animated counter hook — smooth count-up on mount & value change
const useCountUp = (target, duration = 1200) => {
  const [value, setValue] = React.useState(0);
  const fromRef = React.useRef(0);
  const startRef = React.useRef(0);
  React.useEffect(() => {
    fromRef.current = value;
    startRef.current = performance.now();
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - startRef.current) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      const v = fromRef.current + (target - fromRef.current) * eased;
      setValue(v);
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [target]);
  return value;
};

// expose
Object.assign(window, { fmtUSD, fmtPct, fmtNum, fmtDate, fmtTime, fmtDateTime, cx, useCountUp });
