import { describe, it, expect, vi, beforeEach } from "vitest";
import { createHmac } from "node:crypto";

const { envMock } = vi.hoisted(() => ({
  envMock: { WAHA_HMAC_SECRET: "", WAHA_WEBHOOK_REQUIRE_SIGNATURE: "false" },
}));
vi.mock("@/lib/env", () => ({ env: envMock }));

import { authenticateWahaWebhook } from "./webhook-auth";

const BODY = '{"event":"message","session":"org_1","payload":{"id":"x"}}';
const SEGREDO = "2997fd3bb5b53732742e721fffa3bd4a1282b35a105e0b21fd6efa582d6b0f3b";
const assina = (b: string, s: string) => createHmac("sha512", s).update(b, "utf8").digest("hex");

describe("authenticateWahaWebhook", () => {
  beforeEach(() => {
    envMock.WAHA_HMAC_SECRET = "";
    envMock.WAHA_WEBHOOK_REQUIRE_SIGNATURE = "false";
  });

  it("REJEITA assinatura errada — o buraco que deixava injetar mensagem falsa", () => {
    // Reproduz o ataque: POST com X-Webhook-Hmac de zeros. Antes o handler
    // marcava hmacSkipped e gravava a mensagem no banco assim mesmo.
    envMock.WAHA_HMAC_SECRET = SEGREDO;
    const r = authenticateWahaWebhook({
      rawBody: BODY, signatureHeader: "0".repeat(64), sessionSecret: null,
    });
    expect(r).toEqual({ ok: false, reason: "bad_signature" });
  });

  it("REJEITA assinatura quando não há segredo para conferir", () => {
    // Confiar no que não dá para verificar era o defeito de origem.
    const r = authenticateWahaWebhook({
      rawBody: BODY, signatureHeader: assina(BODY, SEGREDO), sessionSecret: null,
    });
    expect(r).toEqual({ ok: false, reason: "bad_signature" });
  });

  it("aceita assinatura correta com o segredo do ambiente", () => {
    envMock.WAHA_HMAC_SECRET = SEGREDO;
    const r = authenticateWahaWebhook({
      rawBody: BODY, signatureHeader: assina(BODY, SEGREDO), sessionSecret: null,
    });
    expect(r).toEqual({ ok: true, signatureVerified: true });
  });

  it("prefere o segredo da sessão quando ele é real", () => {
    envMock.WAHA_HMAC_SECRET = SEGREDO;
    const daSessao = "a".repeat(32);
    const r = authenticateWahaWebhook({
      rawBody: BODY, signatureHeader: assina(BODY, daSessao), sessionSecret: daSessao,
    });
    expect(r).toEqual({ ok: true, signatureVerified: true });
  });

  it("ignora segredo de sessão curto demais (o placeholder de 1 byte)", () => {
    // As rotas que criam sessão gravam Buffer.from([0]); decifrar isso devolve
    // lixo curto, que não pode ser tratado como segredo.
    envMock.WAHA_HMAC_SECRET = SEGREDO;
    const r = authenticateWahaWebhook({
      rawBody: BODY, signatureHeader: assina(BODY, SEGREDO), sessionSecret: " ",
    });
    expect(r).toEqual({ ok: true, signatureVerified: true });
  });

  it("sem assinatura: aceita, mas diz que NÃO verificou (o log grava a verdade)", () => {
    // WAHA Core não assina — exigir aqui derrubaria a ingestão de todo mundo.
    const r = authenticateWahaWebhook({ rawBody: BODY, signatureHeader: null, sessionSecret: null });
    expect(r).toEqual({ ok: true, signatureVerified: false });
  });

  it("com REQUIRE_SIGNATURE=true, sem assinatura é rejeitado", () => {
    envMock.WAHA_HMAC_SECRET = SEGREDO;
    envMock.WAHA_WEBHOOK_REQUIRE_SIGNATURE = "true";
    const r = authenticateWahaWebhook({ rawBody: BODY, signatureHeader: null, sessionSecret: null });
    expect(r).toEqual({ ok: false, reason: "signature_required" });
  });

  it("corpo adulterado com assinatura do corpo original é rejeitado", () => {
    envMock.WAHA_HMAC_SECRET = SEGREDO;
    const r = authenticateWahaWebhook({
      rawBody: BODY.replace("message", "message.any"),
      signatureHeader: assina(BODY, SEGREDO),
      sessionSecret: null,
    });
    expect(r).toEqual({ ok: false, reason: "bad_signature" });
  });
});
