/**
 * Number Formatting Utilities
 * Provides locale-aware number, currency, and measurement formatting
 * Fixes floating point precision issues
 */

export interface FormatNumberOptions {
  minimumFractionDigits?: number;
  maximumFractionDigits?: number;
  useGrouping?: boolean;
}

export interface FormatCurrencyOptions extends FormatNumberOptions {
  currency?: string;
  currencyDisplay?: 'symbol' | 'code' | 'name';
}

export interface FormatWeightOptions extends FormatNumberOptions {
  unit?: 'kg' | 'g' | 'lb' | 'oz';
}

/**
 * Round number to specified decimal places to avoid floating point errors
 */
export function roundToPrecision(value: number, decimals: number = 2): number {
  const multiplier = Math.pow(10, decimals);
  return Math.round(value * multiplier) / multiplier;
}

/**
 * Format number with locale-specific formatting
 */
export function formatNumber(
  value: number | string,
  locale: string = 'es-ES',
  options: FormatNumberOptions = {}
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return '0';
  }

  // Round to avoid floating point errors
  const rounded = roundToPrecision(numValue, options.maximumFractionDigits ?? 2);

  const defaultOptions: Intl.NumberFormatOptions = {
    minimumFractionDigits: options.minimumFractionDigits ?? 0,
    maximumFractionDigits: options.maximumFractionDigits ?? 2,
    useGrouping: options.useGrouping ?? true,
  };

  return new Intl.NumberFormat(locale, defaultOptions).format(rounded);
}

/**
 * Format currency with locale-specific formatting
 */
export function formatCurrency(
  value: number | string,
  locale: string = 'es-ES',
  options: FormatCurrencyOptions = {}
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return '€0,00';
  }

  // Round to avoid floating point errors
  const rounded = roundToPrecision(numValue, options.maximumFractionDigits ?? 2);

  const defaultOptions: Intl.NumberFormatOptions = {
    style: 'currency',
    currency: options.currency ?? 'EUR',
    currencyDisplay: options.currencyDisplay ?? 'symbol',
    minimumFractionDigits: options.minimumFractionDigits ?? 2,
    maximumFractionDigits: options.maximumFractionDigits ?? 2,
  };

  return new Intl.NumberFormat(locale, defaultOptions).format(rounded);
}

/**
 * Format weight/mass with unit
 */
export function formatWeight(
  value: number | string,
  locale: string = 'es-ES',
  options: FormatWeightOptions = {}
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return '0 kg';
  }

  const unit = options.unit ?? 'kg';
  // Round to avoid floating point errors
  const rounded = roundToPrecision(numValue, options.maximumFractionDigits ?? 2);

  const formatted = formatNumber(rounded, locale, {
    minimumFractionDigits: options.minimumFractionDigits ?? 0,
    maximumFractionDigits: options.maximumFractionDigits ?? 2,
    useGrouping: options.useGrouping ?? true,
  });

  return `${formatted} ${unit}`;
}

/**
 * Format volume with unit
 */
export function formatVolume(
  value: number | string,
  locale: string = 'es-ES',
  unit: 'L' | 'mL' | 'gal' = 'L',
  decimals: number = 2
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return `0 ${unit}`;
  }

  const rounded = roundToPrecision(numValue, decimals);
  const formatted = formatNumber(rounded, locale, {
    maximumFractionDigits: decimals,
  });

  return `${formatted} ${unit}`;
}

/**
 * Format percentage
 */
export function formatPercentage(
  value: number | string,
  locale: string = 'es-ES',
  decimals: number = 1
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return '0%';
  }

  const rounded = roundToPrecision(numValue, decimals);
  const formatted = formatNumber(rounded, locale, {
    minimumFractionDigits: 0,
    maximumFractionDigits: decimals,
  });

  return `${formatted}%`;
}

/**
 * Format compact number (1K, 1M, etc.)
 */
export function formatCompactNumber(
  value: number | string,
  locale: string = 'es-ES'
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return '0';
  }

  const rounded = roundToPrecision(numValue, 1);

  return new Intl.NumberFormat(locale, {
    notation: 'compact',
    maximumFractionDigits: 1,
  }).format(rounded);
}

/**
 * Format integer (no decimals)
 */
export function formatInteger(
  value: number | string,
  locale: string = 'es-ES'
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return '0';
  }

  return new Intl.NumberFormat(locale, {
    minimumFractionDigits: 0,
    maximumFractionDigits: 0,
  }).format(Math.round(numValue));
}

/**
 * Parse localized number string to number
 */
export function parseLocalizedNumber(
  value: string,
  locale: string = 'es-ES'
): number {
  // Get locale-specific decimal and group separators
  const parts = new Intl.NumberFormat(locale).formatToParts(1234.5);
  const decimalSeparator = parts.find(p => p.type === 'decimal')?.value ?? ',';
  const groupSeparator = parts.find(p => p.type === 'group')?.value ?? '.';

  // Remove group separators and replace decimal separator with dot
  const normalized = value
    .replace(new RegExp(`\\${groupSeparator}`, 'g'), '')
    .replace(decimalSeparator, '.');

  return parseFloat(normalized);
}

/**
 * Format unit of measure with value
 */
export function formatMeasurement(
  value: number | string,
  unit: string,
  locale: string = 'es-ES',
  decimals: number = 2
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return `0 ${unit}`;
  }

  const rounded = roundToPrecision(numValue, decimals);
  const formatted = formatNumber(rounded, locale, {
    minimumFractionDigits: 0,
    maximumFractionDigits: decimals,
  });

  return `${formatted} ${unit}`;
}

/**
 * Safe division to avoid floating point errors
 */
export function safeDivide(
  numerator: number,
  denominator: number,
  decimals: number = 2
): number {
  if (denominator === 0) {
    return 0;
  }
  return roundToPrecision(numerator / denominator, decimals);
}

/**
 * Safe multiplication to avoid floating point errors
 */
export function safeMultiply(
  a: number,
  b: number,
  decimals: number = 2
): number {
  return roundToPrecision(a * b, decimals);
}

/**
 * Safe addition to avoid floating point errors
 */
export function safeAdd(
  ...values: number[]
): number {
  const sum = values.reduce((acc, val) => acc + val, 0);
  return roundToPrecision(sum, 2);
}

/**
 * Format quantity with appropriate unit of measure
 * Handles common bakery units
 */
export function formatQuantity(
  value: number | string,
  unit: string,
  locale: string = 'es-ES'
): string {
  const numValue = typeof value === 'string' ? parseFloat(value) : value;

  if (isNaN(numValue)) {
    return `0 ${unit}`;
  }

  // Determine decimals based on unit
  let decimals = 2;
  if (unit.toLowerCase() === 'unidades' || unit.toLowerCase() === 'units') {
    decimals = 0;
  } else if (['kg', 'l', 'lb'].includes(unit.toLowerCase())) {
    decimals = 2;
  }

  const rounded = roundToPrecision(numValue, decimals);
  const formatted = formatNumber(rounded, locale, {
    minimumFractionDigits: 0,
    maximumFractionDigits: decimals,
  });

  return `${formatted} ${unit}`;
}
