/**
 * Exchange registry - select best FxPriceProvider per pair with fallback
 */

import type { FxPriceProvider } from '@/core/fx/price-provider.interface';
import { BinancePriceAdapter } from './binance';
import { KrakenPriceAdapter } from './kraken';
import { OandaPriceAdapter } from './oanda';
import { FxcmPriceAdapter } from './fxcm';

export type ExchangeProviderId = 'binance' | 'kraken' | 'oanda' | 'fxcm';

export interface ExchangeRegistryConfig {
  /** Optional OTC price provider (e.g. from Crypto.com OTC) - highest priority when set */
  otcProvider?: FxPriceProvider;
}

export class ExchangeRegistryService {
  private providers: Array<{ id: ExchangeProviderId | 'otc'; adapter: FxPriceProvider }> = [];
  private initialized = false;

  async initialize(config?: ExchangeRegistryConfig): Promise<void> {
    if (this.initialized) return;

    if (config?.otcProvider) {
      this.providers.push({ id: 'otc', adapter: config.otcProvider });
    }

    const binance = new BinancePriceAdapter();
    this.providers.push({ id: 'binance', adapter: binance });

    const kraken = new KrakenPriceAdapter();
    this.providers.push({ id: 'kraken', adapter: kraken });

    const oandaKey = process.env.OANDA_API_KEY;
    const oandaAccount = process.env.OANDA_ACCOUNT_ID;
    if (oandaKey && oandaAccount) {
      const oanda = new OandaPriceAdapter({
        apiKey: oandaKey,
        accountId: oandaAccount,
        environment: (process.env.OANDA_ENVIRONMENT as 'practice' | 'live') ?? 'practice',
      });
      this.providers.push({ id: 'oanda', adapter: oanda });
    }

    const fxcmToken = process.env.FXCM_API_TOKEN;
    if (fxcmToken) {
      const fxcm = new FxcmPriceAdapter({ token: fxcmToken });
      this.providers.push({ id: 'fxcm', adapter: fxcm });
    }

    this.initialized = true;
  }

  async getPrice(pair: string, amount?: number): Promise<string | null> {
    if (!this.initialized) await this.initialize();

    for (const { adapter } of this.providers) {
      if (adapter.isPairSupported?.(pair) !== false) {
        const price = await Promise.resolve(adapter.getPrice(pair, amount));
        if (price) return price;
      }
    }
    return null;
  }

  getProvider(pair?: string): FxPriceProvider | null {
    if (!this.providers.length) return null;
    for (const { adapter } of this.providers) {
      if (!pair || adapter.isPairSupported?.(pair) !== false) {
        return adapter;
      }
    }
    return this.providers[0]?.adapter ?? null;
  }

  listProviders(): (ExchangeProviderId | 'otc')[] {
    return this.providers.map((p) => p.id);
  }
}

export const exchangeRegistryService = new ExchangeRegistryService();
