const usd = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  maximumFractionDigits: 0,
});

const usdPrecise = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

const number = new Intl.NumberFormat("en-US");

const date = new Intl.DateTimeFormat("en-US", {
  month: "short",
  day: "numeric",
  year: "numeric",
});

const dateShort = new Intl.DateTimeFormat("en-US", {
  month: "short",
  day: "numeric",
});

const time = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "2-digit",
});

const relative = new Intl.RelativeTimeFormat("en-US", { numeric: "auto" });

/**
 * Coerce a backend Decimal-serialized value (string) or a number to a finite
 * number. Returns the supplied fallback (default 0) on null/undefined/NaN.
 * Used everywhere the FastAPI `Decimal` field needs to flow into a UI that
 * expects `number`.
 */
export const toNum = (v: string | number | null | undefined, fallback = 0): number => {
  if (v === null || v === undefined) return fallback;
  const n = typeof v === "number" ? v : Number(v);
  return Number.isFinite(n) ? n : fallback;
};

export const fmt = {
  usd: (n: number) => usd.format(n),
  usdPrecise: (n: number) => usdPrecise.format(n),
  usdDecimal: (v: string | number | null | undefined) =>
    usdPrecise.format(toNum(v)),
  num: (n: number) => number.format(n),
  date: (iso: string) => date.format(new Date(iso)),
  dateShort: (iso: string) => dateShort.format(new Date(iso)),
  time: (iso: string) => time.format(new Date(iso)),
  pct: (n: number, digits = 1) => `${n.toFixed(digits)}%`,
  relative: (iso: string) => {
    const ms = new Date(iso).getTime() - Date.now();
    const minutes = Math.round(ms / 60_000);
    if (Math.abs(minutes) < 60) return relative.format(minutes, "minute");
    const hours = Math.round(minutes / 60);
    if (Math.abs(hours) < 24) return relative.format(hours, "hour");
    const days = Math.round(hours / 24);
    if (Math.abs(days) < 7) return relative.format(days, "day");
    return fmt.date(iso);
  },
};
