/**
 * MTA error classes for SMTP client operations
 */

export class MtaConnectionError extends Error {
  public code: string;
  public details?: any;
  constructor(message: string, detailsOrCode?: any) {
    super(message);
    this.name = 'MtaConnectionError';
    if (typeof detailsOrCode === 'string') {
      this.code = detailsOrCode;
    } else {
      this.code = 'CONNECTION_ERROR';
      this.details = detailsOrCode;
    }
  }
  static timeout(host: string, port: number, timeoutMs?: number): MtaConnectionError {
    return new MtaConnectionError(`Connection to ${host}:${port} timed out${timeoutMs ? ` after ${timeoutMs}ms` : ''}`, 'TIMEOUT');
  }
  static refused(host: string, port: number): MtaConnectionError {
    return new MtaConnectionError(`Connection to ${host}:${port} refused`, 'REFUSED');
  }
  static dnsError(host: string, err?: any): MtaConnectionError {
    const errMsg = typeof err === 'string' ? err : err?.message || '';
    return new MtaConnectionError(`DNS resolution failed for ${host}${errMsg ? `: ${errMsg}` : ''}`, 'DNS_ERROR');
  }
}

export class MtaAuthenticationError extends Error {
  public code: string;
  public details?: any;
  constructor(message: string, detailsOrCode?: any) {
    super(message);
    this.name = 'MtaAuthenticationError';
    if (typeof detailsOrCode === 'string') {
      this.code = detailsOrCode;
    } else {
      this.code = 'AUTH_ERROR';
      this.details = detailsOrCode;
    }
  }
  static invalidCredentials(host?: string, user?: string): MtaAuthenticationError {
    const detail = host && user ? `${user}@${host}` : host || user || '';
    return new MtaAuthenticationError(`Authentication failed${detail ? `: ${detail}` : ''}`, 'INVALID_CREDENTIALS');
  }
}

export class MtaDeliveryError extends Error {
  public code: string;
  public responseCode?: number;
  public details?: any;
  constructor(message: string, detailsOrCode?: any, responseCode?: number) {
    super(message);
    this.name = 'MtaDeliveryError';
    if (typeof detailsOrCode === 'string') {
      this.code = detailsOrCode;
      this.responseCode = responseCode;
    } else {
      this.code = 'DELIVERY_ERROR';
      this.details = detailsOrCode;
    }
  }
  static temporary(message: string, ...args: any[]): MtaDeliveryError {
    return new MtaDeliveryError(message, 'TEMPORARY');
  }
  static permanent(message: string, ...args: any[]): MtaDeliveryError {
    return new MtaDeliveryError(message, 'PERMANENT');
  }
}

export class MtaConfigurationError extends Error {
  public code: string;
  public details?: any;
  constructor(message: string, detailsOrCode?: any) {
    super(message);
    this.name = 'MtaConfigurationError';
    if (typeof detailsOrCode === 'string') {
      this.code = detailsOrCode;
    } else {
      this.code = 'CONFIG_ERROR';
      this.details = detailsOrCode;
    }
  }
}

export class MtaTimeoutError extends Error {
  public code: string;
  public details?: any;
  constructor(message: string, detailsOrCode?: any) {
    super(message);
    this.name = 'MtaTimeoutError';
    if (typeof detailsOrCode === 'string') {
      this.code = detailsOrCode;
    } else {
      this.code = 'TIMEOUT';
      this.details = detailsOrCode;
    }
  }
  static commandTimeout(command: string, hostOrTimeout?: any, timeoutMs?: number): MtaTimeoutError {
    const timeout = typeof hostOrTimeout === 'number' ? hostOrTimeout : timeoutMs;
    return new MtaTimeoutError(`Command '${command}' timed out${timeout ? ` after ${timeout}ms` : ''}`, 'COMMAND_TIMEOUT');
  }
}

export class MtaProtocolError extends Error {
  public code: string;
  public details?: any;
  constructor(message: string, detailsOrCode?: any) {
    super(message);
    this.name = 'MtaProtocolError';
    if (typeof detailsOrCode === 'string') {
      this.code = detailsOrCode;
    } else {
      this.code = 'PROTOCOL_ERROR';
      this.details = detailsOrCode;
    }
  }
}
