// ── Secret-at-rest encryption (AES-256-GCM) ────────────────────────────────
//
// Used to encrypt OAuth client secrets before they are written to the DB, so a
// database read alone does not yield usable provider credentials. Output format
// is `iv:tag:ciphertext`, each part base64. GCM provides authenticated
// encryption, so tampering is detected on decrypt.
//
// The key comes from SECRET_ENC_KEY (any string — it is hashed to 32 bytes). In
// development, if unset, we derive a key from JWT_SECRET with a loud warning
// (mirrors token.resolveJwtSecret) so local dev works; production must set a
// dedicated key so rotating JWT_SECRET does not silently orphan stored secrets.

const crypto = require('crypto')
require('dotenv').config()

const log = require('../utils/logger')('secretbox')

const ALGO = 'aes-256-gcm'

function resolveKey() {
  const explicit = process.env.SECRET_ENC_KEY
  if (explicit) return crypto.createHash('sha256').update(explicit).digest()
  if (process.env.NODE_ENV === 'production') {
    throw new Error('SECRET_ENC_KEY must be set in production')
  }
  const jwt = process.env.JWT_SECRET || 'dev-insecure-jwt-secret-do-not-use-in-production'
  log.warn('SECRET_ENC_KEY is not set — deriving an insecure key from JWT_SECRET for development. Set SECRET_ENC_KEY before deploying.')
  return crypto.createHash('sha256').update(`secretbox:${jwt}`).digest()
}

const KEY = resolveKey()

// Encrypt a UTF-8 string → "iv:tag:ct" (base64 parts). Returns null for empty input.
function encrypt(plaintext) {
  if (plaintext == null || plaintext === '') return null
  const iv = crypto.randomBytes(12)
  const cipher = crypto.createCipheriv(ALGO, KEY, iv)
  const ct = Buffer.concat([cipher.update(String(plaintext), 'utf8'), cipher.final()])
  const tag = cipher.getAuthTag()
  return `${iv.toString('base64')}:${tag.toString('base64')}:${ct.toString('base64')}`
}

// Decrypt a value produced by encrypt(). Returns null for null/blank input;
// throws if the payload is malformed or fails authentication (tampered/wrong key).
function decrypt(payload) {
  if (payload == null || payload === '') return null
  const parts = String(payload).split(':')
  if (parts.length !== 3) throw new Error('secretBox: malformed ciphertext')
  const [iv, tag, ct] = parts.map((p) => Buffer.from(p, 'base64'))
  const decipher = crypto.createDecipheriv(ALGO, KEY, iv)
  decipher.setAuthTag(tag)
  return Buffer.concat([decipher.update(ct), decipher.final()]).toString('utf8')
}

module.exports = { encrypt, decrypt }
