/**
 * Exchange Rate Service
 *
 * Fetches live exchange rates from fawazahmed0/exchange-api
 * with Redis caching (1-hour TTL) and fallback to hardcoded rates.
 *
 * @server-only - Uses Redis caching and fetch
 */
import 'server-only';
import { cache } from '@/lib/cache';
import { logger } from '@/lib/logger';
import type { Currency } from '@/lib/types/pricing';

// Cache configuration
const EXCHANGE_RATE_CACHE_KEY = 'exchange_rates:gbp';
const EXCHANGE_RATE_CACHE_TTL = 3600; // 1 hour

// API endpoints (primary + fallback)
const PRIMARY_API_URL = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/gbp.json';
const FALLBACK_API_URL = 'https://latest.currency-api.pages.dev/v1/currencies/gbp.json';

// Fallback rates (from current CurrencyManager.EXCHANGE_RATES)
// These are used if both API endpoints fail
const FALLBACK_RATES: Record<string, number> = {
  gbp: 1,
  usd: 1.27,
  eur: 1.17,
  sar: 4.76,
  aed: 4.66,
  qar: 4.62,
  kwd: 0.39,
  bhd: 0.48,
  omr: 0.49,
};

// Type for API response
interface ExchangeRateAPIResponse {
  date: string;
  gbp: Record<string, number>;
}

// Type for our normalized rates
export interface ExchangeRates {
  date: string;
  baseCurrency: 'GBP';
  rates: Record<string, number>;
  source: 'api' | 'cache' | 'fallback';
  fetchedAt: string;
}

/**
 * Fetch exchange rates from the API
 * Tries primary URL first, then fallback
 */
async function fetchFromAPI(): Promise<ExchangeRateAPIResponse | null> {
  const urls = [PRIMARY_API_URL, FALLBACK_API_URL];

  for (const url of urls) {
    try {
      const response = await fetch(url, {
        next: { revalidate: 3600 }, // Next.js ISR: revalidate every hour
      });

      if (!response.ok) {
        logger.warn(`Exchange rate API returned ${response.status}`, { url });
        continue;
      }

      const data = await response.json() as ExchangeRateAPIResponse;

      // Validate response structure
      if (!data.gbp || typeof data.gbp !== 'object') {
        logger.warn('Invalid exchange rate API response structure', { url });
        continue;
      }

      logger.info('Successfully fetched exchange rates', {
        url,
        date: data.date,
        currencyCount: Object.keys(data.gbp).length
      });

      return data;
    } catch (error) {
      logger.warn('Failed to fetch from exchange rate API', {
        url,
        error: error instanceof Error ? error.message : 'Unknown error'
      });
    }
  }

  return null;
}

/**
 * Get exchange rates with caching
 * Priority: Cache > API > Fallback
 */
export async function getExchangeRates(): Promise<ExchangeRates> {
  return cache.getOrSet<ExchangeRates>(
    EXCHANGE_RATE_CACHE_KEY,
    async () => {
      // Try to fetch from API
      const apiResponse = await fetchFromAPI();

      if (apiResponse) {
        // Extract only the currencies we support
        const supportedCurrencies = ['gbp', 'usd', 'eur', 'sar', 'aed', 'qar', 'kwd', 'bhd', 'omr'];
        const rates: Record<string, number> = {};

        for (const currency of supportedCurrencies) {
          const rate = apiResponse.gbp[currency];
          if (typeof rate === 'number' && !isNaN(rate)) {
            rates[currency] = rate;
          } else {
            // Use fallback for this specific currency if not in API response
            rates[currency] = FALLBACK_RATES[currency] || 1;
          }
        }

        return {
          date: apiResponse.date,
          baseCurrency: 'GBP',
          rates,
          source: 'api',
          fetchedAt: new Date().toISOString(),
        };
      }

      // API failed, use fallback rates
      logger.warn('Using fallback exchange rates - API unavailable');

      return {
        date: new Date().toISOString().split('T')[0],
        baseCurrency: 'GBP',
        rates: { ...FALLBACK_RATES },
        source: 'fallback',
        fetchedAt: new Date().toISOString(),
      };
    },
    EXCHANGE_RATE_CACHE_TTL
  );
}

/**
 * Get exchange rate for a specific currency pair
 */
export async function getExchangeRate(
  from: Currency,
  to: Currency
): Promise<number> {
  if (from === to) return 1;

  const rates = await getExchangeRates();
  const fromLower = from.toLowerCase();
  const toLower = to.toLowerCase();

  // If converting from GBP
  if (fromLower === 'gbp') {
    return rates.rates[toLower] || 1;
  }

  // If converting to GBP
  if (toLower === 'gbp') {
    const fromRate = rates.rates[fromLower];
    return fromRate ? 1 / fromRate : 1;
  }

  // Cross-rate conversion (e.g., USD to QAR)
  // First convert to GBP, then to target currency
  const fromRate = rates.rates[fromLower];
  const toRate = rates.rates[toLower];

  if (!fromRate || !toRate) {
    logger.warn('Missing exchange rate for conversion', { from, to });
    return 1;
  }

  return toRate / fromRate;
}

/**
 * Convert an amount from one currency to another
 * Rounds to 2 decimal places
 */
export async function convertCurrency(
  amount: number,
  from: Currency,
  to: Currency
): Promise<number> {
  if (from === to) return amount;

  const rate = await getExchangeRate(from, to);
  const converted = amount * rate;

  // Round to 2 decimal places
  return Math.round(converted * 100) / 100;
}

/**
 * Convert GBP amount to target currency
 * Convenience function for the common case
 */
export async function convertFromGBP(
  amountGBP: number,
  targetCurrency: Currency
): Promise<number> {
  return convertCurrency(amountGBP, 'GBP', targetCurrency);
}

/**
 * Get formatted price with currency symbol
 */
export async function getFormattedPrice(
  amountGBP: number,
  targetCurrency: Currency
): Promise<{ amount: number; formatted: string; symbol: string }> {
  const symbols: Record<Currency, string> = {
    GBP: '£',
    USD: '$',
    EUR: '€',
    SAR: 'ر.س',
    AED: 'د.إ',
    QAR: 'ر.ق',
    KWD: 'د.ك',
    BHD: 'د.ب',
    OMR: 'ر.ع',
  };

  const amount = await convertFromGBP(amountGBP, targetCurrency);
  const symbol = symbols[targetCurrency] || targetCurrency;

  // Format based on currency (RTL currencies show symbol after amount)
  const rtlCurrencies: Currency[] = ['SAR', 'AED', 'QAR', 'KWD', 'BHD', 'OMR'];
  const isRTL = rtlCurrencies.includes(targetCurrency);

  const formatted = isRTL
    ? `${amount.toLocaleString()} ${symbol}`
    : `${symbol}${amount.toLocaleString()}`;

  return { amount, formatted, symbol };
}

/**
 * Invalidate cached exchange rates
 * Call this if you need to force a refresh
 */
export async function invalidateExchangeRateCache(): Promise<void> {
  await cache.del(EXCHANGE_RATE_CACHE_KEY);
  logger.info('Exchange rate cache invalidated');
}

/**
 * Get exchange rate service status (for health checks)
 */
export async function getExchangeRateStatus(): Promise<{
  healthy: boolean;
  source: 'api' | 'cache' | 'fallback';
  lastUpdate: string;
  rateCount: number;
}> {
  const rates = await getExchangeRates();

  return {
    healthy: rates.source !== 'fallback',
    source: rates.source,
    lastUpdate: rates.fetchedAt,
    rateCount: Object.keys(rates.rates).length,
  };
}
