import { ambienteFiscal } from "@/lib/fiscal/ambiente";
import { STATUS_QUE_TRAVAM_O_PEDIDO } from "@/lib/fiscal/status";
import { NOME_DO_MODELO, type ModeloFiscal } from "@/lib/spedy/api";
import { createAdminClient } from "@/lib/supabase-server";

import type { Admin } from "./base";
import { cancelarNotaFiscal, descartarPrevia, ErroFiscal } from "./notas";

/**
 * O que a nota fiscal trava no pedido.
 *
 * Nota VALENDO (produção) autorizada ou a caminho congela itens e valores: a
 * nota é um documento que já saiu, e mudar o pedido por baixo dela deixaria os
 * dois contando histórias diferentes. Nota de teste não trava nada.
 */

type NotaQueTrava = { id: string; modelo: ModeloFiscal; status: string; numero: number | null };

export async function notasQueTravamOPedido(pedidoId: string, admin: Admin = createAdminClient()): Promise<NotaQueTrava[]> {
  const { data, error } = await admin
    .from("fiscal_notas")
    .select("id,modelo,status,numero")
    .eq("pedido_id", pedidoId)
    .eq("ambiente_nota", "producao")
    .in("status", STATUS_QUE_TRAVAM_O_PEDIDO);
  if (error) {
    console.error("[fiscal] falha ao conferir notas do pedido", pedidoId, error.message);
    return [];
  }
  return (data ?? []) as NotaQueTrava[];
}

export function mensagemDaTrava(notas: NotaQueTrava[], acao: "mudar" | "cancelar") {
  const nomes = notas.map((nota) => `${NOME_DO_MODELO[nota.modelo]}${nota.numero ? ` nº ${nota.numero}` : ""}`).join(", ");
  const andando = notas.some((nota) => nota.status !== "autorizada");
  if (acao === "cancelar") {
    return andando
      ? `A nota fiscal deste pedido (${nomes}) ainda está sendo processada. Aguarde a autorização e cancele a nota antes de cancelar o pedido.`
      : `Este pedido tem nota fiscal autorizada (${nomes}). Cancele a nota na aba Financeiro antes de cancelar o pedido.`;
  }
  return `Este pedido tem nota fiscal emitida (${nomes}). Para mudar itens ou valores, cancele a nota antes.`;
}

/**
 * Cancelar a venda do PDV cancela a NFC-e junto. Se a nota não puder ser
 * cancelada (prazo da SEFAZ, contingência, ainda processando), a venda fica
 * como está e a mensagem diz por quê.
 */
export async function cancelarNotasDaVenda(input: { empresaId: string; pedidoId: string; usuarioId: string | null }) {
  const admin = createAdminClient();
  const { data, error } = await admin
    .from("fiscal_notas")
    .select("id,modelo,status,numero,ambiente")
    .eq("pedido_id", input.pedidoId)
    .eq("empresa_id", input.empresaId)
    .eq("ambiente", ambienteFiscal())
    .not("status", "in", "(cancelada,removida,denegada)");
  if (error) throw new ErroFiscal("Não foi possível conferir a nota fiscal da venda.", 500);
  const notas = (data ?? []) as Array<{ id: string; modelo: ModeloFiscal; status: string; numero: number | null }>;

  const andando = notas.find((nota) => ["preparando", "enviando", "processando", "cancelando"].includes(nota.status));
  if (andando) {
    throw new ErroFiscal("A nota fiscal desta venda ainda está sendo processada. Aguarde um instante e tente cancelar de novo.", 409);
  }
  if (notas.some((nota) => nota.status === "contingencia")) {
    throw new ErroFiscal("A NFC-e desta venda está em contingência. Ela só pode ser cancelada depois que a SEFAZ confirmar.", 409);
  }

  const canceladas: string[] = [];
  for (const nota of notas) {
    if (nota.status === "autorizada") {
      try {
        await cancelarNotaFiscal(admin, {
          empresaId: input.empresaId,
          notaId: nota.id,
          motivo: "Venda cancelada no ponto de venda a pedido do cliente",
          usuarioId: input.usuarioId,
        });
        canceladas.push(nota.id);
      } catch (erro) {
        const motivo = erro instanceof Error ? erro.message : "a SEFAZ recusou";
        throw new ErroFiscal(
          `A ${NOME_DO_MODELO[nota.modelo]}${nota.numero ? ` nº ${nota.numero}` : ""} não pôde ser cancelada (${motivo}). A venda continua ativa.`,
          409
        );
      }
    } else if (["rascunho", "rejeitada", "erro"].includes(nota.status)) {
      await descartarPrevia(admin, { empresaId: input.empresaId, notaId: nota.id, usuarioId: input.usuarioId }).catch(() => undefined);
    }
  }
  return { canceladas };
}
