/**
 * AES-256-GCM for IMAP passwords. ENCRYPTION_KEY = 64 hex chars (32 bytes).
 * Legacy: if decrypt fails or key missing, value treated as plaintext.
 */

import crypto from 'crypto'

const ALGO = 'aes-256-gcm'
const IV_LEN = 16
const AUTH_TAG_LEN = 16

function getKeyBuffer() {
  const hex = process.env.ENCRYPTION_KEY || ''
  if (hex.length !== 64) {
    throw new Error('ENCRYPTION_KEY must be 64 hex characters (32 bytes). Generate: openssl rand -hex 32')
  }
  return Buffer.from(hex, 'hex')
}

export function encrypt(text) {
  if (text == null || text === '') return ''
  const key = getKeyBuffer()
  const iv = crypto.randomBytes(IV_LEN)
  const cipher = crypto.createCipheriv(ALGO, key, iv, { authTagLength: AUTH_TAG_LEN })
  const enc = Buffer.concat([cipher.update(String(text), 'utf8'), cipher.final()])
  const authTag = cipher.getAuthTag()
  const combined = Buffer.concat([iv, authTag, enc])
  return combined.toString('base64url')
}

export function decrypt(encoded) {
  if (!encoded) return ''
  const buf = Buffer.from(String(encoded), 'base64url')
  if (buf.length < IV_LEN + AUTH_TAG_LEN + 1) {
    throw new Error('invalid ciphertext')
  }
  const key = getKeyBuffer()
  const iv = buf.subarray(0, IV_LEN)
  const authTag = buf.subarray(IV_LEN, IV_LEN + AUTH_TAG_LEN)
  const data = buf.subarray(IV_LEN + AUTH_TAG_LEN)
  const decipher = crypto.createDecipheriv(ALGO, key, iv, { authTagLength: AUTH_TAG_LEN })
  decipher.setAuthTag(authTag)
  return Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8')
}

/** Encrypt IMAP password when ENCRYPTION_KEY is set; otherwise store plaintext. */
export function encryptImapSecret(plain) {
  if (plain == null || plain === '') return ''
  if (!process.env.ENCRYPTION_KEY) return String(plain)
  try {
    return encrypt(plain)
  } catch (e) {
    logWarnOnce('encryptImapSecret', e.message)
    return String(plain)
  }
}

/** Decrypt IMAP secret; on failure return as plaintext (legacy). */
export function decryptImapSecret(stored) {
  if (stored == null || stored === '') return ''
  if (!process.env.ENCRYPTION_KEY) return String(stored)
  try {
    return decrypt(stored)
  } catch {
    return String(stored)
  }
}

let warnedEncrypt = false
function logWarnOnce(tag, msg) {
  if (warnedEncrypt) return
  warnedEncrypt = true
  console.warn(`[crypto] ${tag}: ${msg}`)
}
