/**
 * Exchange Rate Provider Interface
 *
 * All exchange rate providers must implement this interface.
 * Rates are expressed as "USD per token" (e.g., 1 ABT = 0.1 USD means rate = 0.1)
 */

export interface IExchangeRateProvider {
  readonly name: string;

  /**
   * Fetch the current exchange rate for a given token symbol
   * @param symbol - Token symbol (e.g., 'ABT', 'ETH')
   * @returns Exchange rate data
   * @throws Error if fetching fails or data is invalid
   */
  fetch(symbol: string): Promise<ExchangeRateData>;
}

export interface ExchangeRateData {
  /**
   * Exchange rate in USD per token
   * Example: 1 ABT = 0.1 USD => rate = "0.1"
   */
  rate: string;

  /**
   * Timestamp of the rate in milliseconds
   */
  timestamp_ms: number;

  /**
   * Optional metadata
   */
  metadata?: Record<string, any>;
}

export interface ExchangeRateResult extends ExchangeRateData {
  /**
   * Consensus method used to compute the final rate
   */
  consensus_method?: string;

  /**
   * Provider snapshots participating in consensus
   */
  providers?: ExchangeRateProviderSnapshot[];

  /**
   * Provider ID from database
   */
  provider_id: string;

  /**
   * Provider name
   */
  provider_name: string;

  /**
   * Human-readable provider display string
   * - Single source: "CoinGecko"
   * - Multiple sources: "CoinGecko (2 sources)"
   */
  provider_display?: string;

  /**
   * Whether the rate is from a degraded provider
   */
  degraded: boolean;

  /**
   * Reason for degradation (if degraded)
   */
  degraded_reason?: string;

  /**
   * Timestamp when we fetched the data (milliseconds)
   * Different from timestamp_ms which is the provider's data timestamp
   */
  fetched_at?: number;
}

export interface ExchangeRateProviderSnapshot {
  provider_id: string;
  provider_name: string;
  rate: string;
  timestamp_ms: number;
  degraded: boolean;
  degraded_reason?: string;
}

export interface ProviderConfig {
  base_url?: string;
  api_key?: string;
  timeout?: number;
  [key: string]: any;
}

/**
 * Error thrown when a symbol is not supported by the provider
 * This error should NOT be recorded as a provider failure
 * because it's a data issue, not a service issue
 */
export class SymbolNotSupportedError extends Error {
  public readonly symbol: string;
  public readonly provider: string;

  constructor(symbol: string, provider: string, message?: string) {
    super(message || `Symbol ${symbol} is not supported by ${provider}`);
    this.name = 'SymbolNotSupportedError';
    this.symbol = symbol;
    this.provider = provider;
  }
}
