/**
 * Server-side encryption service using AES-256-GCM.
 * Only import this in server-side code (API routes).
 *
 * Format: enc:v1:<iv-hex>:<authTag-hex>:<ciphertext-hex>
 */
import {
  createCipheriv,
  createDecipheriv,
  randomBytes,
  pbkdf2Sync,
} from "crypto";

const ALGORITHM = "aes-256-gcm";
const IV_LENGTH = 12; // 96 bits recommended for GCM
const TAG_LENGTH = 16; // 128 bits
const PREFIX = "enc:v1:";

/** Derive a 256-bit key from the secret using PBKDF2 */
function deriveKey(secret: string): Buffer {
  // Fixed salt — acceptable because the secret itself is high-entropy
  const salt = Buffer.from("architools-vault-v1", "utf8");
  return pbkdf2Sync(secret, salt, 100_000, 32, "sha256");
}

function getKey(): Buffer {
  const secret = process.env.ENCRYPTION_SECRET;
  if (!secret || secret.length < 16) {
    throw new Error(
      "ENCRYPTION_SECRET environment variable must be set (min 16 chars)",
    );
  }
  return deriveKey(secret);
}

/** Encrypt a plaintext string. Returns prefixed format. */
export function encrypt(plaintext: string): string {
  const key = getKey();
  const iv = randomBytes(IV_LENGTH);
  const cipher = createCipheriv(ALGORITHM, key, iv, {
    authTagLength: TAG_LENGTH,
  });

  let encrypted = cipher.update(plaintext, "utf8", "hex");
  encrypted += cipher.final("hex");
  const authTag = cipher.getAuthTag().toString("hex");

  return `${PREFIX}${iv.toString("hex")}:${authTag}:${encrypted}`;
}

/** Decrypt a previously encrypted string. Handles both encrypted and plaintext (migration). */
export function decrypt(value: string): string {
  // If not encrypted (legacy plaintext), return as-is
  if (!value.startsWith(PREFIX)) {
    return value;
  }

  const key = getKey();
  const parts = value.slice(PREFIX.length).split(":");
  if (parts.length !== 3) {
    throw new Error("Invalid encrypted format");
  }
  const [ivHex, authTagHex, ciphertext] = parts;
  if (!ivHex || !authTagHex || !ciphertext) {
    throw new Error("Invalid encrypted format: missing parts");
  }

  const iv = Buffer.from(ivHex, "hex");
  const authTag = Buffer.from(authTagHex, "hex");
  const decipher = createDecipheriv(ALGORITHM, key, iv, {
    authTagLength: TAG_LENGTH,
  });
  decipher.setAuthTag(authTag);

  let decrypted = decipher.update(ciphertext, "hex", "utf8");
  decrypted += decipher.final("utf8");
  return decrypted;
}

/** Check if a value is already encrypted */
export function isEncrypted(value: string): boolean {
  return value.startsWith(PREFIX);
}
