import { createHmac, timingSafeEqual } from "node:crypto";

const SECRET_ENV = "BB_PIX_SECRET";

function getSecret(): string {
  const s = process.env[SECRET_ENV];
  if (!s || s.length < 16) {
    throw new Error(`${SECRET_ENV} env var missing or too short (need 16+ chars)`);
  }
  return s;
}

function b64urlEncode(buf: Buffer): string {
  return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

function b64urlDecode(s: string): Buffer {
  const pad = s.length % 4 ? "=".repeat(4 - (s.length % 4)) : "";
  return Buffer.from(s.replace(/-/g, "+").replace(/_/g, "/") + pad, "base64");
}

/**
 * Sign a tracked-email id into a compact URL-safe token. The recipient never
 * sees the raw uuid — they see /pix/<token>.png and we recover the id by
 * verifying the HMAC. Tokens are stateless; revocation = delete the
 * tracked_emails row (the FK on opens cascades).
 */
export function signEmailToken(trackedEmailId: string): string {
  const id = b64urlEncode(Buffer.from(trackedEmailId.replace(/-/g, ""), "hex"));
  const sig = createHmac("sha256", getSecret()).update(id).digest();
  const shortSig = b64urlEncode(sig.subarray(0, 12));
  return `${id}.${shortSig}`;
}

export function verifyEmailToken(token: string): string | null {
  const dot = token.indexOf(".");
  if (dot < 1) return null;
  const id = token.slice(0, dot);
  const provided = token.slice(dot + 1);
  const expected = b64urlEncode(
    createHmac("sha256", getSecret()).update(id).digest().subarray(0, 12),
  );
  const a = Buffer.from(provided);
  const b = Buffer.from(expected);
  if (a.length !== b.length) return null;
  if (!timingSafeEqual(a, b)) return null;
  const hex = b64urlDecode(id).toString("hex");
  if (hex.length !== 32) return null;
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}

export function pixelUrl(trackedEmailId: string, baseUrl = "https://avbeat.com"): string {
  return `${baseUrl.replace(/\/+$/, "")}/pix/${signEmailToken(trackedEmailId)}.png`;
}
