import { promises as fs } from 'fs';
import { join } from 'path';

// Currency symbol mapping from ISO codes to display symbols
const CURRENCY_SYMBOLS: Record<string, string> = {
  // Major World Currencies
  USD: '$',
  EUR: '€',
  GBP: '£',
  JPY: '¥',
  CHF: 'Fr',
  CAD: 'C$',
  AUD: 'A$',
  CNY: '¥',
  
  // European Currencies
  SEK: 'kr',        // Swedish Krona
  NOK: 'kr',        // Norwegian Krone
  DKK: 'kr',        // Danish Krone
  ISK: 'kr',        // Icelandic Krona
  PLN: 'zł',        // Polish Złoty
  CZK: 'Kč',        // Czech Koruna
  HUF: 'Ft',        // Hungarian Forint
  RON: 'lei',       // Romanian Leu
  BGN: 'лв',        // Bulgarian Lev
  HRK: 'kn',        // Croatian Kuna
  RUB: '₽',         // Russian Ruble
  TRY: '₺',         // Turkish Lira
  ALL: 'L',         // Albanian Lek
  BAM: 'KM',        // Bosnia and Herzegovina Convertible Mark
  MKD: 'ден',       // Macedonian Denar
  RSD: 'дин',       // Serbian Dinar
  MDL: 'L',         // Moldovan Leu
  UAH: '₴',         // Ukrainian Hryvnia
  BYN: 'Br',        // Belarusian Ruble
  GEL: '₾',         // Georgian Lari
  AMD: '֏',         // Armenian Dram
  AZN: '₼',         // Azerbaijani Manat
  
  // Caribbean Currencies
  XCD: 'EC$',       // Eastern Caribbean Dollar (Antigua, Dominica, Grenada, etc.)
  BBD: 'Bds$',      // Barbados Dollar
  BSD: 'B$',        // Bahamian Dollar
  BZD: 'BZ$',       // Belize Dollar
  JMD: 'J$',        // Jamaican Dollar
  KYD: 'CI$',       // Cayman Islands Dollar
  TTD: 'TT$',       // Trinidad and Tobago Dollar
  CUP: '₱',         // Cuban Peso
  CUC: 'CUC$',      // Cuban Convertible Peso
  DOP: 'RD$',       // Dominican Peso
  HTG: 'G',         // Haitian Gourde
  AWG: 'ƒ',         // Aruban Florin
  ANG: 'ƒ',         // Netherlands Antillean Guilder
  SRD: '$',         // Suriname Dollar
  GYD: 'G$',        // Guyana Dollar
  
  // Central America & Panama
  PAB: 'B/.',       // Panamanian Balboa
  GTQ: 'Q',         // Guatemalan Quetzal
  HNL: 'L',         // Honduran Lempira
  NIO: 'C$',        // Nicaraguan Córdoba
  CRC: '₡',         // Costa Rican Colón
  
  // North America
  MXN: '$',         // Mexican Peso
  
  // South America
  BRL: 'R$',        // Brazilian Real
  ARS: '$',         // Argentine Peso
  CLP: '$',         // Chilean Peso
  COP: '$',         // Colombian Peso
  PEN: 'S/',        // Peruvian Sol
  UYU: '$U',        // Uruguayan Peso
  PYG: '₲',         // Paraguayan Guaraní
  BOB: 'Bs.',       // Bolivian Boliviano
  VES: 'Bs.S',      // Venezuelan Bolívar Soberano
  
  // Asia
  INR: '₹',         // Indian Rupee
  KRW: '₩',         // South Korean Won
  SGD: 'S$',        // Singapore Dollar
  HKD: 'HK$',       // Hong Kong Dollar
  TWD: 'NT$',       // Taiwan Dollar
  THB: '฿',         // Thai Baht
  MYR: 'RM',        // Malaysian Ringgit
  PHP: '₱',         // Philippine Peso
  IDR: 'Rp',        // Indonesian Rupiah
  VND: '₫',         // Vietnamese Dong
  LAK: '₭',         // Lao Kip
  KHR: '៛',         // Cambodian Riel
  MMK: 'K',         // Myanmar Kyat
  
  // Middle East & Africa
  ZAR: 'R',         // South African Rand
  EGP: '£',         // Egyptian Pound
  NGN: '₦',         // Nigerian Naira
  KES: 'KSh',       // Kenyan Shilling
  GHS: '₵',         // Ghanaian Cedi
  MAD: 'د.م.',      // Moroccan Dirham
  TND: 'د.ت',       // Tunisian Dinar
  DZD: 'د.ج',       // Algerian Dinar
  AED: 'د.إ',       // UAE Dirham
  SAR: '﷼',         // Saudi Riyal
  QAR: '﷼',         // Qatari Riyal
  KWD: 'د.ك',       // Kuwaiti Dinar
  BHD: '.د.ب',      // Bahraini Dinar
  OMR: '﷼',         // Omani Rial
  JOD: 'د.ا',       // Jordanian Dinar
  LBP: '£',         // Lebanese Pound
  ILS: '₪',         // Israeli Shekel
  
  // Oceania
  NZD: 'NZ$',       // New Zealand Dollar
  FJD: 'FJ$',       // Fijian Dollar
  TOP: 'T$',        // Tongan Paʻanga
  WST: 'WS$',       // Samoan Tala
  VUV: 'Vt',        // Vanuatu Vatu
  SBD: 'SI$',       // Solomon Islands Dollar
  PGK: 'K',         // Papua New Guinea Kina
  
  // Additional European Dependencies
  GIP: '£',         // Gibraltar Pound
  FKP: '£',         // Falkland Islands Pound
  SHP: '£',         // Saint Helena Pound
  JEP: '£',         // Jersey Pound
  GGP: '£',         // Guernsey Pound
  IMP: '£',         // Isle of Man Pound
};

// Exchange rate cache interface
interface ExchangeRateCache {
  rates: Record<string, number>;
  lastUpdated: string;
  baseCurrency: string;
}

// Cache file path
const CACHE_FILE_PATH = join(process.cwd(), '.cache', 'exchange-rates.json');

// Cache TTL: 1 hour in milliseconds
const CACHE_TTL = 60 * 60 * 1000;

/**
 * Get currency symbol from ISO code
 */
export const getCurrencySymbol = (currencyCode: string): string => {
  return CURRENCY_SYMBOLS[currencyCode.toUpperCase()] || currencyCode;
};

/**
 * Ensure cache directory exists
 */
const ensureCacheDirectory = async (): Promise<void> => {
  try {
    const cacheDir = join(process.cwd(), '.cache');
    await fs.mkdir(cacheDir, { recursive: true });
  } catch (error) {
    console.error('[currency] Failed to create cache directory:', error);
  }
};

/**
 * Load exchange rates from cache
 */
const loadCachedRates = async (): Promise<ExchangeRateCache | null> => {
  try {
    const cacheData = await fs.readFile(CACHE_FILE_PATH, 'utf8');
    const cache: ExchangeRateCache = JSON.parse(cacheData);
    
    // Check if cache is still valid (within TTL)
    const lastUpdated = new Date(cache.lastUpdated).getTime();
    const now = Date.now();
    
    if (now - lastUpdated < CACHE_TTL) {
      console.log('[currency] Using cached exchange rates');
      return cache;
    } else {
      console.log('[currency] Cache expired, need to fetch new rates');
      return null;
    }
  } catch (error) {
    console.log('[currency] No valid cache found, will fetch new rates');
    return null;
  }
};

/**
 * Save exchange rates to cache
 */
const saveCachedRates = async (cache: ExchangeRateCache): Promise<void> => {
  try {
    await ensureCacheDirectory();
    await fs.writeFile(CACHE_FILE_PATH, JSON.stringify(cache, null, 2), 'utf8');
    console.log('[currency] Exchange rates cached successfully');
  } catch (error) {
    console.error('[currency] Failed to save cache:', error);
  }
};

/**
 * Fetch exchange rates from Frankfurter API
 */
const fetchExchangeRates = async (): Promise<ExchangeRateCache | null> => {
  try {
    console.log('[currency] Fetching exchange rates from Frankfurter API...');
    
    // Fetch rates with USD as base currency for consistency
    const response = await fetch('https://api.frankfurter.app/latest?from=USD');
    
    if (!response.ok) {
      throw new Error(`Frankfurter API responded with status: ${response.status}`);
    }
    
    const data = await response.json();
    
    // Frankfurter response format: { amount: 1, base: "USD", date: "2025-06-27", rates: { EUR: 0.956, ... } }
    const cache: ExchangeRateCache = {
      rates: {
        USD: 1.0, // Base currency
        ...data.rates
      },
      lastUpdated: new Date().toISOString(),
      baseCurrency: 'USD'
    };
    
    await saveCachedRates(cache);
    console.log('[currency] Successfully fetched and cached exchange rates');
    
    return cache;
  } catch (error) {
    console.error('[currency] Failed to fetch exchange rates:', error);
    return null;
  }
};

/**
 * Get current exchange rates (cached or fresh)
 */
export const getExchangeRates = async (): Promise<ExchangeRateCache | null> => {
  // Try to load from cache first
  let cache = await loadCachedRates();
  
  // If no valid cache, fetch fresh rates
  if (!cache) {
    cache = await fetchExchangeRates();
  }
  
  return cache;
};

/**
 * Convert amount from one currency to USD
 */
export const convertToUSD = async (amount: number, fromCurrency: string): Promise<{
  usdAmount: number;
  rate: number;
  conversionDate: string;
} | null> => {
  // If already USD, no conversion needed
  if (fromCurrency.toUpperCase() === 'USD') {
    return {
      usdAmount: amount,
      rate: 1.0,
      conversionDate: new Date().toISOString()
    };
  }
  
  try {
    const rateCache = await getExchangeRates();
    
    if (!rateCache) {
      console.error('[currency] No exchange rates available for conversion');
      return null;
    }
    
    const fromCurrencyUpper = fromCurrency.toUpperCase();
    
    // Get rate from source currency to USD
    // Since our cache has USD as base, we need to convert FROM the source currency TO USD
    // If USD -> EUR rate is 0.956, then EUR -> USD rate is 1/0.956
    const usdToSourceRate = rateCache.rates[fromCurrencyUpper];
    
    if (!usdToSourceRate) {
      console.error(`[currency] Currency ${fromCurrencyUpper} not supported`);
      return null;
    }
    
    // Calculate USD amount
    // If USD -> EUR = 0.956, then EUR -> USD = 1/0.956 = 1.046
    const sourceToUsdRate = 1 / usdToSourceRate;
    const usdAmount = amount * sourceToUsdRate;
    
    console.log(`[currency] Converted ${amount} ${fromCurrencyUpper} to ${usdAmount.toFixed(2)} USD (rate: ${sourceToUsdRate.toFixed(4)})`);
    
    return {
      usdAmount: parseFloat(usdAmount.toFixed(2)),
      rate: parseFloat(sourceToUsdRate.toFixed(4)),
      conversionDate: rateCache.lastUpdated
    };
  } catch (error) {
    console.error('[currency] Error during currency conversion:', error);
    return null;
  }
};

/**
 * Format price with currency symbol
 */
export const formatPriceWithCurrency = (amount: number, currencyCode: string): string => {
  const symbol = getCurrencySymbol(currencyCode);
  const formattedAmount = amount.toFixed(2);
  
  // For most currencies, symbol goes before the amount
  // Special cases where symbol goes after can be added here if needed
  return `${symbol}${formattedAmount}`;
};

/**
 * Create display price string (original + USD if not USD)
 */
export const createDisplayPrice = (
  originalAmount: number,
  originalCurrency: string,
  usdAmount?: number
): string => {
  const originalFormatted = formatPriceWithCurrency(originalAmount, originalCurrency);
  
  // If original currency is USD or no USD conversion available, just show original
  if (originalCurrency.toUpperCase() === 'USD' || !usdAmount) {
    return originalFormatted;
  }
  
  const usdFormatted = formatPriceWithCurrency(usdAmount, 'USD');
  return `${originalFormatted} (${usdFormatted})`;
};

/**
 * Manually refresh exchange rates (for API endpoint)
 */
export const refreshExchangeRates = async (): Promise<{
  success: boolean;
  message: string;
  ratesCount?: number;
}> => {
  try {
    console.log('[currency] Manual refresh of exchange rates requested');
    
    const cache = await fetchExchangeRates();
    
    if (cache) {
      return {
        success: true,
        message: 'Exchange rates refreshed successfully',
        ratesCount: Object.keys(cache.rates).length
      };
    } else {
      return {
        success: false,
        message: 'Failed to fetch exchange rates from API'
      };
    }
  } catch (error) {
    console.error('[currency] Error during manual refresh:', error);
    return {
      success: false,
      message: 'Error occurred during refresh'
    };
  }
};

/**
 * Get cache status information
 */
export const getCacheStatus = async (): Promise<{
  cached: boolean;
  lastUpdated?: string;
  ratesCount?: number;
  minutesUntilExpiry?: number;
  minutesSinceUpdate?: number;
}> => {
  try {
    const cache = await loadCachedRates();
    
    if (!cache) {
      return { cached: false };
    }
    
    const lastUpdated = new Date(cache.lastUpdated).getTime();
    const now = Date.now();
    const minutesUntilExpiry = Math.max(0, Math.floor((CACHE_TTL - (now - lastUpdated)) / (60 * 1000)));
    const minutesSinceUpdate = Math.floor((now - lastUpdated) / (60 * 1000));
    
    return {
      cached: true,
      lastUpdated: cache.lastUpdated,
      ratesCount: Object.keys(cache.rates).length,
      minutesUntilExpiry,
      minutesSinceUpdate
    };
  } catch (error) {
    console.error('[currency] Error checking cache status:', error);
    return { cached: false };
  }
};

/**
 * Enhanced expense processing with currency conversion
 */
export const processExpenseWithCurrency = async (expense: any): Promise<any> => {
  const processedExpense = { ...expense };
  
  // Parse price number
  const priceNumber = parseFloat(expense.Price?.toString().replace(/[^\d.-]/g, '')) || 0;
  processedExpense.PriceNumber = priceNumber;
  
  // Get currency symbol
  const currencyCode = expense.currency || 'USD';
  processedExpense.CurrencySymbol = getCurrencySymbol(currencyCode);
  
  // Convert to USD if not already USD
  if (currencyCode.toUpperCase() !== 'USD') {
    const conversion = await convertToUSD(priceNumber, currencyCode);
    
    if (conversion) {
      processedExpense.PriceUSD = conversion.usdAmount;
      processedExpense.ConversionRate = conversion.rate;
      processedExpense.ConversionDate = conversion.conversionDate;
    }
  } else {
    // If already USD, set USD amount to original amount
    processedExpense.PriceUSD = priceNumber;
    processedExpense.ConversionRate = 1.0;
    processedExpense.ConversionDate = new Date().toISOString();
  }
  
  // Create display prices
  processedExpense.DisplayPrice = createDisplayPrice(
    priceNumber,
    currencyCode,
    processedExpense.PriceUSD
  );
  
  processedExpense.DisplayPriceUSD = formatPriceWithCurrency(
    processedExpense.PriceUSD || priceNumber,
    'USD'
  );
  
  return processedExpense;
};
