/**
 * Server-side encryption helper — AES-256-GCM
 *
 * Alur enkripsi:
 *   plaintext → encrypt(AES-256-GCM, key=ENCRYPTION_SECRET) → base64 → simpan di DB
 *
 * Alur dekripsi:
 *   DB → base64 decode → decrypt(AES-256-GCM) → plaintext (hanya di server)
 *
 * Format ciphertext yang disimpan:
 *   base64( iv[12 bytes] + authTag[16 bytes] + ciphertext )
 *
 * PENTING: File ini hanya boleh diimport dari server-side code
 * (API routes, server actions, lib server). TIDAK BOLEH diimport
 * dari komponen client ('use client').
 */

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

const ALGORITHM = "aes-256-gcm";
const IV_LENGTH = 12;    // GCM recommended
const TAG_LENGTH = 16;   // auth tag

/**
 * Derive 32-byte key dari ENCRYPTION_SECRET menggunakan SHA-256.
 * Ini memungkinkan secret berupa string biasa (bukan harus 32 bytes persis).
 */
function getEncryptionKey(): Buffer {
  const secret = process.env.ENCRYPTION_SECRET;
  if (!secret) {
    throw new Error(
      "ENCRYPTION_SECRET tidak ditemukan di environment variables. " +
      "Tambahkan ke .env.local: ENCRYPTION_SECRET=<random-64-char-string>"
    );
  }
  return createHash("sha256").update(secret).digest();
}

/**
 * Enkripsi plaintext → base64(iv + authTag + ciphertext)
 */
export function encrypt(plaintext: string): string {
  const key = getEncryptionKey();
  const iv = randomBytes(IV_LENGTH);

  const cipher = createCipheriv(ALGORITHM, key, iv);
  const encrypted = Buffer.concat([
    cipher.update(plaintext, "utf8"),
    cipher.final(),
  ]);
  const authTag = cipher.getAuthTag();

  // Gabungkan: iv (12) + authTag (16) + ciphertext
  const combined = Buffer.concat([iv, authTag, encrypted]);
  return combined.toString("base64");
}

/**
 * Dekripsi base64(iv + authTag + ciphertext) → plaintext
 */
export function decrypt(ciphertext: string): string {
  const key = getEncryptionKey();
  const combined = Buffer.from(ciphertext, "base64");

  if (combined.length < IV_LENGTH + TAG_LENGTH) {
    throw new Error("Ciphertext terlalu pendek atau corrupt");
  }

  const iv = combined.subarray(0, IV_LENGTH);
  const authTag = combined.subarray(IV_LENGTH, IV_LENGTH + TAG_LENGTH);
  const encrypted = combined.subarray(IV_LENGTH + TAG_LENGTH);

  const decipher = createDecipheriv(ALGORITHM, key, iv);
  decipher.setAuthTag(authTag);

  const decrypted = Buffer.concat([
    decipher.update(encrypted),
    decipher.final(),
  ]);

  return decrypted.toString("utf8");
}

/**
 * Cek apakah string adalah ciphertext valid (bisa didekripsi)
 */
export function isValidCiphertext(value: string): boolean {
  try {
    decrypt(value);
    return true;
  } catch {
    return false;
  }
}

/**
 * Mask value untuk display — tampilkan 4 karakter terakhir saja
 */
export function maskValue(value: string): string {
  if (!value || value.length < 6) return "••••••";
  const visible = Math.min(4, Math.floor(value.length * 0.1));
  return "•".repeat(value.length - visible) + value.slice(-visible);
}

/**
 * Generate random secret yang cocok dipakai sebagai ENCRYPTION_SECRET
 */
export function generateSecret(): string {
  return randomBytes(32).toString("hex"); // 64 hex chars = 256 bits
}
