/**
 * ابزارهای رمزنگاری سمت سرور:
 * توکن تصادفی، هش توکن، HMAC کد OTP، مقایسه امن و رمزگذاری AES-256-GCM برای داده‌های حساس.
 */
import "server-only";
import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes, randomInt, timingSafeEqual } from "node:crypto";
import { env } from "./env";

/** توکن تصادفی امن (برای کوکی نشست) */
export function randomToken(bytes = 32): string {
  return randomBytes(bytes).toString("base64url");
}

/** هش SHA-256 (فقط هش توکن در دیتابیس ذخیره می‌شود) */
export function sha256(value: string): string {
  return createHash("sha256").update(value).digest("hex");
}

/** HMAC با کلید سرور (برای کد OTP تا با نشت دیتابیس قابل حدس نباشد) */
export function hmac(value: string): string {
  return createHmac("sha256", env().SESSION_SECRET).update(value).digest("hex");
}

export function safeEqual(a: string, b: string): boolean {
  const ab = Buffer.from(a);
  const bb = Buffer.from(b);
  return ab.length === bb.length && timingSafeEqual(ab, bb);
}

/** کد عددی تصادفی امن با طول مشخص */
export function randomDigits(length: number): string {
  return Array.from({ length }, () => randomInt(0, 10)).join("");
}

// ── رمزگذاری متقارن (AES-256-GCM) ─────────────────────────
// قالب خروجی: v1.<iv>.<tag>.<ciphertext> (همه base64url)

function key() {
  return Buffer.from(env().DATA_ENCRYPTION_KEY, "base64");
}

export function encrypt(plain: string): string {
  const iv = randomBytes(12);
  const cipher = createCipheriv("aes-256-gcm", key(), iv);
  const data = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
  return ["v1", iv.toString("base64url"), cipher.getAuthTag().toString("base64url"), data.toString("base64url")].join(".");
}

export function decrypt(payload: string): string {
  const [version, iv, tag, data] = payload.split(".");
  if (version !== "v1" || !iv || !tag || !data) throw new Error("قالب داده رمزگذاری‌شده نامعتبر است");
  const decipher = createDecipheriv("aes-256-gcm", key(), Buffer.from(iv, "base64url"));
  decipher.setAuthTag(Buffer.from(tag, "base64url"));
  return Buffer.concat([decipher.update(Buffer.from(data, "base64url")), decipher.final()]).toString("utf8");
}
