/**
 * Currency utilities for formatting and calculations
 */

// Currency configuration
export const CURRENCY_CONFIG = {
  EUR: {
    code: 'EUR',
    symbol: '€',
    name: 'Euro',
    decimals: 2,
    locale: 'es-ES',
  },
  USD: {
    code: 'USD',
    symbol: '$',
    name: 'US Dollar',
    decimals: 2,
    locale: 'en-US',
  },
  GBP: {
    code: 'GBP',
    symbol: '£',
    name: 'British Pound',
    decimals: 2,
    locale: 'en-GB',
  },
} as const;

export type CurrencyCode = keyof typeof CURRENCY_CONFIG;

// Default currency for the application (Euro)
export const DEFAULT_CURRENCY: CurrencyCode = 'EUR';

// Get currency symbol
export const getCurrencySymbol = (currencyCode: CurrencyCode = DEFAULT_CURRENCY): string => {
  return CURRENCY_CONFIG[currencyCode]?.symbol || '€';
};

// Format currency amount
export const formatCurrency = (
  amount: number,
  currencyCode: CurrencyCode = 'EUR',
  options: Intl.NumberFormatOptions = {}
): string => {
  if (typeof amount !== 'number' || isNaN(amount)) {
    return formatCurrency(0, currencyCode, options);
  }

  const config = CURRENCY_CONFIG[currencyCode];
  
  const defaultOptions: Intl.NumberFormatOptions = {
    style: 'currency',
    currency: config.code,
    minimumFractionDigits: config.decimals,
    maximumFractionDigits: config.decimals,
  };

  const formatOptions = { ...defaultOptions, ...options };

  try {
    return new Intl.NumberFormat(config.locale, formatOptions).format(amount);
  } catch (error) {
    // Fallback to manual formatting if Intl.NumberFormat fails
    const formattedAmount = amount.toFixed(config.decimals);
    return `${formattedAmount} ${config.symbol}`;
  }
};

// Format currency without symbol (just the number)
export const formatCurrencyAmount = (
  amount: number,
  currencyCode: CurrencyCode = 'EUR',
  decimals?: number
): string => {
  if (typeof amount !== 'number' || isNaN(amount)) {
    return formatCurrencyAmount(0, currencyCode, decimals);
  }

  const config = CURRENCY_CONFIG[currencyCode];
  const decimalPlaces = decimals ?? config.decimals;

  try {
    return new Intl.NumberFormat(config.locale, {
      minimumFractionDigits: decimalPlaces,
      maximumFractionDigits: decimalPlaces,
    }).format(amount);
  } catch (error) {
    return amount.toFixed(decimalPlaces);
  }
};

// Parse currency string to number
export const parseCurrency = (
  currencyString: string,
  currencyCode: CurrencyCode = 'EUR'
): number => {
  if (!currencyString || typeof currencyString !== 'string') {
    return 0;
  }

  const config = CURRENCY_CONFIG[currencyCode];
  
  // Remove currency symbols and spaces
  const cleanString = currencyString
    .replace(new RegExp(`[${config.symbol}\\s]`, 'g'), '')
    .replace(/,/g, '.') // Replace comma with dot for decimal separator
    .trim();

  const parsed = parseFloat(cleanString);
  return isNaN(parsed) ? 0 : parsed;
};

// Add two currency amounts
export const addCurrency = (amount1: number, amount2: number): number => {
  if (typeof amount1 !== 'number' || typeof amount2 !== 'number') {
    return 0;
  }

  // Use proper decimal arithmetic to avoid floating point errors
  return Math.round((amount1 + amount2) * 100) / 100;
};

// Subtract two currency amounts
export const subtractCurrency = (amount1: number, amount2: number): number => {
  if (typeof amount1 !== 'number' || typeof amount2 !== 'number') {
    return 0;
  }

  return Math.round((amount1 - amount2) * 100) / 100;
};

// Multiply currency amount
export const multiplyCurrency = (amount: number, multiplier: number): number => {
  if (typeof amount !== 'number' || typeof multiplier !== 'number') {
    return 0;
  }

  return Math.round(amount * multiplier * 100) / 100;
};

// Divide currency amount
export const divideCurrency = (amount: number, divisor: number): number => {
  if (typeof amount !== 'number' || typeof divisor !== 'number' || divisor === 0) {
    return 0;
  }

  return Math.round((amount / divisor) * 100) / 100;
};

// Calculate percentage of amount
export const calculatePercentage = (amount: number, percentage: number): number => {
  if (typeof amount !== 'number' || typeof percentage !== 'number') {
    return 0;
  }

  return multiplyCurrency(amount, percentage / 100);
};

// Add percentage to amount
export const addPercentage = (amount: number, percentage: number): number => {
  const percentageAmount = calculatePercentage(amount, percentage);
  return addCurrency(amount, percentageAmount);
};

// Subtract percentage from amount
export const subtractPercentage = (amount: number, percentage: number): number => {
  const percentageAmount = calculatePercentage(amount, percentage);
  return subtractCurrency(amount, percentageAmount);
};

// Calculate tax amount
export const calculateTax = (amount: number, taxRate: number): number => {
  return calculatePercentage(amount, taxRate);
};

// Calculate amount before tax (gross to net)
export const calculateNetAmount = (grossAmount: number, taxRate: number): number => {
  if (typeof grossAmount !== 'number' || typeof taxRate !== 'number') {
    return 0;
  }

  return divideCurrency(grossAmount, 1 + (taxRate / 100));
};

// Calculate amount with tax (net to gross)
export const calculateGrossAmount = (netAmount: number, taxRate: number): number => {
  if (typeof netAmount !== 'number' || typeof taxRate !== 'number') {
    return 0;
  }

  return multiplyCurrency(netAmount, 1 + (taxRate / 100));
};

// Calculate discount amount
export const calculateDiscount = (amount: number, discountRate: number): number => {
  return calculatePercentage(amount, discountRate);
};

// Apply discount to amount
export const applyDiscount = (amount: number, discountRate: number): number => {
  const discountAmount = calculateDiscount(amount, discountRate);
  return subtractCurrency(amount, discountAmount);
};

// Calculate profit margin
export const calculateProfitMargin = (revenue: number, cost: number): number => {
  if (typeof revenue !== 'number' || typeof cost !== 'number' || revenue === 0) {
    return 0;
  }

  const profit = subtractCurrency(revenue, cost);
  return Math.round((profit / revenue) * 10000) / 100; // Return as percentage with 2 decimal places
};

// Calculate markup
export const calculateMarkup = (cost: number, markupPercentage: number): number => {
  return addPercentage(cost, markupPercentage);
};

// Calculate selling price from cost and desired margin
export const calculateSellingPrice = (cost: number, marginPercentage: number): number => {
  if (typeof cost !== 'number' || typeof marginPercentage !== 'number' || marginPercentage >= 100) {
    return cost;
  }

  return divideCurrency(cost, 1 - (marginPercentage / 100));
};

// Calculate cost from selling price and margin
export const calculateCostFromMargin = (sellingPrice: number, marginPercentage: number): number => {
  if (typeof sellingPrice !== 'number' || typeof marginPercentage !== 'number') {
    return 0;
  }

  return multiplyCurrency(sellingPrice, 1 - (marginPercentage / 100));
};

// Format currency range (e.g., "€10 - €20")
export const formatCurrencyRange = (
  minAmount: number,
  maxAmount: number,
  currencyCode: CurrencyCode = 'EUR'
): string => {
  if (typeof minAmount !== 'number' || typeof maxAmount !== 'number') {
    return formatCurrency(0, currencyCode);
  }

  if (minAmount === maxAmount) {
    return formatCurrency(minAmount, currencyCode);
  }

  const formattedMin = formatCurrency(minAmount, currencyCode);
  const formattedMax = formatCurrency(maxAmount, currencyCode);
  
  return `${formattedMin} - ${formattedMax}`;
};

// Round currency to nearest cent
export const roundCurrency = (amount: number): number => {
  if (typeof amount !== 'number') {
    return 0;
  }

  return Math.round(amount * 100) / 100;
};

// Check if amount is valid currency value
export const isValidCurrencyAmount = (amount: any): boolean => {
  return typeof amount === 'number' && !isNaN(amount) && isFinite(amount) && amount >= 0;
};

// Convert between currencies (simplified - in real app, use exchange rates API)
export const convertCurrency = (
  amount: number,
  fromCurrency: CurrencyCode,
  toCurrency: CurrencyCode,
  exchangeRate: number = 1
): number => {
  if (!isValidCurrencyAmount(amount) || typeof exchangeRate !== 'number') {
    return 0;
  }

  if (fromCurrency === toCurrency) {
    return amount;
  }

  return multiplyCurrency(amount, exchangeRate);
};

// Format currency for input fields (without currency symbol)
export const formatCurrencyInput = (amount: number | string): string => {
  if (typeof amount === 'string') {
    const parsed = parseCurrency(amount);
    return parsed === 0 && amount !== '0' ? amount : formatCurrencyAmount(parsed);
  }

  if (typeof amount === 'number' && !isNaN(amount)) {
    return formatCurrencyAmount(amount);
  }

  return '';
};

// Calculate total from array of amounts
export const calculateTotal = (amounts: number[]): number => {
  if (!Array.isArray(amounts)) {
    return 0;
  }

  return amounts.reduce((total, amount) => {
    if (isValidCurrencyAmount(amount)) {
      return addCurrency(total, amount);
    }
    return total;
  }, 0);
};

// Calculate average from array of amounts
export const calculateAverage = (amounts: number[]): number => {
  if (!Array.isArray(amounts) || amounts.length === 0) {
    return 0;
  }

  const validAmounts = amounts.filter(isValidCurrencyAmount);
  if (validAmounts.length === 0) {
    return 0;
  }

  const total = calculateTotal(validAmounts);
  return divideCurrency(total, validAmounts.length);
};

// Find minimum amount in array
export const findMinimumAmount = (amounts: number[]): number => {
  if (!Array.isArray(amounts) || amounts.length === 0) {
    return 0;
  }

  const validAmounts = amounts.filter(isValidCurrencyAmount);
  return validAmounts.length > 0 ? Math.min(...validAmounts) : 0;
};

// Find maximum amount in array
export const findMaximumAmount = (amounts: number[]): number => {
  if (!Array.isArray(amounts) || amounts.length === 0) {
    return 0;
  }

  const validAmounts = amounts.filter(isValidCurrencyAmount);
  return validAmounts.length > 0 ? Math.max(...validAmounts) : 0;
};

// Format compact currency (e.g., €1.2K, €1.5M)
export const formatCompactCurrency = (
  amount: number,
  currencyCode: CurrencyCode = 'EUR'
): string => {
  if (!isValidCurrencyAmount(amount)) {
    return formatCurrency(0, currencyCode);
  }

  const config = CURRENCY_CONFIG[currencyCode];

  try {
    return new Intl.NumberFormat(config.locale, {
      style: 'currency',
      currency: config.code,
      notation: 'compact',
      compactDisplay: 'short',
      maximumFractionDigits: 1,
    }).format(amount);
  } catch (error) {
    // Fallback for browsers that don't support compact notation
    if (amount >= 1000000) {
      return `${config.symbol}${(amount / 1000000).toFixed(1)}M`;
    } else if (amount >= 1000) {
      return `${config.symbol}${(amount / 1000).toFixed(1)}K`;
    } else {
      return formatCurrency(amount, currencyCode);
    }
  }
};

// Calculate compound interest
export const calculateCompoundInterest = (
  principal: number,
  rate: number,
  time: number,
  compound: number = 1
): number => {
  if (!isValidCurrencyAmount(principal) || typeof rate !== 'number' || typeof time !== 'number') {
    return principal;
  }

  const amount = principal * Math.pow(1 + (rate / 100) / compound, compound * time);
  return roundCurrency(amount);
};

// Currency formatting options for different contexts
export const getCurrencyFormatOptions = (context: 'display' | 'input' | 'compact' | 'accounting') => {
  const baseOptions = {
    style: 'currency' as const,
    currency: 'EUR' as const,
  };

  switch (context) {
    case 'display':
      return {
        ...baseOptions,
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      };
    
    case 'input':
      return {
        ...baseOptions,
        minimumFractionDigits: 0,
        maximumFractionDigits: 2,
      };
    
    case 'compact':
      return {
        ...baseOptions,
        notation: 'compact' as const,
        compactDisplay: 'short' as const,
        maximumFractionDigits: 1,
      };
    
    case 'accounting':
      return {
        ...baseOptions,
        currencySign: 'accounting' as const,
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      };
    
    default:
      return baseOptions;
  }
};