import crypto from "crypto";
import { safeFetch } from "@/lib/validate-webhook-url";
import { decrypt } from "@/lib/encrypt";

// Secrets created before encryption-at-rest was added are a bare 64-char hex
// string (crypto.randomBytes(32).toString("hex")) with no ":" separators —
// encrypt()'s output is always "iv:authTag:ciphertext". Fall back to treating
// the value as already-plaintext rather than a hard migration, since this is
// only reached with a value this app itself generated (never user input).
export function decryptWebhookSecret(stored: string): string {
  return stored.split(":").length === 3 ? decrypt(stored) : stored;
}

/**
 * Signs and POSTs a single webhook payload. Shared by the per-user
 * (`lib/webhooks.ts`) and admin (`lib/admin-webhooks.ts`) dispatchers so the
 * signing/delivery mechanics — which are security-relevant — live in exactly
 * one place instead of two copies that could drift.
 */
export async function deliverWebhook(
  url: string,
  secret: string,
  event: string,
  payload: object
): Promise<{ statusCode: number; success: boolean }> {
  const body = JSON.stringify({ event, payload, timestamp: new Date().toISOString() });
  const sig = crypto.createHmac("sha256", decryptWebhookSecret(secret)).update(body).digest("hex");

  try {
    // safeFetch resolves and pins the connection to a single validated IP
    // (and re-validates + re-pins every redirect hop), so there's no
    // separate re-resolution for a rebinding attack to exploit.
    const res = await safeFetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Epicure-Signature": `sha256=${sig}`,
        "X-Epicure-Event": event,
      },
      body,
      signal: AbortSignal.timeout(10000),
    });
    return { statusCode: res.status, success: res.ok };
  } catch {
    return { statusCode: 0, success: false };
  }
}
