File size: 2,834 Bytes
4a285d2
 
 
 
 
ef85da9
4a285d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import axios from 'axios';

export class ExchangeRateService {
  private cachedRate: number | null = null;
  private cacheExpiry: Date | null = null;
  private readonly CACHE_DURATION_MS = 60 * 60 * 1000;
  private readonly FALLBACK_RATE: number;

  constructor() {
    this.FALLBACK_RATE = parseFloat(process.env.NGN_PER_USD || '750');
  }

  async getNGNToUSDRate(): Promise<number> {
    if (this.cachedRate && this.cacheExpiry && new Date() < this.cacheExpiry) {
      console.log('Using cached exchange rate:', this.cachedRate);
      return this.cachedRate;
    }

    try {
      const rate = await this.fetchExchangeRate();
      this.cachedRate = rate;
      this.cacheExpiry = new Date(Date.now() + this.CACHE_DURATION_MS);
      console.log('Fetched new exchange rate:', rate);
      return rate;
    } catch (error) {
      console.error('Failed to fetch exchange rate, using fallback:', error);
      return this.FALLBACK_RATE;
    }
  }

  private async fetchExchangeRate(): Promise<number> {
    try {
      const response = await axios.get('https://api.exchangerate-api.com/v4/latest/USD', {
        timeout: 5000,
      });
      const rate = response.data.rates?.NGN;
      if (rate && rate > 0) {
        return rate;
      }
    } catch (error) {
      console.warn('ExchangeRate-API failed, trying alternative...');
    }

    // Option 2: CurrencyAPI (requires free API key, but more reliable)
    const currencyApiKey = process.env.CURRENCY_API_KEY;
    if (currencyApiKey) {
      try {
        const response = await axios.get(
          `https://api.currencyapi.com/v3/latest?apikey=${currencyApiKey}&currencies=NGN&base_currency=USD`,
          { timeout: 5000 }
        );
        const rate = response.data.data?.NGN?.value;
        if (rate && rate > 0) {
          return rate;
        }
      } catch (error) {
        console.warn('CurrencyAPI failed, trying alternative...');
      }
    }

    // Option 3: Fixer.io (requires API key)
    const fixerApiKey = process.env.FIXER_API_KEY;
    if (fixerApiKey) {
      try {
        const response = await axios.get(
          `https://api.fixer.io/latest?access_key=${fixerApiKey}&base=USD&symbols=NGN`,
          { timeout: 5000 }
        );
        const rate = response.data.rates?.NGN;
        if (rate && rate > 0) {
          return rate;
        }
      } catch (error) {
        console.warn('Fixer.io failed, using fallback...');
      }
    }

    // If all APIs fail, throw error to use fallback
    throw new Error('All exchange rate APIs failed');
  }

  /**
   * Get the fallback rate (from env or default)
   */
  getFallbackRate(): number {
    return this.FALLBACK_RATE;
  }

  /**
   * Clear the cache (useful for testing or manual refresh)
   */
  clearCache(): void {
    this.cachedRate = null;
    this.cacheExpiry = null;
  }
}