import { CarrierApi } from './carrier-types';
import { TwilioCarrier } from './twilio-carrier';
import { PlivoCarrier } from './plivo-carrier';

export type CarrierType = 'twilio' | 'plivo' | 'sip';

export interface CarrierFactoryConfig {
  twilio?: {
    apiKey: string;
    apiSecret: string;
    accountSid: string;
    apiBaseUrl?: string;
    decisionTimeout?: number;
  };
  plivo?: {
    authId: string;
    authToken: string;
    apiBaseUrl?: string;
    decisionTimeout?: number;
  };
  defaultDecisionTimeout?: number;
}

export class CarrierFactory {
  private readonly config: CarrierFactoryConfig;
  private readonly carriers: Map<CarrierType, CarrierApi> = new Map();

  constructor(config: CarrierFactoryConfig) {
    this.config = {
      defaultDecisionTimeout: 200,
      ...config,
    };
  }

  createCarrier(type: CarrierType): CarrierApi {
    const cached = this.carriers.get(type);
    if (cached) {
      return cached;
    }

    const carrier = this.instantiateCarrier(type);
    this.carriers.set(type, carrier);
    return carrier;
  }

  async validateCarrier(type: CarrierType): Promise<boolean> {
    const carrier = this.createCarrier(type);
    return carrier.isHealthy();
  }

  async getCarrierMetrics(type: CarrierType): Promise<{
    type: CarrierType;
    healthy: boolean;
    latency: number;
  }> {
    const carrier = this.createCarrier(type);
    const startTime = Date.now();
    const healthy = await carrier.isHealthy();
    const latency = Date.now() - startTime;

    return { type, healthy, latency };
  }

  private instantiateCarrier(type: CarrierType): CarrierApi {
    switch (type) {
      case 'twilio':
        if (!this.config.twilio) {
          throw new Error('Twilio configuration not provided');
        }
        return new TwilioCarrier({
          ...this.config.twilio,
          decisionTimeout: this.config.twilio.decisionTimeout ?? this.config.defaultDecisionTimeout,
        });

      case 'plivo':
        if (!this.config.plivo) {
          throw new Error('Plivo configuration not provided');
        }
        return new PlivoCarrier({
          ...this.config.plivo,
          decisionTimeout: this.config.plivo.decisionTimeout ?? this.config.defaultDecisionTimeout,
        });

      case 'sip':
        // SIP carrier would be implemented separately
        throw new Error('SIP carrier not yet implemented');

      default:
        throw new Error(`Unknown carrier type: ${type}`);
    }
  }

  async getAllCarriers(): Promise<Array<{ type: CarrierType; healthy: boolean }>> {
    const results: Array<{ type: CarrierType; healthy: boolean }> = [];

    for (const [type, carrier] of this.carriers.entries()) {
      const healthy = await carrier.isHealthy();
      results.push({
        type,
        healthy,
      });
    }

    return results;
  }

  clearCache(): void {
    this.carriers.clear();
  }
}
