import crypto from "node:crypto";

const ALGO = "aes-256-gcm";
const IV_LEN = 12;
const TAG_LEN = 16;

function readKey(envName: string): Buffer {
  const hex = process.env[envName];
  if (!hex) throw new Error(`Missing env ${envName}`);
  if (hex.length !== 64) {
    throw new Error(`${envName} must be 64 hex chars (32 bytes)`);
  }
  return Buffer.from(hex, "hex");
}

function getEncKey(): Buffer {
  return readKey("KYC_ENCRYPTION_KEY");
}

function getNikPepper(): Buffer {
  return readKey("KYC_NIK_PEPPER");
}

/** Encrypt a Buffer with AES-256-GCM. Output layout: [iv(12) | tag(16) | ciphertext]. */
export function encryptBuffer(plain: Buffer): Buffer {
  const iv = crypto.randomBytes(IV_LEN);
  const cipher = crypto.createCipheriv(ALGO, getEncKey(), iv);
  const ct = Buffer.concat([cipher.update(plain), cipher.final()]);
  const tag = cipher.getAuthTag();
  return Buffer.concat([iv, tag, ct]);
}

export function decryptBuffer(blob: Buffer): Buffer {
  if (blob.length < IV_LEN + TAG_LEN) throw new Error("Ciphertext too short");
  const iv = blob.subarray(0, IV_LEN);
  const tag = blob.subarray(IV_LEN, IV_LEN + TAG_LEN);
  const ct = blob.subarray(IV_LEN + TAG_LEN);
  const decipher = crypto.createDecipheriv(ALGO, getEncKey(), iv);
  decipher.setAuthTag(tag);
  return Buffer.concat([decipher.update(ct), decipher.final()]);
}

/** Encrypt UTF-8 string -> base64 string. Used for short PII like NIK. */
export function encryptString(plain: string): string {
  return encryptBuffer(Buffer.from(plain, "utf8")).toString("base64");
}

export function decryptString(b64: string): string {
  return decryptBuffer(Buffer.from(b64, "base64")).toString("utf8");
}

/** Deterministic HMAC-SHA256 of a normalized value, hex-encoded. Used for unique-lookup of NIK without storing plaintext. */
export function hmacHex(value: string): string {
  return crypto.createHmac("sha256", getNikPepper()).update(value).digest("hex");
}
