export function formatFileSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

export function formatDateTime(dateString: string | null, fallback = 'N/A'): string {
  if (!dateString) return fallback;
  return new Date(dateString).toLocaleString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
  });
}

export function formatDateOnly(dateString: string | null, fallback = 'N/A'): string {
  if (!dateString) return fallback;
  return new Date(dateString).toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric',
  });
}

export function formatRelativeTime(dateString: string | null): string {
  if (!dateString) return 'Never';
  const date = new Date(dateString);
  const now = new Date();
  const diffMs = now.getTime() - date.getTime();
  const diffMins = Math.floor(diffMs / 60000);
  if (diffMins < 1) return 'just now';
  if (diffMins < 60) return `${diffMins}m ago`;
  const diffHours = Math.floor(diffMins / 60);
  if (diffHours < 24) return `${diffHours}h ago`;
  const diffDays = Math.floor(diffHours / 24);
  if (diffDays < 30) return `${diffDays}d ago`;
  return formatDateOnly(dateString);
}

/** @deprecated Use formatDateTime or formatDateOnly instead */
export function formatDate(dateString: string | null, fallback = 'N/A'): string {
  return formatDateTime(dateString, fallback);
}

export function formatCurrency(value: number, locale = 'en-US', currency = 'USD'): string {
  return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value);
}

export function capitalize(str: string): string {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

const PROVIDER_NAMES: Record<string, string> = {
  github: 'GitHub',
  google: 'Google',
  stripe: 'Stripe',
};

export function formatProviderName(provider: string): string {
  return PROVIDER_NAMES[provider.toLowerCase()] ?? capitalize(provider);
}

/**
 * Format a number with thousands separators.
 * @param value - The number to format
 * @returns Formatted number with commas (e.g., "1,234"), or "—" for NaN/Infinity
 */
export function formatNumber(value: number): string {
  if (!Number.isFinite(value)) return '—';
  return new Intl.NumberFormat('en-US').format(value);
}

/**
 * Format a number in short format (e.g., 1.2K, 3.4M, 5.6B).
 * @param value - The number to format
 * @param decimals - Number of decimal places (default: 1)
 * @returns Short formatted number (e.g., "1.2K", "3.4M")
 */
export function formatNumberShort(value: number, decimals = 1): string {
  if (value >= 1e9) {
    return `${(value / 1e9).toFixed(decimals)}B`;
  }
  if (value >= 1e6) {
    return `${(value / 1e6).toFixed(decimals)}M`;
  }
  if (value >= 1e3) {
    return `${(value / 1e3).toFixed(decimals)}K`;
  }
  return formatNumber(value);
}

/**
 * Format a ratio as percentage (multiplies by 100).
 * @param value - The ratio (0-1 range, e.g., 0.455)
 * @param decimals - Number of decimal places (default: 1)
 * @returns Formatted percentage (e.g., "45.5%"), or "—" for NaN/Infinity
 */
export function formatPercent(value: number, decimals = 1): string {
  if (!Number.isFinite(value)) return '—';
  return `${(value * 100).toFixed(decimals)}%`;
}

/**
 * Format a pre-computed percentage value (does NOT multiply by 100).
 * Use when the value is already a percentage (e.g., CTR of 5.2).
 * @param value - The percentage value (e.g., 5.2)
 * @param decimals - Number of decimal places (default: 1)
 * @returns Formatted percentage (e.g., "5.2%"), or "—" for NaN/Infinity
 */
export function formatPercentRaw(value: number, decimals = 1): string {
  if (!Number.isFinite(value)) return '—';
  return `${value.toFixed(decimals)}%`;
}

/**
 * Format a decimal number with fixed precision.
 * @param value - The number to format
 * @param decimals - Number of decimal places (default: 2)
 * @returns Formatted decimal (e.g., "3.14"), or "—" for NaN/Infinity
 */
export function formatDecimal(value: number, decimals = 2): string {
  if (!Number.isFinite(value)) return '—';
  return new Intl.NumberFormat('en-US', {
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  }).format(value);
}

/**
 * Truncates a URL to a readable path, limiting total length.
 * Intentionally strips the domain and hash fragment — only pathname + search
 * are returned, since GSC/traffic alert URLs don't carry meaningful fragments
 * and the full href is always available via the link's href attribute.
 * @param url - Full URL or path string
 * @param maxLen - Maximum character length (default 50)
 */
export function truncateUrl(url: string, maxLen = 50): string {
  try {
    const parsed = new URL(url);
    const path = parsed.pathname + parsed.search;
    return path.length > maxLen ? path.slice(0, maxLen) + '…' : path;
  } catch {
    return url.length > maxLen ? url.slice(0, maxLen) + '…' : url;
  }
}
