/**
 * ESTORNAR a comanda.
 *
 * Estorno não é o desfazer de cancelar: cancelar vale para comanda ABERTA, que
 * ainda não virou nada; estornar vale para a FINALIZADA, que já virou
 * lançamento, comissão e ponto. Por isso são duas operações e não um botão com
 * dois sentidos.
 *
 * E estorno **nunca apaga**. `fn_estornar_comanda` insere o contra-lançamento e
 * deixa o original intacto — ele está pago, e o trigger `fn_lancamento_pago_e_
 * imutavel` recusaria a alteração de qualquer forma. A comissão vira
 * `reversed`, e não some, porque ela existiu e alguém pode já ter sido pago por
 * ela.
 *
 * ⚠️ Exige `manager`, um degrau acima de finalizar. Desfazer dinheiro que já
 * entrou é decisão de quem responde pelo caixa, não de quem opera o balcão — e
 * quem impõe isso é a própria função, no banco.
 */
import { randomUUID } from "node:crypto";

import type { NextRequest } from "next/server";

import { ok, fail } from "@/lib/api/wrappers";
import { audit } from "@/lib/audit";
import { requireRole } from "@/lib/auth/require-role";
import { estornarSchema } from "@/lib/financeiro/comanda";
import { requireSupportWrite } from "@/lib/impersonate/support";
import { moduloLigado } from "@/lib/instalacao/modulos";
import { createAdminClient } from "@/lib/supabase/admin";
import { createClient } from "@/lib/supabase/server";

export const dynamic = "force-dynamic";

type Ctx = { params: Promise<{ id: string }> };

function traduzirErro(mensagem: string): { code: string; status: number; texto: string } | null {
  if (mensagem.includes("estorno_forbidden")) {
    return {
      code: "forbidden",
      status: 403,
      texto: "Estornar uma comanda exige perfil de gerente.",
    };
  }
  if (mensagem.includes("comanda_nao_encontrada")) {
    return { code: "not_found", status: 404, texto: "Comanda não encontrada." };
  }
  if (mensagem.includes("comanda_nao_finalizada")) {
    return {
      code: "conflict",
      status: 409,
      texto: "Só comanda finalizada pode ser estornada. Comanda aberta se cancela.",
    };
  }
  return null;
}

export async function POST(req: NextRequest, ctx: Ctx): Promise<Response> {
  const requestId = randomUUID();
  // #1907 item 4 — comanda é MÓDULO DE TABELA: sem `modulos_instalados` a
  // linha ativa as cinco tabelas não existem e a rota não existe. 404,
  // mesmo molde da cobrança desligada (falha fechada, dois lados).
  const admin = createAdminClient();
  if (!(await moduloLigado(admin, "financeiro"))) return fail("not_found", "Not found", 404, { requestId });
  const supportDenied = await requireSupportWrite();
  if (supportDenied) return supportDenied;

  const authz = await requireRole("manager", { requestId, resource: "financeiro" });
  if (!authz.ok) return authz.response;

  const lido = estornarSchema.safeParse(await req.json().catch(() => ({})));
  if (!lido.success) {
    return fail(
      "validation_failed",
      // O motivo é obrigatório porque um estorno sem motivo é um buraco no caixa
      // que ninguém consegue explicar três meses depois.
      lido.error.issues[0]?.message ?? "Informe o motivo do estorno.",
      422,
      { requestId },
    );
  }

  const { id } = await ctx.params;
  const supabase = await createClient();

  const { data, error } = await supabase.rpc("fn_estornar_comanda", {
    p_org: authz.org.orgId,
    p_sale: id,
    p_motivo: lido.data.reason,
  });

  if (error) {
    const traduzido = traduzirErro(error.message);
    if (traduzido) {
      return fail(traduzido.code as never, traduzido.texto, traduzido.status as never, { requestId });
    }
    return fail("internal_error", error.message, 500, { requestId });
  }

  const desfecho = (data ?? {}) as { sale_id?: string; ja_estornada?: boolean };

  if (!desfecho.ja_estornada) {
    // ⚠️ O MOTIVO NÃO ENTRA NO AUDIT. Ele é texto livre de até 500 caracteres
    // que uma pessoa escreve sobre outra ("estornado porque a paciente passou
    // mal com o procedimento"), e `lib/audit` grava `metadata` cru em
    // `api_audit_log` — tabela de retenção longa que a cascata de anonimização
    // da LGPD não alcança, porque nenhum papel tem GRANT de UPDATE/DELETE nela,
    // nem `service_role`. Anonimizar o titular redigiria `sales.reverse_reason`
    // e deixaria a mesma frase viva aqui, para sempre.
    //
    // O motivo continua GUARDADO onde a LGPD chega: `fn_estornar_comanda` o
    // grava em `sales.reverse_reason`. O audit só precisa provar que houve
    // motivo — que é o que a obrigatoriedade do campo existe para garantir.
    await audit({
      action: "comanda.estornada",
      resourceType: "sale",
      resourceId: id,
      requestId,
      metadata: { motivo_informado: true, motivo_chars: lido.data.reason.length },
    });
  }

  return ok(desfecho, { requestId });
}
