/**
 * SMTP Client Helper Functions
 * Protocol helper functions and utilities
 */

import { SMTP_CODES, REGEX_PATTERNS, LINE_ENDINGS } from '../constants.js';
import type { ISmtpResponse, ISmtpCapabilities } from '../interfaces.js';

/**
 * Parse SMTP server response
 */
export function parseSmtpResponse(data: string): ISmtpResponse {
  const lines = data.trim().split(/\r?\n/);
  const firstLine = lines[0];
  const match = firstLine.match(REGEX_PATTERNS.RESPONSE_CODE);
  
  if (!match) {
    return {
      code: 500,
      message: 'Invalid server response',
      raw: data
    };
  }
  
  const code = parseInt(match[1], 10);
  const separator = match[2];
  const message = lines.map(line => line.substring(4)).join(' ');
  
  // Check for enhanced status code
  const enhancedMatch = message.match(REGEX_PATTERNS.ENHANCED_STATUS);
  const enhancedCode = enhancedMatch ? enhancedMatch[1] : undefined;
  
  return {
    code,
    message: enhancedCode ? message.substring(enhancedCode.length + 1) : message,
    enhancedCode,
    raw: data
  };
}

/**
 * Parse EHLO response and extract capabilities
 */
export function parseEhloResponse(response: string): ISmtpCapabilities {
  const lines = response.trim().split(/\r?\n/);
  const capabilities: ISmtpCapabilities = {
    extensions: new Set(),
    authMethods: new Set(),
    pipelining: false,
    starttls: false,
    eightBitMime: false
  };
  
  for (const line of lines.slice(1)) { // Skip first line (greeting)
    const extensionLine = line.substring(4); // Remove "250-" or "250 "
    const parts = extensionLine.split(/\s+/);
    const extension = parts[0].toUpperCase();
    
    capabilities.extensions.add(extension);
    
    switch (extension) {
      case 'PIPELINING':
        capabilities.pipelining = true;
        break;
      case 'STARTTLS':
        capabilities.starttls = true;
        break;
      case '8BITMIME':
        capabilities.eightBitMime = true;
        break;
      case 'SIZE':
        if (parts[1]) {
          capabilities.maxSize = parseInt(parts[1], 10);
        }
        break;
      case 'AUTH':
        // Parse authentication methods
        for (let i = 1; i < parts.length; i++) {
          capabilities.authMethods.add(parts[i].toUpperCase());
        }
        break;
    }
  }
  
  return capabilities;
}

/**
 * Format SMTP command with proper line ending
 */
export function formatCommand(command: string, ...args: string[]): string {
  const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command;
  return fullCommand + LINE_ENDINGS.CRLF;
}

/**
 * Encode authentication string for AUTH PLAIN
 */
export function encodeAuthPlain(username: string, password: string): string {
  const authString = `\0${username}\0${password}`;
  return Buffer.from(authString, 'utf8').toString('base64');
}

/**
 * Encode authentication string for AUTH LOGIN
 */
export function encodeAuthLogin(value: string): string {
  return Buffer.from(value, 'utf8').toString('base64');
}

/**
 * Generate OAuth2 authentication string
 */
export function generateOAuth2String(username: string, accessToken: string): string {
  const authString = `user=${username}\x01auth=Bearer ${accessToken}\x01\x01`;
  return Buffer.from(authString, 'utf8').toString('base64');
}

/**
 * Check if response code indicates success
 */
export function isSuccessCode(code: number): boolean {
  return code >= 200 && code < 300;
}

/**
 * Check if response code indicates temporary failure
 */
export function isTemporaryFailure(code: number): boolean {
  return code >= 400 && code < 500;
}

/**
 * Check if response code indicates permanent failure
 */
export function isPermanentFailure(code: number): boolean {
  return code >= 500;
}

/**
 * Escape email address for SMTP commands
 */
export function escapeEmailAddress(email: string): string {
  return `<${email.trim()}>`;
}

/**
 * Extract email address from angle brackets
 */
export function extractEmailAddress(email: string): string {
  const match = email.match(/^<(.+)>$/);
  return match ? match[1] : email.trim();
}

/**
 * Generate unique connection ID
 */
export function generateConnectionId(): string {
  return `smtp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}

/**
 * Format timeout duration for human readability
 */
export function formatTimeout(milliseconds: number): string {
  if (milliseconds < 1000) {
    return `${milliseconds}ms`;
  } else if (milliseconds < 60000) {
    return `${Math.round(milliseconds / 1000)}s`;
  } else {
    return `${Math.round(milliseconds / 60000)}m`;
  }
}

/**
 * Validate and normalize email data size
 */
export function validateEmailSize(emailData: string, maxSize?: number): boolean {
  const size = Buffer.byteLength(emailData, 'utf8');
  return !maxSize || size <= maxSize;
}

/**
 * Clean sensitive data from logs
 */
export function sanitizeForLogging(data: any): any {
  if (typeof data !== 'object' || data === null) {
    return data;
  }
  
  const sanitized = { ...data };
  const sensitiveFields = ['password', 'pass', 'accessToken', 'refreshToken', 'clientSecret'];
  
  for (const field of sensitiveFields) {
    if (field in sanitized) {
      sanitized[field] = '[REDACTED]';
    }
  }
  
  return sanitized;
}

/**
 * Calculate exponential backoff delay
 */
export function calculateBackoffDelay(attempt: number, baseDelay: number = 1000): number {
  return Math.min(baseDelay * Math.pow(2, attempt - 1), 30000); // Max 30 seconds
}

/**
 * Parse enhanced status code
 */
export function parseEnhancedStatusCode(code: string): { class: number; subject: number; detail: number } | null {
  const match = code.match(/^(\d)\.(\d)\.(\d)$/);
  if (!match) {
    return null;
  }
  
  return {
    class: parseInt(match[1], 10),
    subject: parseInt(match[2], 10),
    detail: parseInt(match[3], 10)
  };
}