/**
 * webhooks.ts
 *
 * Sistema de despacho de webhooks inspirado en OpenWA (webhook.service.ts).
 * Características:
 * - Firma HMAC-SHA256 en cada request (header X-Webhook-Signature)
 * - Reintentos automáticos con backoff exponencial (3 intentos)
 * - Filtrado por nombre de evento ("*" = todos los eventos)
 * - Fire-and-forget: no bloquea el flujo principal del bot
 */

import crypto from "node:crypto";
import { getActiveWebhooks } from "./db";

export interface WebhookPayload {
  event: string;
  data: Record<string, unknown>;
  timestamp: string;
}

/**
 * Despacha un evento a todos los webhooks activos registrados en la DB.
 * Cada webhook recibe el payload firmado con su secret (si tiene uno).
 *
 * @param event - Nombre del evento (ej: "message.received", "session.status")
 * @param data  - Datos del evento
 */
export async function dispatchWebhook(
  event: string,
  data: Record<string, unknown>
): Promise<void> {
  let webhooks: ReturnType<typeof getActiveWebhooks>;
  try {
    webhooks = getActiveWebhooks();
  } catch {
    return; // DB no disponible aún, ignorar silenciosamente
  }

  if (webhooks.length === 0) return;

  const payload: WebhookPayload = {
    event,
    data,
    timestamp: new Date().toISOString(),
  };
  const body = JSON.stringify(payload);

  // Despachar a todos los webhooks en paralelo (fire-and-forget)
  await Promise.allSettled(
    webhooks
      .filter((wh) => {
        // Filtrar por lista de eventos soportados
        let events: string[] = ["*"];
        try { events = JSON.parse(wh.events); } catch {}
        return events.includes("*") || events.includes(event);
      })
      .map((wh) => sendWithRetry(wh.url, body, wh.secret, event))
  );
}

/**
 * Envía el webhook con reintentos (hasta MAX_RETRIES veces).
 * Usa backoff exponencial: 1s, 2s, 4s entre reintentos.
 */
async function sendWithRetry(
  url: string,
  body: string,
  secret: string | null,
  event: string,
  attempt = 1
): Promise<void> {
  const MAX_RETRIES = 3;
  const headers: Record<string, string> = {
    "Content-Type": "application/json",
    "X-Webhook-Event": event,
    "User-Agent": "agente-whatsapp/1.1.0",
  };

  // Firmar el payload con HMAC-SHA256 si hay un secret configurado
  if (secret) {
    const signature = crypto
      .createHmac("sha256", secret)
      .update(body)
      .digest("hex");
    headers["X-Webhook-Signature"] = `sha256=${signature}`;
  }

  try {
    const response = await fetch(url, {
      method: "POST",
      headers,
      body,
      signal: AbortSignal.timeout(10_000), // Timeout de 10 segundos
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
  } catch (err: any) {
    if (attempt < MAX_RETRIES) {
      const delay = Math.pow(2, attempt - 1) * 1000; // 1s, 2s, 4s
      console.warn(
        `[webhook] ⚠️  Intento ${attempt}/${MAX_RETRIES} fallido para ${url}: ${err?.message}. Reintentando en ${delay}ms...`
      );
      await new Promise((resolve) => setTimeout(resolve, delay));
      return sendWithRetry(url, body, secret, event, attempt + 1);
    } else {
      console.error(
        `[webhook] ✘ Falló definitivamente después de ${MAX_RETRIES} intentos para ${url}: ${err?.message}`
      );
    }
  }
}
