import { createHash } from "node:crypto";

import { NextResponse } from "next/server";

import { assinaturaValida, segredoDoCorpoValido } from "@/lib/assinatura-cakto";
import { processarEntrega, registrarAviso } from "@/lib/assinatura-cakto-servidor";
import { createAdminClient } from "@/lib/supabase-server";

export const runtime = "nodejs";

/**
 * A rota oficial dos avisos da Cakto para a assinatura da Ktalogu.
 *
 * - A origem é conferida pela assinatura do cabeçalho (`X-Cakto-Signature`,
 *   HMAC do timestamp + corpo cru). Sem o cabeçalho, vale o `secret` do corpo.
 * - Todo aviso é gravado e a resposta 200 sai logo depois; aplicar vem em
 *   seguida, no mesmo processo. A Cakto desiste em 8 segundos, e aplicar pode
 *   passar disso. Se aplicar falhar, quem tenta de novo é o nosso relógio, a
 *   partir do que ficou gravado.
 * - Só responde erro quando nem gravar deu: aí a conciliação diária, que lê o
 *   histórico de entregas da Cakto, recupera o aviso.
 */
export async function POST(req: Request) {
  const segredo = String(process.env.CAKTO_WEBHOOK_SECRET || "").trim();
  if (!segredo) return NextResponse.json({ error: "Rota não configurada." }, { status: 503 });

  const corpoCru = await req.text();
  let corpo: unknown;
  try {
    corpo = JSON.parse(corpoCru);
  } catch {
    return NextResponse.json({ error: "Corpo inválido." }, { status: 400 });
  }

  const assinatura = req.headers.get("x-cakto-signature") || "";
  const timestamp = req.headers.get("x-cakto-timestamp") || "";
  const origemConfere = assinatura
    ? assinaturaValida(corpoCru, timestamp, assinatura, segredo)
    : segredoDoCorpoValido(corpo, segredo);
  if (!origemConfere) return NextResponse.json({ error: "Origem não confere." }, { status: 401 });

  const chaveSemPedido = `sem-pedido:${createHash("sha256").update(corpoCru).digest("hex")}`;
  try {
    const admin = createAdminClient();
    const { entrega, aviso } = await registrarAviso(admin, corpo, chaveSemPedido);
    if (entrega.jaFeita) return NextResponse.json({ ok: true, repetido: true });
    void processarEntrega(admin, entrega, aviso, corpo).then(({ erro }) => {
      if (erro) console.error("[cakto] aviso gravado, aplicação falhou; o relógio tenta de novo", entrega.id, erro);
    });
    return NextResponse.json({ ok: true, recebido: true });
  } catch (e) {
    console.error("[cakto] não foi possível gravar o aviso", e instanceof Error ? e.message : e);
    return NextResponse.json({ error: "Não foi possível gravar o aviso." }, { status: 500 });
  }
}
