import crypto from 'crypto';

const algorithm = 'aes-256-gcm';
const saltLength = 64;
const tagLength = 16;
const ivLength = 16;
const iterations = 100000;
const keyLength = 32;

function getKey(): Buffer {
  const key = process.env.NUXT_EMAIL_ENCRYPTION_KEY;
  if (!key || key.length < 32) {
    throw new Error('NUXT_EMAIL_ENCRYPTION_KEY must be at least 32 characters long');
  }
  // Ensure key is exactly 32 bytes
  return Buffer.from(key.substring(0, 32).padEnd(32, '0'));
}

export function encryptCredentials(email: string, password: string): string {
  try {
    const key = getKey();
    const iv = crypto.randomBytes(ivLength);
    const salt = crypto.randomBytes(saltLength);
    
    const derivedKey = crypto.pbkdf2Sync(key, salt, iterations, keyLength, 'sha256');
    const cipher = crypto.createCipheriv(algorithm, derivedKey, iv);
    
    const data = JSON.stringify({ email, password });
    const encrypted = Buffer.concat([
      cipher.update(data, 'utf8'),
      cipher.final()
    ]);
    
    const tag = cipher.getAuthTag();
    
    // Combine salt, iv, tag, and encrypted data
    const combined = Buffer.concat([salt, iv, tag, encrypted]);
    
    return combined.toString('base64');
  } catch (error) {
    throw new Error('Failed to encrypt credentials');
  }
}

export function decryptCredentials(encryptedData: string): { email: string; password: string } {
  try {
    const key = getKey();
    const combined = Buffer.from(encryptedData, 'base64');
    
    // Extract components
    const salt = combined.slice(0, saltLength);
    const iv = combined.slice(saltLength, saltLength + ivLength);
    const tag = combined.slice(saltLength + ivLength, saltLength + ivLength + tagLength);
    const encrypted = combined.slice(saltLength + ivLength + tagLength);
    
    const derivedKey = crypto.pbkdf2Sync(key, salt, iterations, keyLength, 'sha256');
    const decipher = crypto.createDecipheriv(algorithm, derivedKey, iv);
    decipher.setAuthTag(tag);
    
    const decrypted = Buffer.concat([
      decipher.update(encrypted),
      decipher.final()
    ]);
    
    return JSON.parse(decrypted.toString('utf8'));
  } catch (error) {
    throw new Error('Failed to decrypt credentials');
  }
}

// In-memory session storage for credentials (cleared on server restart)
const credentialCache = new Map<string, { credentials: string; timestamp: number }>();
const CACHE_TTL = 30 * 60 * 1000; // 30 minutes

export function storeCredentialsInSession(sessionId: string, encryptedCredentials: string): void {
  credentialCache.set(sessionId, {
    credentials: encryptedCredentials,
    timestamp: Date.now()
  });
  
  // Clean up expired sessions
  cleanupExpiredSessions();
}

export function getCredentialsFromSession(sessionId: string): string | null {
  const session = credentialCache.get(sessionId);
  
  if (!session) {
    return null;
  }
  
  // Check if session is expired
  if (Date.now() - session.timestamp > CACHE_TTL) {
    credentialCache.delete(sessionId);
    return null;
  }
  
  // Update timestamp on access
  session.timestamp = Date.now();
  return session.credentials;
}

export function clearCredentialsFromSession(sessionId: string): void {
  credentialCache.delete(sessionId);
}

function cleanupExpiredSessions(): void {
  const now = Date.now();
  for (const [sessionId, session] of credentialCache.entries()) {
    if (now - session.timestamp > CACHE_TTL) {
      credentialCache.delete(sessionId);
    }
  }
}

// Cleanup expired sessions every 5 minutes
setInterval(cleanupExpiredSessions, 5 * 60 * 1000);
