import {
  SmtpConfig,
  SendGridConfig,
  SesConfig,
  EmailProviderConfig,
  EmailProviderType,
} from '../interfaces/email-options.interface';
import { ConfigurationError, ValidationError } from '../errors';

export class ConfigValidator {
  static validateSmtpConfig(config: SmtpConfig): void {
    if (!config.host) {
      throw new ConfigurationError('SMTP host is required');
    }
    if (!config.port) {
      throw new ConfigurationError('SMTP port is required');
    }
    if (config.auth) {
      if (!config.auth.user) {
        throw new ConfigurationError('SMTP username is required when auth is provided');
      }
      if (!config.auth.pass) {
        throw new ConfigurationError('SMTP password is required when auth is provided');
      }
    }
  }

  static validateSendGridConfig(config: SendGridConfig): void {
    if (!config.apiKey) {
      throw new ConfigurationError('SendGrid API key is required');
    }

    // Check for basic API key format (SendGrid keys typically start with "SG.")
    if (typeof config.apiKey === 'string' && !config.apiKey.startsWith('SG.')) {
      throw new ConfigurationError('SendGrid API key appears to be invalid. Valid SendGrid API keys typically start with "SG."');
    }

    // Check for minimum length (SendGrid keys are typically 69 characters)
    if (typeof config.apiKey === 'string' && config.apiKey.length < 20) {
      throw new ConfigurationError('SendGrid API key appears to be too short. Please verify your API key.');
    }
  }

  static validateSesConfig(config: SesConfig): void {
    if (!config.region) {
      throw new ConfigurationError('SES region is required');
    }

    // Validate that at least one credential method is provided
    const hasCredentials = config.credentials || 
                         (config.accessKeyId && config.secretAccessKey) ||
                         process.env.AWS_ACCESS_KEY_ID;
    
    if (!hasCredentials) {
      throw new ConfigurationError('SES credentials are required (accessKeyId/secretAccessKey, credentials object, or AWS environment variables)');
    }

    // Validate region format (basic check)
    if (!/^[a-z0-9-]+$/.test(config.region)) {
      throw new ConfigurationError('Invalid SES region format');
    }

    // Validate optional parameters
    if (config.maxRetries !== undefined && config.maxRetries < 0) {
      throw new ConfigurationError('SES maxRetries must be a non-negative number');
    }

    if (config.httpOptions) {
      if (config.httpOptions.timeout !== undefined && config.httpOptions.timeout < 0) {
        throw new ConfigurationError('SES httpOptions timeout must be a non-negative number');
      }
      if (config.httpOptions.connectTimeout !== undefined && config.httpOptions.connectTimeout < 0) {
        throw new ConfigurationError('SES httpOptions connectTimeout must be a non-negative number');
      }
    }
  }

  static validateProviderConfig(config: EmailProviderConfig): void {
    if (!config.type) {
      throw new ConfigurationError('Provider type is required');
    }

    switch (config.type) {
      case EmailProviderType.SMTP:
        this.validateSmtpConfig(config.config as SmtpConfig);
        break;
      case EmailProviderType.SENDGRID:
        this.validateSendGridConfig(config.config as SendGridConfig);
        break;
      case EmailProviderType.SES:
        this.validateSesConfig(config.config as SesConfig);
        break;
      default:
        throw new ConfigurationError(`Unsupported provider type: ${config.type}`);
    }
  }

  static validateEmail(email: string): void {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      throw new ValidationError(`Invalid email format: ${email}`);
    }
  }

  static validatePort(port: number): void {
    if (port < 1 || port > 65535) {
      throw new ConfigurationError(`Invalid port number: ${port}`);
    }
  }

  static validateTimeout(timeout: number): void {
    if (timeout < 0) {
      throw new ConfigurationError('Timeout must be a positive number');
    }
  }

  static validateRetryAttempts(attempts: number): void {
    if (attempts < 0) {
      throw new ConfigurationError('Retry attempts must be a positive number');
    }
  }

  static validateRetryDelay(delay: number): void {
    if (delay < 0) {
      throw new ConfigurationError('Retry delay must be a positive number');
    }
  }
}
