import * as plugins from '../../plugins.js';
import { EventEmitter } from 'node:events';
import * as net from 'node:net';
import * as tls from 'node:tls';
import { logger } from '../../logger.js';
import { 
  SecurityLogger, 
  SecurityLogLevel, 
  SecurityEventType 
} from '../../security/index.js';
import { UnifiedDeliveryQueue, type IQueueItem } from './classes.delivery.queue.js';
import type { Email } from '../core/classes.email.js';
import type { UnifiedEmailServer } from '../routing/classes.unified.email.server.js';
import type { SmtpClient } from './smtpclient/smtp-client.js';

/**
 * Delivery status enumeration
 */
export enum DeliveryStatus {
  PENDING = 'pending',
  DELIVERING = 'delivering',
  DELIVERED = 'delivered',
  DEFERRED = 'deferred',
  FAILED = 'failed'
}

/**
 * Delivery handler interface
 */
export interface IDeliveryHandler {
  deliver(item: IQueueItem): Promise<any>;
}

/**
 * Delivery options
 */
export interface IMultiModeDeliveryOptions {
  // Connection options
  connectionPoolSize?: number;
  socketTimeout?: number;
  
  // Delivery behavior
  concurrentDeliveries?: number;
  sendTimeout?: number;
  
  // TLS options
  verifyCertificates?: boolean;
  tlsMinVersion?: string;
  
  // Mode-specific handlers
  forwardHandler?: IDeliveryHandler;
  deliveryHandler?: IDeliveryHandler;
  processHandler?: IDeliveryHandler;
  
  // Rate limiting
  globalRateLimit?: number;
  perPatternRateLimit?: Record<string, number>;
  
  // Bounce handling
  processBounces?: boolean;
  bounceHandler?: {
    processSmtpFailure: (recipient: string, smtpResponse: string, options: any) => Promise<any>;
  };
  
  // Event hooks
  onDeliveryStart?: (item: IQueueItem) => Promise<void>;
  onDeliverySuccess?: (item: IQueueItem, result: any) => Promise<void>;
  onDeliveryFailed?: (item: IQueueItem, error: string) => Promise<void>;
}

/**
 * Delivery system statistics
 */
export interface IDeliveryStats {
  activeDeliveries: number;
  totalSuccessful: number;
  totalFailed: number;
  avgDeliveryTime: number;
  byMode: {
    forward: {
      successful: number;
      failed: number;
    };
    mta: {
      successful: number;
      failed: number;
    };
    process: {
      successful: number;
      failed: number;
    };
  };
  rateLimiting: {
    currentRate: number;
    globalLimit: number;
    throttled: number;
  };
}

/**
 * Handles delivery for all email processing modes
 */
export class MultiModeDeliverySystem extends EventEmitter {
  private queue: UnifiedDeliveryQueue;
  private options: Required<IMultiModeDeliveryOptions>;
  private stats: IDeliveryStats;
  private deliveryTimes: number[] = [];
  private activeDeliveries: Set<string> = new Set();
  private running: boolean = false;
  private throttled: boolean = false;
  private rateLimitLastCheck: number = Date.now();
  private rateLimitCounter: number = 0;
  private emailServer?: UnifiedEmailServer;
  
  /**
   * Create a new multi-mode delivery system
   * @param queue Unified delivery queue
   * @param options Delivery options
   * @param emailServer Optional reference to unified email server for SmtpClient access
   */
  constructor(queue: UnifiedDeliveryQueue, options: IMultiModeDeliveryOptions, emailServer?: UnifiedEmailServer) {
    super();
    
    this.queue = queue;
    this.emailServer = emailServer;
    
    // Set default options
    this.options = {
      connectionPoolSize: options.connectionPoolSize || 10,
      socketTimeout: options.socketTimeout || 30000, // 30 seconds
      concurrentDeliveries: options.concurrentDeliveries || 10,
      sendTimeout: options.sendTimeout || 60000, // 1 minute
      verifyCertificates: options.verifyCertificates !== false, // Default to true
      tlsMinVersion: options.tlsMinVersion || 'TLSv1.2',
      forwardHandler: options.forwardHandler || {
        deliver: this.handleForwardDelivery.bind(this)
      },
      deliveryHandler: options.deliveryHandler || {
        deliver: this.handleMtaDelivery.bind(this)
      },
      processHandler: options.processHandler || {
        deliver: this.handleProcessDelivery.bind(this)
      },
      globalRateLimit: options.globalRateLimit || 100, // 100 emails per minute
      perPatternRateLimit: options.perPatternRateLimit || {},
      processBounces: options.processBounces !== false, // Default to true
      bounceHandler: options.bounceHandler || null,
      onDeliveryStart: options.onDeliveryStart || (async () => {}),
      onDeliverySuccess: options.onDeliverySuccess || (async () => {}),
      onDeliveryFailed: options.onDeliveryFailed || (async () => {})
    };
    
    // Initialize statistics
    this.stats = {
      activeDeliveries: 0,
      totalSuccessful: 0,
      totalFailed: 0,
      avgDeliveryTime: 0,
      byMode: {
        forward: {
          successful: 0,
          failed: 0
        },
        mta: {
          successful: 0,
          failed: 0
        },
        process: {
          successful: 0,
          failed: 0
        }
      },
      rateLimiting: {
        currentRate: 0,
        globalLimit: this.options.globalRateLimit,
        throttled: 0
      }
    };
    
    // Set up event listeners
    this.queue.on('itemsReady', this.processItems.bind(this));
  }
  
  /**
   * Start the delivery system
   */
  public async start(): Promise<void> {
    logger.log('info', 'Starting MultiModeDeliverySystem');
    
    if (this.running) {
      logger.log('warn', 'MultiModeDeliverySystem is already running');
      return;
    }
    
    this.running = true;
    
    // Emit started event
    this.emit('started');
    logger.log('info', 'MultiModeDeliverySystem started successfully');
  }
  
  /**
   * Stop the delivery system
   */
  public async stop(): Promise<void> {
    logger.log('info', 'Stopping MultiModeDeliverySystem');
    
    if (!this.running) {
      logger.log('warn', 'MultiModeDeliverySystem is already stopped');
      return;
    }
    
    this.running = false;
    
    // Wait for active deliveries to complete
    if (this.activeDeliveries.size > 0) {
      logger.log('info', `Waiting for ${this.activeDeliveries.size} active deliveries to complete`);
      
      // Wait for a maximum of 30 seconds
      await new Promise<void>(resolve => {
        const checkInterval = setInterval(() => {
          if (this.activeDeliveries.size === 0) {
            clearInterval(checkInterval);
            resolve();
          }
        }, 1000);
        
        // Force resolve after 30 seconds
        setTimeout(() => {
          clearInterval(checkInterval);
          resolve();
        }, 30000);
      });
    }
    
    // Emit stopped event
    this.emit('stopped');
    logger.log('info', 'MultiModeDeliverySystem stopped successfully');
  }
  
  /**
   * Process ready items from the queue
   * @param items Queue items ready for processing
   */
  private async processItems(items: IQueueItem[]): Promise<void> {
    if (!this.running) {
      return;
    }
    
    // Check if we're already at max concurrent deliveries
    if (this.activeDeliveries.size >= this.options.concurrentDeliveries) {
      logger.log('debug', `Already at max concurrent deliveries (${this.activeDeliveries.size})`);
      return;
    }
    
    // Check rate limiting
    if (this.checkRateLimit()) {
      logger.log('debug', 'Rate limit exceeded, throttling deliveries');
      return;
    }
    
    // Calculate how many more deliveries we can start
    const availableSlots = this.options.concurrentDeliveries - this.activeDeliveries.size;
    const itemsToProcess = items.slice(0, availableSlots);
    
    if (itemsToProcess.length === 0) {
      return;
    }
    
    logger.log('info', `Processing ${itemsToProcess.length} items for delivery`);
    
    // Process each item
    for (const item of itemsToProcess) {
      // Mark as processing
      await this.queue.markProcessing(item.id);
      
      // Add to active deliveries
      this.activeDeliveries.add(item.id);
      this.stats.activeDeliveries = this.activeDeliveries.size;
      
      // Deliver asynchronously
      this.deliverItem(item).catch(err => {
        logger.log('error', `Unhandled error in delivery: ${err.message}`);
      });
    }
    
    // Update statistics
    this.emit('statsUpdated', this.stats);
  }
  
  /**
   * Deliver an item from the queue
   * @param item Queue item to deliver
   */
  private async deliverItem(item: IQueueItem): Promise<void> {
    const startTime = Date.now();
    
    try {
      // Call delivery start hook
      await this.options.onDeliveryStart(item);
      
      // Emit delivery start event
      this.emit('deliveryStart', item);
      logger.log('info', `Starting delivery of item ${item.id}, mode: ${item.processingMode}`);
      
      // Choose the appropriate handler based on mode
      let result: any;
      
      switch (item.processingMode) {
        case 'forward':
          result = await this.options.forwardHandler.deliver(item);
          break;
          
        case 'mta':
          result = await this.options.deliveryHandler.deliver(item);
          break;
          
        case 'process':
          result = await this.options.processHandler.deliver(item);
          break;
          
        default:
          throw new Error(`Unknown processing mode: ${item.processingMode}`);
      }
      
      // Mark as delivered
      await this.queue.markDelivered(item.id);
      
      // Update statistics
      this.stats.totalSuccessful++;
      this.stats.byMode[item.processingMode].successful++;
      
      // Calculate delivery time
      const deliveryTime = Date.now() - startTime;
      this.deliveryTimes.push(deliveryTime);
      this.updateDeliveryTimeStats();
      
      // Call delivery success hook
      await this.options.onDeliverySuccess(item, result);
      
      // Emit delivery success event
      this.emit('deliverySuccess', item, result);
      logger.log('info', `Item ${item.id} delivered successfully in ${deliveryTime}ms`);
      
      SecurityLogger.getInstance().logEvent({
        level: SecurityLogLevel.INFO,
        type: SecurityEventType.EMAIL_DELIVERY,
        message: 'Email delivery successful',
        details: {
          itemId: item.id,
          mode: item.processingMode,
          routeName: item.route?.name || 'unknown',
          deliveryTime
        },
        success: true
      });
    } catch (error: any) {
      // Calculate delivery attempt time even for failures
      const deliveryTime = Date.now() - startTime;
      
      // Mark as failed
      await this.queue.markFailed(item.id, error.message);
      
      // Update statistics
      this.stats.totalFailed++;
      this.stats.byMode[item.processingMode].failed++;
      
      // Call delivery failed hook
      await this.options.onDeliveryFailed(item, error.message);
      
      // Process as bounce if enabled and we have a bounce handler
      if (this.options.processBounces && this.options.bounceHandler) {
        try {
          const email = item.processingResult as Email;
          
          // Extract recipient and error message
          // For multiple recipients, we'd need more sophisticated parsing
          const recipient = email.to.length > 0 ? email.to[0] : '';
          
          if (recipient) {
            logger.log('info', `Processing delivery failure as bounce for recipient ${recipient}`);
            
            // Process SMTP failure through bounce handler
            await this.options.bounceHandler.processSmtpFailure(
              recipient,
              error.message,
              {
                sender: email.from,
                originalEmailId: item.id,
                headers: email.headers
              }
            );
            
            logger.log('info', `Bounce record created for failed delivery to ${recipient}`);
          }
        } catch (bounceError) {
          logger.log('error', `Failed to process bounce: ${bounceError.message}`);
        }
      }
      
      // Emit delivery failed event
      this.emit('deliveryFailed', item, error);
      logger.log('error', `Item ${item.id} delivery failed: ${error.message}`);
      
      SecurityLogger.getInstance().logEvent({
        level: SecurityLogLevel.ERROR,
        type: SecurityEventType.EMAIL_DELIVERY,
        message: 'Email delivery failed',
        details: {
          itemId: item.id,
          mode: item.processingMode,
          routeName: item.route?.name || 'unknown',
          error: error.message,
          deliveryTime
        },
        success: false
      });
    } finally {
      // Remove from active deliveries
      this.activeDeliveries.delete(item.id);
      this.stats.activeDeliveries = this.activeDeliveries.size;
      
      // Update statistics
      this.emit('statsUpdated', this.stats);
    }
  }
  
  /**
   * Default handler for forward mode delivery
   * @param item Queue item
   */
  private async handleForwardDelivery(item: IQueueItem): Promise<any> {
    logger.log('info', `Forward delivery for item ${item.id}`);
    
    const email = item.processingResult as Email;
    const route = item.route;
    
    // Get target server information
    const targetServer = route?.action.forward?.host;
    const targetPort = route?.action.forward?.port || 25;
    const useTls = false; // TLS configuration can be enhanced later
    
    if (!targetServer) {
      throw new Error('No target server configured for forward mode');
    }
    
    logger.log('info', `Forwarding email to ${targetServer}:${targetPort}, TLS: ${useTls}`);
    
    try {
      // Get SMTP client from email server if available
      if (!this.emailServer) {
        // Fall back to raw socket implementation if no email server
        logger.log('warn', 'No email server available, falling back to raw socket implementation');
        return this.handleForwardDeliveryLegacy(item);
      }
      
      // Get SMTP client from UnifiedEmailServer
      const smtpClient = this.emailServer.getSmtpClient(targetServer, targetPort);
      
      // Apply DKIM signing if configured in the route
      if (item.route?.action.options?.mtaOptions?.dkimSign) {
        await this.applyDkimSigning(email, item.route.action.options.mtaOptions);
      }
      
      // Send the email using SmtpClient
      const result = await smtpClient.sendMail(email);
      
      if (result.success) {
        logger.log('info', `Email forwarded successfully to ${targetServer}:${targetPort}`);
        
        return {
          targetServer: targetServer,
          targetPort: targetPort,
          recipients: result.acceptedRecipients.length,
          messageId: result.messageId,
          rejectedRecipients: result.rejectedRecipients
        };
      } else {
        throw new Error(result.error?.message || 'Failed to forward email');
      }
    } catch (error: any) {
      logger.log('error', `Failed to forward email: ${error.message}`);
      throw error;
    }
  }
  
  /**
   * Legacy forward delivery using raw sockets (fallback)
   * @param item Queue item
   */
  private async handleForwardDeliveryLegacy(item: IQueueItem): Promise<any> {
    const email = item.processingResult as Email;
    const route = item.route;
    
    // Get target server information
    const targetServer = route?.action.forward?.host;
    const targetPort = route?.action.forward?.port || 25;
    const useTls = false; // TLS configuration can be enhanced later
    
    if (!targetServer) {
      throw new Error('No target server configured for forward mode');
    }
    
    // Create a socket connection to the target server
    const socket = new net.Socket();
    
    // Set timeout
    socket.setTimeout(this.options.socketTimeout);
    
    try {
      // Connect to the target server
      await new Promise<void>((resolve, reject) => {
        // Handle connection events
        socket.on('connect', () => {
          logger.log('debug', `Connected to ${targetServer}:${targetPort}`);
          resolve();
        });
        
        socket.on('timeout', () => {
          reject(new Error(`Connection timeout to ${targetServer}:${targetPort}`));
        });
        
        socket.on('error', (err) => {
          reject(new Error(`Connection error to ${targetServer}:${targetPort}: ${err.message}`));
        });
        
        // Connect to the server
        socket.connect({
          host: targetServer,
          port: targetPort
        });
      });
      
      // Send EHLO
      await this.smtpCommand(socket, `EHLO ${route?.action.options?.mtaOptions?.domain || 'localhost'}`);
      
      // Start TLS if required
      if (useTls) {
        await this.smtpCommand(socket, 'STARTTLS');
        
        // Upgrade to TLS
        const tlsSocket = await this.upgradeTls(socket, targetServer);
        
        // Send EHLO again after STARTTLS
        await this.smtpCommand(tlsSocket, `EHLO ${route?.action.options?.mtaOptions?.domain || 'localhost'}`);
        
        // Use tlsSocket for remaining commands
        return this.completeSMTPExchange(tlsSocket, email, route);
      }
      
      // Complete the SMTP exchange
      return this.completeSMTPExchange(socket, email, route);
    } catch (error: any) {
      logger.log('error', `Failed to forward email: ${error.message}`);
      
      // Close the connection
      socket.destroy();
      
      throw error;
    }
  }
  
  /**
   * Complete the SMTP exchange after connection and initial setup
   * @param socket Network socket
   * @param email Email to send
   * @param rule Domain rule
   */
  private async completeSMTPExchange(socket: net.Socket | tls.TLSSocket, email: Email, route: any): Promise<any> {
    try {
      // Authenticate if credentials provided
      if (route?.action?.forward?.auth?.user && route?.action?.forward?.auth?.pass) {
        // Send AUTH LOGIN
        await this.smtpCommand(socket, 'AUTH LOGIN');
        
        // Send username (base64)
        const username = Buffer.from(route.action.forward.auth.user).toString('base64');
        await this.smtpCommand(socket, username);
        
        // Send password (base64)
        const password = Buffer.from(route.action.forward.auth.pass).toString('base64');
        await this.smtpCommand(socket, password);
      }
      
      // Send MAIL FROM
      await this.smtpCommand(socket, `MAIL FROM:<${email.from}>`);
      
      // Send RCPT TO for each recipient
      for (const recipient of email.getAllRecipients()) {
        await this.smtpCommand(socket, `RCPT TO:<${recipient}>`);
      }
      
      // Send DATA
      await this.smtpCommand(socket, 'DATA');
      
      // Send email content (simplified)
      const emailContent = await this.getFormattedEmail(email);
      await this.smtpData(socket, emailContent);
      
      // Send QUIT
      await this.smtpCommand(socket, 'QUIT');
      
      // Close the connection
      socket.end();
      
      logger.log('info', `Email forwarded successfully to ${route?.action?.forward?.host}:${route?.action?.forward?.port || 25}`);
      
      return {
        targetServer: route?.action?.forward?.host,
        targetPort: route?.action?.forward?.port || 25,
        recipients: email.getAllRecipients().length
      };
    } catch (error: any) {
      logger.log('error', `Failed to forward email: ${error.message}`);
      
      // Close the connection
      socket.destroy();
      
      throw error;
    }
  }
  
  /**
   * Default handler for MTA mode delivery
   * @param item Queue item
   */
  private async handleMtaDelivery(item: IQueueItem): Promise<any> {
    logger.log('info', `MTA delivery for item ${item.id}`);
    
    const email = item.processingResult as Email;
    const route = item.route;
    
    try {
      // Apply DKIM signing if configured in the route
      if (item.route?.action.options?.mtaOptions?.dkimSign) {
        await this.applyDkimSigning(email, item.route.action.options.mtaOptions);
      }
      
      // In a full implementation, this would use the MTA service
      // For now, we'll simulate a successful delivery
      
      logger.log('info', `Email processed by MTA: ${email.subject} to ${email.getAllRecipients().join(', ')}`);
      
      // Note: The MTA implementation would handle actual local delivery
      
      // Simulate successful delivery
      return {
        recipients: email.getAllRecipients().length,
        subject: email.subject,
        dkimSigned: !!item.route?.action.options?.mtaOptions?.dkimSign
      };
    } catch (error: any) {
      logger.log('error', `Failed to process email in MTA mode: ${error.message}`);
      throw error;
    }
  }
  
  /**
   * Default handler for process mode delivery
   * @param item Queue item
   */
  private async handleProcessDelivery(item: IQueueItem): Promise<any> {
    logger.log('info', `Process delivery for item ${item.id}`);
    
    const email = item.processingResult as Email;
    const route = item.route;
    
    try {
      // Apply content scanning if enabled
      if (route?.action.options?.contentScanning && route?.action.options?.scanners && route.action.options.scanners.length > 0) {
        logger.log('info', 'Performing content scanning');
        
        // Apply each scanner
        for (const scanner of route.action.options.scanners) {
          switch (scanner.type) {
            case 'spam':
              logger.log('info', 'Scanning for spam content');
              // Implement spam scanning
              break;
              
            case 'virus':
              logger.log('info', 'Scanning for virus content');
              // Implement virus scanning
              break;
              
            case 'attachment':
              logger.log('info', 'Scanning attachments');
              
              // Check for blocked extensions
              if (scanner.blockedExtensions && scanner.blockedExtensions.length > 0) {
                for (const attachment of email.attachments) {
                  const ext = this.getFileExtension(attachment.filename);
                  if (scanner.blockedExtensions.includes(ext)) {
                    if (scanner.action === 'reject') {
                      throw new Error(`Blocked attachment type: ${ext}`);
                    } else { // tag
                      email.addHeader('X-Attachment-Warning', `Potentially unsafe attachment: ${attachment.filename}`);
                    }
                  }
                }
              }
              break;
          }
        }
      }
      
      // Apply transformations if defined
      if (route?.action.options?.transformations && route?.action.options?.transformations.length > 0) {
        logger.log('info', 'Applying email transformations');
        
        for (const transform of route.action.options.transformations) {
          switch (transform.type) {
            case 'addHeader':
              if (transform.header && transform.value) {
                email.addHeader(transform.header, transform.value);
              }
              break;
          }
        }
      }
      
      // Apply DKIM signing if configured (after all transformations)
      if (item.route?.action.options?.mtaOptions?.dkimSign || item.route?.action.process?.dkim) {
        await this.applyDkimSigning(email, item.route.action.options?.mtaOptions || {});
      }
      
      logger.log('info', `Email successfully processed in store-and-forward mode`);
      
      // Simulate successful delivery
      return {
        recipients: email.getAllRecipients().length,
        subject: email.subject,
        scanned: !!route?.action.options?.contentScanning,
        transformed: !!(route?.action.options?.transformations && route?.action.options?.transformations.length > 0),
        dkimSigned: !!(item.route?.action.options?.mtaOptions?.dkimSign || item.route?.action.process?.dkim)
      };
    } catch (error: any) {
      logger.log('error', `Failed to process email: ${error.message}`);
      throw error;
    }
  }
  
  /**
   * Get file extension from filename
   */
  private getFileExtension(filename: string): string {
    return filename.substring(filename.lastIndexOf('.')).toLowerCase();
  }
  
  /**
   * Apply DKIM signing to an email
   */
  private async applyDkimSigning(email: Email, mtaOptions: any): Promise<void> {
    if (!this.emailServer) {
      logger.log('warn', 'Cannot apply DKIM signing without email server reference');
      return;
    }
    
    const domainName = mtaOptions.dkimOptions?.domainName || email.from.split('@')[1];
    const keySelector = mtaOptions.dkimOptions?.keySelector || 'default';
    
    try {
      // Ensure DKIM keys exist for the domain
      await this.emailServer.dkimCreator.handleDKIMKeysForDomain(domainName);
      
      // Convert Email to raw format for signing
      const rawEmail = email.toRFC822String();
      
      // Sign the email
      const signResult = await plugins.dkimSign(rawEmail, {
        canonicalization: 'relaxed/relaxed',
        algorithm: 'rsa-sha256',
        signTime: new Date(),
        signatureData: [
          {
            signingDomain: domainName,
            selector: keySelector,
            privateKey: (await this.emailServer.dkimCreator.readDKIMKeys(domainName)).privateKey,
            algorithm: 'rsa-sha256',
            canonicalization: 'relaxed/relaxed'
          }
        ]
      });
      
      // Add the DKIM-Signature header to the email
      if (signResult.signatures) {
        email.addHeader('DKIM-Signature', signResult.signatures);
        logger.log('info', `Successfully added DKIM signature for ${domainName}`);
      }
    } catch (error) {
      logger.log('error', `Failed to apply DKIM signature: ${error.message}`);
      // Don't throw - allow email to be sent without DKIM if signing fails
    }
  }
  
  /**
   * Format email for SMTP transmission
   * @param email Email to format
   */
  private async getFormattedEmail(email: Email): Promise<string> {
    // This is a simplified implementation
    // In a full implementation, this would use proper MIME formatting
    
    let content = '';
    
    // Add headers
    content += `From: ${email.from}\r\n`;
    content += `To: ${email.to.join(', ')}\r\n`;
    content += `Subject: ${email.subject}\r\n`;
    
    // Add additional headers
    for (const [name, value] of Object.entries(email.headers || {})) {
      content += `${name}: ${value}\r\n`;
    }
    
    // Add content type for multipart
    if (email.attachments && email.attachments.length > 0) {
      const boundary = `----_=_NextPart_${Math.random().toString(36).substr(2)}`;
      content += `MIME-Version: 1.0\r\n`;
      content += `Content-Type: multipart/mixed; boundary="${boundary}"\r\n`;
      content += `\r\n`;
      
      // Add text part
      content += `--${boundary}\r\n`;
      content += `Content-Type: text/plain; charset="UTF-8"\r\n`;
      content += `\r\n`;
      content += `${email.text}\r\n`;
      
      // Add HTML part if present
      if (email.html) {
        content += `--${boundary}\r\n`;
        content += `Content-Type: text/html; charset="UTF-8"\r\n`;
        content += `\r\n`;
        content += `${email.html}\r\n`;
      }
      
      // Add attachments
      for (const attachment of email.attachments) {
        content += `--${boundary}\r\n`;
        content += `Content-Type: ${attachment.contentType || 'application/octet-stream'}; name="${attachment.filename}"\r\n`;
        content += `Content-Disposition: attachment; filename="${attachment.filename}"\r\n`;
        content += `Content-Transfer-Encoding: base64\r\n`;
        content += `\r\n`;
        
        // Add base64 encoded content
        const base64Content = attachment.content.toString('base64');
        
        // Split into lines of 76 characters
        for (let i = 0; i < base64Content.length; i += 76) {
          content += base64Content.substring(i, i + 76) + '\r\n';
        }
      }
      
      // End boundary
      content += `--${boundary}--\r\n`;
    } else {
      // Simple email with just text
      content += `Content-Type: text/plain; charset="UTF-8"\r\n`;
      content += `\r\n`;
      content += `${email.text}\r\n`;
    }
    
    return content;
  }
  
  /**
   * Send SMTP command and wait for response
   * @param socket Socket connection
   * @param command SMTP command to send
   */
  private async smtpCommand(socket: net.Socket, command: string): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      const onData = (data: Buffer) => {
        const response = data.toString().trim();
        
        // Clean up listeners
        socket.removeListener('data', onData);
        socket.removeListener('error', onError);
        socket.removeListener('timeout', onTimeout);
        
        // Check response code
        if (response.charAt(0) === '2' || response.charAt(0) === '3') {
          resolve(response);
        } else {
          reject(new Error(`SMTP error: ${response}`));
        }
      };
      
      const onError = (err: Error) => {
        // Clean up listeners
        socket.removeListener('data', onData);
        socket.removeListener('error', onError);
        socket.removeListener('timeout', onTimeout);
        
        reject(err);
      };
      
      const onTimeout = () => {
        // Clean up listeners
        socket.removeListener('data', onData);
        socket.removeListener('error', onError);
        socket.removeListener('timeout', onTimeout);
        
        reject(new Error('SMTP command timeout'));
      };
      
      // Set up listeners
      socket.once('data', onData);
      socket.once('error', onError);
      socket.once('timeout', onTimeout);
      
      // Send command
      socket.write(command + '\r\n');
    });
  }
  
  /**
   * Send SMTP DATA command with content
   * @param socket Socket connection
   * @param data Email content to send
   */
  private async smtpData(socket: net.Socket, data: string): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      const onData = (responseData: Buffer) => {
        const response = responseData.toString().trim();
        
        // Clean up listeners
        socket.removeListener('data', onData);
        socket.removeListener('error', onError);
        socket.removeListener('timeout', onTimeout);
        
        // Check response code
        if (response.charAt(0) === '2') {
          resolve(response);
        } else {
          reject(new Error(`SMTP error: ${response}`));
        }
      };
      
      const onError = (err: Error) => {
        // Clean up listeners
        socket.removeListener('data', onData);
        socket.removeListener('error', onError);
        socket.removeListener('timeout', onTimeout);
        
        reject(err);
      };
      
      const onTimeout = () => {
        // Clean up listeners
        socket.removeListener('data', onData);
        socket.removeListener('error', onError);
        socket.removeListener('timeout', onTimeout);
        
        reject(new Error('SMTP data timeout'));
      };
      
      // Set up listeners
      socket.once('data', onData);
      socket.once('error', onError);
      socket.once('timeout', onTimeout);
      
      // Send data and end with CRLF.CRLF
      socket.write(data + '\r\n.\r\n');
    });
  }
  
  /**
   * Upgrade socket to TLS
   * @param socket Socket connection
   * @param hostname Target hostname for TLS
   */
  private async upgradeTls(socket: net.Socket, hostname: string): Promise<tls.TLSSocket> {
    return new Promise<tls.TLSSocket>((resolve, reject) => {
      const tlsOptions: tls.ConnectionOptions = {
        socket,
        servername: hostname,
        rejectUnauthorized: this.options.verifyCertificates,
        minVersion: this.options.tlsMinVersion as tls.SecureVersion
      };
      
      const tlsSocket = tls.connect(tlsOptions);
      
      tlsSocket.once('secureConnect', () => {
        resolve(tlsSocket);
      });
      
      tlsSocket.once('error', (err) => {
        reject(new Error(`TLS error: ${err.message}`));
      });
      
      tlsSocket.setTimeout(this.options.socketTimeout);
      
      tlsSocket.once('timeout', () => {
        reject(new Error('TLS connection timeout'));
      });
    });
  }
  
  /**
   * Update delivery time statistics
   */
  private updateDeliveryTimeStats(): void {
    if (this.deliveryTimes.length === 0) return;
    
    // Keep only the last 1000 delivery times
    if (this.deliveryTimes.length > 1000) {
      this.deliveryTimes = this.deliveryTimes.slice(-1000);
    }
    
    // Calculate average
    const sum = this.deliveryTimes.reduce((acc, time) => acc + time, 0);
    this.stats.avgDeliveryTime = sum / this.deliveryTimes.length;
  }
  
  /**
   * Check if rate limit is exceeded
   * @returns True if rate limited, false otherwise
   */
  private checkRateLimit(): boolean {
    const now = Date.now();
    const elapsed = now - this.rateLimitLastCheck;
    
    // Reset counter if more than a minute has passed
    if (elapsed >= 60000) {
      this.rateLimitLastCheck = now;
      this.rateLimitCounter = 0;
      this.throttled = false;
      this.stats.rateLimiting.currentRate = 0;
      return false;
    }
    
    // Check if we're already throttled
    if (this.throttled) {
      return true;
    }
    
    // Increment counter
    this.rateLimitCounter++;
    
    // Calculate current rate (emails per minute)
    const rate = (this.rateLimitCounter / elapsed) * 60000;
    this.stats.rateLimiting.currentRate = rate;
    
    // Check if rate limit is exceeded
    if (rate > this.options.globalRateLimit) {
      this.throttled = true;
      this.stats.rateLimiting.throttled++;
      
      // Schedule throttle reset
      const resetDelay = 60000 - elapsed;
      setTimeout(() => {
        this.throttled = false;
        this.rateLimitLastCheck = Date.now();
        this.rateLimitCounter = 0;
        this.stats.rateLimiting.currentRate = 0;
      }, resetDelay);
      
      return true;
    }
    
    return false;
  }
  
  /**
   * Update delivery options
   * @param options New options
   */
  public updateOptions(options: Partial<IMultiModeDeliveryOptions>): void {
    this.options = {
      ...this.options,
      ...options
    };
    
    // Update rate limit statistics
    if (options.globalRateLimit) {
      this.stats.rateLimiting.globalLimit = options.globalRateLimit;
    }
    
    logger.log('info', 'MultiModeDeliverySystem options updated');
  }
  
  /**
   * Get delivery statistics
   */
  public getStats(): IDeliveryStats {
    return { ...this.stats };
  }
}