import crypto from 'crypto';

// Get encryption key from environment or generate a default one
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY || 'phosphat-report-default-key-32b'; // Must be 32 characters
const ALGORITHM = 'aes-256-cbc';
const IV_LENGTH = 16; // For AES, this is always 16

// Ensure the key is exactly 32 bytes
function getEncryptionKey(): Buffer {
  const key = ENCRYPTION_KEY.padEnd(32, '0').substring(0, 32);
  return Buffer.from(key, 'utf8');
}

/**
 * Encrypts a plain text string
 * @param text - The plain text to encrypt
 * @returns Encrypted string in format: iv:encryptedData
 */
export function encrypt(text: string): string {
  if (!text) return '';
  
  try {
    const key = getEncryptionKey();
    const iv = crypto.randomBytes(IV_LENGTH);
    const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
    
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    
    // Return iv and encrypted data separated by ':'
    return iv.toString('hex') + ':' + encrypted;
  } catch (error) {
    console.error('Encryption error:', error);
    throw new Error('Failed to encrypt data');
  }
}

/**
 * Decrypts an encrypted string
 * @param encryptedText - The encrypted text in format: iv:encryptedData
 * @returns Decrypted plain text string
 */
export function decrypt(encryptedText: string): string {
  if (!encryptedText) return '';
  
  try {
    const key = getEncryptionKey();
    
    // Check if this is the new format with IV
    if (isEncrypted(encryptedText)) {
      const textParts = encryptedText.split(':');
      
      if (textParts.length !== 2) {
        throw new Error('Invalid encrypted text format');
      }
      
      const iv = Buffer.from(textParts[0], 'hex');
      const encryptedData = textParts[1];
      
      const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
      let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
      decrypted += decipher.final('utf8');
      
      return decrypted;
    } 
    // Check if this is legacy format
    else if (isLegacyEncrypted(encryptedText)) {
      try {
        return legacyDecrypt(encryptedText);
      } catch (legacyError) {
        console.warn('Failed to decrypt legacy format, treating as plain text:', legacyError);
        // If we can't decrypt legacy format, assume it's plain text
        return encryptedText;
      }
    }
    // If it doesn't match any encrypted format, assume it's plain text
    else {
      return encryptedText;
    }
  } catch (error) {
    console.error('Decryption error:', error);
    // If decryption fails completely, return the original text
    // This prevents the app from crashing if there's corrupted data
    console.warn('Returning original text due to decryption failure');
    return encryptedText;
  }
}

/**
 * Encrypts sensitive mail settings
 * @param settings - Mail settings object
 * @returns Mail settings with encrypted password
 */
export function encryptMailSettings(settings: {
  host: string;
  port: number;
  secure: boolean;
  username: string;
  password: string;
  fromName: string;
  fromEmail: string;
}) {
  return {
    ...settings,
    password: encrypt(settings.password)
  };
}

/**
 * Decrypts sensitive mail settings
 * @param settings - Mail settings object with encrypted password
 * @returns Mail settings with decrypted password
 */
export function decryptMailSettings(settings: {
  host: string;
  port: number;
  secure: boolean;
  username: string;
  password: string;
  fromName: string;
  fromEmail: string;
}) {
  try {
    return {
      ...settings,
      password: decrypt(settings.password)
    };
  } catch (error) {
    console.error('Failed to decrypt mail settings password:', error);
    // Return settings with empty password if decryption fails
    // This prevents the app from crashing
    return {
      ...settings,
      password: ''
    };
  }
}

/**
 * Legacy decrypt function for backward compatibility with old encryption method
 * @param encryptedText - The encrypted text
 * @returns Decrypted plain text string
 */
function legacyDecrypt(encryptedText: string): string {
  try {
    const key = getEncryptionKey();
    // Try to use the old createDecipher method if available (for local development)
    // This is a fallback for data encrypted with the old method
    if (typeof (crypto as any).createDecipher === 'function') {
      const decipher = (crypto as any).createDecipher(ALGORITHM, key);
      let decrypted = decipher.update(encryptedText, 'hex', 'utf8');
      decrypted += decipher.final('utf8');
      return decrypted;
    } else {
      // If old method is not available, we can't decrypt old format
      throw new Error('Cannot decrypt legacy format in this Node.js version');
    }
  } catch (error) {
    throw error;
  }
}

/**
 * Validates if a string is encrypted (contains ':' separator)
 * @param text - Text to validate
 * @returns True if text appears to be encrypted
 */
export function isEncrypted(text: string): boolean {
  return text.includes(':') && text.split(':').length === 2;
}

/**
 * Checks if encrypted text is in legacy format (no IV separator)
 * @param text - Text to check
 * @returns True if text appears to be in legacy format
 */
export function isLegacyEncrypted(text: string): boolean {
  // Legacy format doesn't have ':' separator or has different pattern
  return !text.includes(':') && text.length > 0 && /^[a-f0-9]+$/i.test(text);
}

/**
 * Safely encrypts a password only if it's not already encrypted
 * @param password - Password to encrypt
 * @returns Encrypted password
 */
export function safeEncryptPassword(password: string): string {
  if (isEncrypted(password)) {
    return password; // Already encrypted
  }
  return encrypt(password);
}

/**
 * Migrates legacy encrypted data to new format
 * @param encryptedText - Potentially legacy encrypted text
 * @returns Re-encrypted text in new format
 */
export function migrateEncryption(encryptedText: string): string {
  if (!encryptedText) return '';
  
  try {
    // If it's already in new format, return as-is
    if (isEncrypted(encryptedText)) {
      // Verify it can be decrypted and re-encrypt to ensure consistency
      const decrypted = decrypt(encryptedText);
      return encrypt(decrypted);
    }
    
    // If it's in legacy format, decrypt and re-encrypt
    if (isLegacyEncrypted(encryptedText)) {
      const decrypted = legacyDecrypt(encryptedText);
      return encrypt(decrypted);
    }
    
    // If it's plain text, encrypt it
    return encrypt(encryptedText);
  } catch (error) {
    console.error('Migration error:', error);
    // If migration fails, try to encrypt as plain text
    try {
      return encrypt(encryptedText);
    } catch (encryptError) {
      console.error('Failed to encrypt during migration:', encryptError);
      return encryptedText;
    }
  }
}

/**
 * Test encryption/decryption functionality
 * @param testText - Text to test with
 * @returns Test results
 */
export function testEncryption(testText: string = 'test-password-123') {
  try {
    const encrypted = encrypt(testText);
    const decrypted = decrypt(encrypted);
    
    return {
      success: decrypted === testText,
      original: testText,
      encrypted: encrypted,
      decrypted: decrypted,
      isValid: decrypted === testText,
      format: 'new'
    };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
      format: 'unknown'
    };
  }
}