import { ExchangeRate } from "../data/entities.js";
class ExchangeRateService {
  constructor(em, rateFetchingService) {
    this.em = em;
    this.rateFetchingService = rateFetchingService;
  }
  /**
   * Get exchange rates for a currency pair on a specific date
   * Returns all rates from different providers (exact matches only)
   * If not found, fetches from providers and tries previous days recursively
   * 
   * Note: maxDaysBack means the service will check the requested date plus up to
   * maxDaysBack previous days (total checks = maxDaysBack + 1)
   */
  async getRate(params) {
    const { fromCurrencyCode, toCurrencyCode, date, scope, options } = params;
    const maxDaysBack = options?.maxDaysBack ?? 30;
    const autoFetch = options?.autoFetch ?? true;
    this.validateDate(date);
    const fromCode = fromCurrencyCode.toUpperCase().trim();
    const toCode = toCurrencyCode.toUpperCase().trim();
    if (fromCode === toCode) {
      throw new Error("Cannot get exchange rate for the same currency");
    }
    const result = await this.findRateWithFallback(
      fromCode,
      toCode,
      date,
      scope,
      maxDaysBack,
      autoFetch
    );
    return result;
  }
  /**
   * Get multiple exchange rates at once (batch operation)
   * Errors are captured in the result's error field rather than thrown
   */
  async getRates(params) {
    const { pairs, date, scope, options } = params;
    const results = /* @__PURE__ */ new Map();
    for (const pair of pairs) {
      const key = `${pair.fromCurrencyCode}/${pair.toCurrencyCode}`;
      try {
        const result = await this.getRate({
          fromCurrencyCode: pair.fromCurrencyCode,
          toCurrencyCode: pair.toCurrencyCode,
          date,
          scope,
          options
        });
        results.set(key, result);
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        results.set(key, {
          rates: [],
          fromCurrencyCode: pair.fromCurrencyCode,
          toCurrencyCode: pair.toCurrencyCode,
          requestedDate: date,
          actualDate: null,
          error
        });
      }
    }
    return results;
  }
  /**
   * Recursively find exchange rate, trying to fetch if not found
   * Goes back day by day up to maxDaysBack
   */
  async findRateWithFallback(fromCode, toCode, date, scope, maxDaysBack, autoFetch, daysBack = 0) {
    if (daysBack > maxDaysBack) {
      return {
        rates: [],
        fromCurrencyCode: fromCode,
        toCurrencyCode: toCode,
        requestedDate: date,
        actualDate: null
      };
    }
    const checkDate = this.subtractDays(date, daysBack);
    const normalizedDate = this.normalizeDate(checkDate);
    const existingRates = await this.findExactRates(
      fromCode,
      toCode,
      normalizedDate,
      scope
    );
    if (existingRates.length > 0) {
      return {
        rates: existingRates,
        fromCurrencyCode: fromCode,
        toCurrencyCode: toCode,
        requestedDate: date,
        actualDate: normalizedDate
      };
    }
    if (autoFetch) {
      const fetchResult = await this.rateFetchingService.fetchRatesForDate(
        normalizedDate,
        scope
      );
      if (fetchResult.totalFetched > 0) {
        const fetchedRates = await this.findExactRates(
          fromCode,
          toCode,
          normalizedDate,
          scope
        );
        if (fetchedRates.length > 0) {
          return {
            rates: fetchedRates,
            fromCurrencyCode: fromCode,
            toCurrencyCode: toCode,
            requestedDate: date,
            actualDate: normalizedDate
          };
        }
      }
    }
    return this.findRateWithFallback(
      fromCode,
      toCode,
      date,
      scope,
      maxDaysBack,
      autoFetch,
      daysBack + 1
    );
  }
  /**
   * Find exact matching rates in the database
   * Returns all rates from different providers for the same pair and date
   */
  async findExactRates(fromCode, toCode, date, scope) {
    const normalizedDate = this.normalizeDate(date);
    return this.em.find(ExchangeRate, {
      organizationId: scope.organizationId,
      tenantId: scope.tenantId,
      fromCurrencyCode: fromCode,
      toCurrencyCode: toCode,
      date: normalizedDate,
      deletedAt: null,
      isActive: true
    });
  }
  /**
   * Validate that the date is not in the future
   * Allows today, rejects tomorrow and beyond
   */
  validateDate(date) {
    const now = /* @__PURE__ */ new Date();
    const normalizedNow = new Date(now);
    normalizedNow.setUTCHours(0, 0, 0, 0);
    const normalizedDate = this.normalizeDate(date);
    if (normalizedDate > normalizedNow) {
      throw new Error("Cannot get exchange rate for a future date");
    }
  }
  /**
   * Normalize date to start of day in UTC
   * Exchange rates are typically stored as daily values
   */
  normalizeDate(date) {
    const normalized = new Date(date);
    normalized.setUTCHours(0, 0, 0, 0);
    return normalized;
  }
  /**
   * Subtract days from a date
   */
  subtractDays(date, days) {
    const result = new Date(date);
    result.setDate(result.getDate() - days);
    return result;
  }
}
export {
  ExchangeRateService
};
//# sourceMappingURL=exchangeRateService.js.map
