import crypto from 'crypto';

/**
 * Message Encryption Service
 * Provides encryption/decryption for sensitive messages
 */

const ENCRYPTION_ALGORITHM = 'aes-256-gcm';
const SALT_LENGTH = 16;
const IV_LENGTH = 16;
const AUTH_TAG_LENGTH = 16;

interface EncryptedMessage {
  encryptedContent: string;
  iv: string;
  authTag: string;
  salt: string;
}

interface DecryptedMessage {
  content: string;
  isValid: boolean;
}

/**
 * Derive encryption key from a password/secret
 */
export function deriveKey(secret: string, salt: Buffer): Buffer {
  return crypto.pbkdf2Sync(secret, salt, 100000, 32, 'sha256');
}

/**
 * Encrypt a message
 */
export function encryptMessage(
  content: string,
  encryptionKey: string
): EncryptedMessage {
  // Generate random salt and IV
  const salt = crypto.randomBytes(SALT_LENGTH);
  const iv = crypto.randomBytes(IV_LENGTH);

  // Derive key from encryption key and salt
  const key = deriveKey(encryptionKey, salt);

  // Create cipher
  const cipher = crypto.createCipheriv(ENCRYPTION_ALGORITHM, key, iv);

  // Encrypt content
  let encrypted = cipher.update(content, 'utf8', 'hex');
  encrypted += cipher.final('hex');

  // Get auth tag
  const authTag = cipher.getAuthTag();

  return {
    encryptedContent: encrypted,
    iv: iv.toString('hex'),
    authTag: authTag.toString('hex'),
    salt: salt.toString('hex'),
  };
}

/**
 * Decrypt a message
 */
export function decryptMessage(
  encryptedMessage: EncryptedMessage,
  encryptionKey: string
): DecryptedMessage {
  try {
    // Reconstruct buffers
    const salt = Buffer.from(encryptedMessage.salt, 'hex');
    const iv = Buffer.from(encryptedMessage.iv, 'hex');
    const authTag = Buffer.from(encryptedMessage.authTag, 'hex');

    // Derive key
    const key = deriveKey(encryptionKey, salt);

    // Create decipher
    const decipher = crypto.createDecipheriv(ENCRYPTION_ALGORITHM, key, iv);
    decipher.setAuthTag(authTag);

    // Decrypt content
    let decrypted = decipher.update(encryptedMessage.encryptedContent, 'hex', 'utf8');
    decrypted += decipher.final('utf8');

    return {
      content: decrypted,
      isValid: true,
    };
  } catch (error) {
    console.error('Message decryption failed:', error);
    return {
      content: '',
      isValid: false,
    };
  }
}

/**
 * Generate a random encryption key for a user
 */
export function generateUserEncryptionKey(): string {
  return crypto.randomBytes(32).toString('hex');
}

/**
 * Hash a message for integrity verification
 */
export function hashMessage(content: string): string {
  return crypto.createHash('sha256').update(content).digest('hex');
}

/**
 * Verify message integrity
 */
export function verifyMessageIntegrity(
  content: string,
  hash: string
): boolean {
  return hashMessage(content) === hash;
}

/**
 * Create a message signature
 */
export function signMessage(
  content: string,
  privateKey: string
): string {
  const sign = crypto.createSign('sha256');
  sign.update(content);
  return sign.sign(privateKey, 'hex');
}

/**
 * Verify message signature
 */
export function verifyMessageSignature(
  content: string,
  signature: string,
  publicKey: string
): boolean {
  try {
    const verify = crypto.createVerify('sha256');
    verify.update(content);
    return verify.verify(publicKey, signature, 'hex');
  } catch (error) {
    console.error('Signature verification failed:', error);
    return false;
  }
}

/**
 * Encrypt message for storage
 */
export function encryptForStorage(
  content: string,
  storageKey: string
): string {
  const encrypted = encryptMessage(content, storageKey);
  return JSON.stringify(encrypted);
}

/**
 * Decrypt message from storage
 */
export function decryptFromStorage(
  encryptedData: string,
  storageKey: string
): string {
  try {
    const encrypted = JSON.parse(encryptedData) as EncryptedMessage;
    const decrypted = decryptMessage(encrypted, storageKey);
    return decrypted.isValid ? decrypted.content : '';
  } catch (error) {
    console.error('Storage decryption failed:', error);
    return '';
  }
}

/**
 * Encrypt message for transmission
 */
export function encryptForTransmission(
  content: string,
  recipientPublicKey: string
): string {
  // For transmission, we use a simpler approach with the recipient's public key
  const encrypted = encryptMessage(content, recipientPublicKey);
  return JSON.stringify(encrypted);
}

/**
 * Decrypt message from transmission
 */
export function decryptFromTransmission(
  encryptedData: string,
  recipientPrivateKey: string
): string {
  try {
    const encrypted = JSON.parse(encryptedData) as EncryptedMessage;
    const decrypted = decryptMessage(encrypted, recipientPrivateKey);
    return decrypted.isValid ? decrypted.content : '';
  } catch (error) {
    console.error('Transmission decryption failed:', error);
    return '';
  }
}
