import {
  createCipheriv,
  createDecipheriv,
  randomBytes,
  hkdfSync,
} from "crypto";

const ALGORITHM = "aes-256-gcm";

// Static salt — committed to source so it is stable across deployments.
// It does NOT need to be secret; its purpose is domain-separation and to
// prevent the raw secret from being used directly as a key.
const HKDF_SALT = Buffer.from("epicure-encryption-v1-salt", "utf8");
const HKDF_INFO = Buffer.from("epicure-aes-256-gcm-key", "utf8");

function getKey(): Buffer {
  // Prefer a dedicated encryption secret; fall back to BETTER_AUTH_SECRET so
  // existing deployments keep working without an immediate migration.
  const secret =
    process.env["ENCRYPTION_SECRET"] ?? process.env["BETTER_AUTH_SECRET"];
  if (!secret) throw new Error("ENCRYPTION_SECRET (or BETTER_AUTH_SECRET) is required");

  // HKDF-SHA256 provides proper key derivation with domain separation.
  // This replaces the previous raw SHA-256 hash which offered no stretching
  // or salt, making brute-force against leaked ciphertexts trivial.
  return Buffer.from(
    hkdfSync("sha256", secret, HKDF_SALT, HKDF_INFO, 32)
  );
}

export function encrypt(plaintext: string): string {
  const key = getKey();
  const iv = randomBytes(12);
  const cipher = createCipheriv(ALGORITHM, key, iv);
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
  const authTag = (cipher as ReturnType<typeof createCipheriv> & { getAuthTag(): Buffer }).getAuthTag();
  return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted.toString("hex")}`;
}

export function decrypt(ciphertext: string): string {
  const parts = ciphertext.split(":");
  if (parts.length !== 3) throw new Error("Invalid ciphertext format");
  const [ivHex, authTagHex, encryptedHex] = parts as [string, string, string];
  const key = getKey();
  const iv = Buffer.from(ivHex, "hex");
  const authTag = Buffer.from(authTagHex, "hex");
  const encrypted = Buffer.from(encryptedHex, "hex");
  const decipher = createDecipheriv(ALGORITHM, key, iv);
  (decipher as ReturnType<typeof createDecipheriv> & { setAuthTag(tag: Buffer): void }).setAuthTag(authTag);
  return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
}
