import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';

/**
 * Envelope for a tenant secret sealed with AES-256-GCM. Stored as base64 columns on
 * IiosProviderCredential; the plaintext (a provider config JSON string) never touches disk.
 */
export interface SealedSecret {
  cipherText: string;
  iv: string;
  authTag: string;
  keyVersion: number;
}

/** Bumped only when the platform master key rotates; lets old rows decrypt under an old key. */
export const SECRET_KEY_VERSION = 1;

/**
 * Resolve the 32-byte platform master key from `IIOS_CRED_KEY` (base64). Returns null when
 * unset (so egress providers that need it stay unregistered / fail closed) but THROWS on a
 * present-but-malformed key — a wrong-length key is an operator error, not a "disabled" state.
 */
export function credKeyFromEnv(env: NodeJS.ProcessEnv = process.env): Buffer | null {
  const raw = env.IIOS_CRED_KEY;
  if (!raw) return null;
  const key = Buffer.from(raw, 'base64');
  if (key.length !== 32) throw new Error('IIOS_CRED_KEY must decode to 32 bytes (base64-encoded 256-bit key)');
  return key;
}

export function sealSecret(plaintext: string, key: Buffer): SealedSecret {
  const iv = randomBytes(12);
  const cipher = createCipheriv('aes-256-gcm', key, iv);
  const enc = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
  return {
    cipherText: enc.toString('base64'),
    iv: iv.toString('base64'),
    authTag: cipher.getAuthTag().toString('base64'),
    keyVersion: SECRET_KEY_VERSION,
  };
}

export function openSecret(sealed: SealedSecret, key: Buffer): string {
  const decipher = createDecipheriv('aes-256-gcm', key, Buffer.from(sealed.iv, 'base64'));
  decipher.setAuthTag(Buffer.from(sealed.authTag, 'base64'));
  return Buffer.concat([decipher.update(Buffer.from(sealed.cipherText, 'base64')), decipher.final()]).toString('utf8');
}
