import config from '@/shared/config/config';
import crypto from 'crypto';

const key = Buffer.from(config.tokenEncryptionKey, 'base64'); // must be 32 bytes

interface EncryptedData {
  data: string;
  iv: string;
  tag: string;
}

function encrypt(plaintext: string, tokenLength = 12): EncryptedData {
  const iv = crypto.randomBytes(tokenLength);
  const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
  const encrypted = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();
  return {
    data: encrypted.toString('base64'),
    iv: iv.toString('base64'),
    tag: tag.toString('base64'),
  };
}

function decrypt({ data, iv, tag }: EncryptedData): string {
  if (!data || !iv || !tag) {
    console.error('Decryption failed: Missing data, IV, or tag.');
    // Return an empty string or throw a more specific error
    throw new Error('Missing encryption components (data, iv, or tag).');
  }
  const decipher = crypto.createDecipheriv(
    'aes-256-gcm',
    key,
    Buffer.from(iv, 'base64'),
  );
  decipher.setAuthTag(Buffer.from(tag, 'base64'));
  const decrypted = Buffer.concat([
    decipher.update(Buffer.from(data, 'base64')),
    decipher.final(),
  ]);
  return decrypted.toString('utf8');
}

function encryptAndCombine(plaintext: string): string {
  const { data, iv, tag } = encrypt(plaintext, 6);
  return `${iv}:${data}:${tag}`;
}

function decryptCombined(combinedText: string): string {
  if (!combinedText || typeof combinedText !== 'string')
    throw new Error('Invalid input for decryption.');

  const parts = combinedText.split(':');
  if (parts.length !== 3)
    throw new Error('Invalid combined encryption format.');

  const [iv, data, tag] = parts;

  return decrypt({ data, iv, tag });
}
export { encrypt, decrypt, encryptAndCombine, decryptCombined };
