/**
 * Tiny AES-256-GCM wrapper for storing secrets (Gitea bot PATs, etc.)
 * at rest in Postgres. Layout: base64( iv(12) || ciphertext || authTag(16) ).
 *
 * The key comes from VIBN_SECRETS_KEY. It must be base64 (32 bytes) OR
 * any string we hash down to 32 bytes. We hash with SHA-256 so both
 * forms work — rotating just means generating a new env value and
 * re-provisioning workspaces.
 */

import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto';

const IV_BYTES = 12;

function getKey(): Buffer {
  const raw = process.env.VIBN_SECRETS_KEY;
  if (!raw || raw.length < 16) {
    throw new Error(
      'VIBN_SECRETS_KEY env var is required (>=16 chars) to encrypt workspace secrets'
    );
  }
  // Normalize any input into a 32-byte key via SHA-256.
  return createHash('sha256').update(raw).digest();
}

export function encryptSecret(plain: string): string {
  const key = getKey();
  const iv = randomBytes(IV_BYTES);
  const cipher = createCipheriv('aes-256-gcm', key, iv);
  const enc = Buffer.concat([cipher.update(plain, 'utf8'), cipher.final()]);
  const tag = cipher.getAuthTag();
  return Buffer.concat([iv, enc, tag]).toString('base64');
}

export function decryptSecret(payload: string): string {
  const buf = Buffer.from(payload, 'base64');
  if (buf.length < IV_BYTES + 16) throw new Error('secret-box: payload too short');
  const iv = buf.subarray(0, IV_BYTES);
  const tag = buf.subarray(buf.length - 16);
  const ciphertext = buf.subarray(IV_BYTES, buf.length - 16);
  const key = getKey();
  const decipher = createDecipheriv('aes-256-gcm', key, iv);
  decipher.setAuthTag(tag);
  const dec = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
  return dec.toString('utf8');
}
