const KNOWN_WINDOWS: Record<number, string> = {
  3600: "1 hour",
  86400: "24 hours",
  604800: "7 days",
  2592000: "30 days",
};

const GOAL_STATUS_LABEL: Record<string, string> = {
  receiving_events: "Receiving events",
  no_matching_events: "No matching events",
  tracking_not_installed: "Tracking not installed",
  inactive: "Inactive",
};

const FUNNEL_STATE_LABEL: Record<string, string> = {
  inactive: "Inactive",
  no_tracking: "No tracking",
  no_entrants: "No entrants",
  none_completed: "None completed",
  partial: "Partial",
  all_completed: "All completed",
};

export function formatCount(value: number): string {
  return new Intl.NumberFormat("en-US").format(value);
}

export function formatNullableCount(value: number | null | undefined): string {
  if (value == null) return "Unavailable";
  return formatCount(value);
}

export function formatRate(value: number | null | undefined): string {
  if (value == null) return "Not available";
  return `${new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 }).format(value)}%`;
}

export function formatRange(range: string | undefined): string {
  if (range === "today") return "Today";
  if (range === "7d") return "Last 7 days";
  if (range === "30d") return "Last 30 days";
  return range ?? "";
}

export function formatTimestamp(value: string | null | undefined): string {
  if (!value) return "None";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return new Intl.DateTimeFormat(undefined, {
    dateStyle: "medium",
    timeStyle: "short",
  }).format(date);
}

export function formatDate(value: string): string {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return new Intl.DateTimeFormat(undefined, { dateStyle: "medium" }).format(date);
}

/** Short axis label. ISO days become "Oct 20". Other labels stay as returned. */
export function formatChartLabel(label: string): string {
  const day = /^(\d{4})-(\d{2})-(\d{2})$/.exec(label.trim());
  if (!day) {
    const hour = /^(\d{2}):(\d{2})\s*UTC$/i.exec(label.trim());
    return hour ? `${hour[1]}:${hour[2]}` : label;
  }
  const date = new Date(Date.UTC(Number(day[1]), Number(day[2]) - 1, Number(day[3])));
  return new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", timeZone: "UTC" }).format(date);
}

const SENSITIVE_QUERY = /token|invite|secret|password|nonce|signature|^key$|^code$|^sig$|^auth$|^pass$|^pwd$|api_key|autologin|auto_login|magic|redirect_to/;

function sensitiveQueryKey(key: string): boolean {
  const name = key.trim().toLowerCase().replace(/-/g, "_");
  return SENSITIVE_QUERY.test(name);
}

function secretQueryValue(value: string): boolean {
  return value.length >= 20 && /^[A-Za-z0-9._~+/=-]+$/.test(value);
}

function publicSegment(segment: string): string {
  let text = segment;
  try {
    text = decodeURIComponent(segment);
  } catch {
    text = segment;
  }
  if (text.length >= 24 && /^[A-Za-z0-9._~-]+$/.test(text)) return "…";
  return text;
}

/**
 * Path shown in a table. Query secrets and long token-like segments are removed.
 * The returned text is safe to put in a title attribute.
 */
export function displayPath(value: string): string {
  const raw = value.trim();
  if (!raw) return "";
  let pathname = raw;
  let query = "";
  if (/^https?:\/\//i.test(raw)) {
    try {
      const url = new URL(raw);
      pathname = url.pathname || "/";
      query = url.search.startsWith("?") ? url.search.slice(1) : "";
    } catch {
      pathname = raw.split(/[?#]/)[0] ?? raw;
    }
  } else {
    const hashless = raw.split("#")[0] ?? raw;
    const split = hashless.indexOf("?");
    pathname = split === -1 ? hashless : hashless.slice(0, split);
    query = split === -1 ? "" : hashless.slice(split + 1);
  }
  const text = pathname
    .split("/")
    .map((segment) => publicSegment(segment))
    .join("/");
  if (!query) return text || "/";
  const kept = new URLSearchParams();
  for (const [key, item] of new URLSearchParams(query)) {
    if (sensitiveQueryKey(key) || secretQueryValue(item)) continue;
    kept.append(key, item);
  }
  const rest = kept.toString();
  return rest ? `${text || "/"}?${rest}` : text || "/";
}

/** Display label for the conversion window already returned by the API. */
export function formatWindow(value: string | number | undefined): string | null {
  if (value == null || value === "") return null;
  if (typeof value === "string" && Number.isNaN(Number(value))) return value;
  const seconds = typeof value === "number" ? value : Number(value);
  return KNOWN_WINDOWS[seconds] ?? `${formatCount(seconds)} seconds`;
}

export function goalStatusLabel(status: string): string {
  return GOAL_STATUS_LABEL[status] ?? status;
}

export function funnelStateLabel(state: string | undefined): string | null {
  if (!state) return null;
  return FUNNEL_STATE_LABEL[state] ?? state;
}
