import { Inject, Injectable } from "@nestjs/common";

import { CbeExchangeProvider } from "./cbe.provider";
import { EXCHANGE_OPTIONS, ExchangeOptions } from "./exchange.options";
import { CurrencyCode } from "./exchange.types";

/**
 * Currency exchange service. Resolves the rate between any supported currency
 * pair and converts amounts, backed by a rate provider (currently CBE).
 *
 * Resolution order for `getRate(from, to)`:
 *  1. `from === to` → `1`.
 *  2. Provider supplies the pair directly (e.g. CBE → USD→ETB).
 *  3. Provider supplies the inverse → return `1 / inverse` (e.g. ETB→USD).
 *
 * Configure via {@link ExchangeModule.forRoot} / `forRootAsync`.
 */
@Injectable()
export class ExchangeService {
  private readonly provider: CbeExchangeProvider;

  constructor(@Inject(EXCHANGE_OPTIONS) options: ExchangeOptions) {
    this.provider = new CbeExchangeProvider(options);
  }

  /**
   * Returns the rate to convert 1 unit of `from` into `to`
   * (i.e. `amountInTo = amountInFrom * getRate(from, to)`).
   */
  async getRate(from: CurrencyCode, to: CurrencyCode): Promise<number> {
    if (from === to) {
      return 1;
    }

    const direct = await this.provider.getBaseRate({ from, to });
    if (direct !== null) {
      return direct;
    }

    const inverse = await this.provider.getBaseRate({ from: to, to: from });
    if (inverse !== null && inverse > 0) {
      return 1 / inverse;
    }

    throw new Error(
      `No exchange rate available for ${from}→${to} from provider ${this.provider.name}`,
    );
  }

  /** Converts `amount` from one currency to another using {@link getRate}. */
  async convert(
    amount: number,
    from: CurrencyCode,
    to: CurrencyCode,
  ): Promise<number> {
    const rate = await this.getRate(from, to);
    return amount * rate;
  }

  /**
   * Convenience alias for `getRate('USD', 'ETB')`.
   * @deprecated Prefer {@link getRate}; kept for existing callers.
   */
  getUsdToEtbRate(): Promise<number> {
    return this.getRate("USD", "ETB");
  }

  /** Convenience alias for `getRate('ETB', 'USD')`. */
  getEtbToUsdRate(): Promise<number> {
    return this.getRate("ETB", "USD");
  }
}
