/**
 * O motivo de uma rejeição, em palavras de quem opera o balcão.
 *
 * A mensagem original da SEFAZ ou da prefeitura continua aparecendo (é a fonte
 * mais confiável), mas "Rejeicao: IE do destinatario nao cadastrada" não diz o
 * que fazer. Aqui cada código comum ganha um título curto, a dica do conserto e
 * onde consertar. Código que não está na lista mostra a mensagem como veio.
 */

export type OndeCorrigir = "cliente" | "produto" | "empresa" | "certificado" | "tributacao" | "numeracao" | "csc" | "aguardar" | "suporte";

export type Explicacao = {
  titulo: string;
  dica: string;
  onde: OndeCorrigir | null;
  /** Transitório: não reenviar, a Spedy reprocessa sozinha. */
  aguardar?: boolean;
};

type Regra = { codigos: string[]; explicacao: Explicacao };

const REGRAS: Regra[] = [
  {
    codigos: ["SPD001", "SPD002", "SPD006"],
    explicacao: { titulo: "Ainda processando", dica: "A autoridade ainda não respondeu. Não reenvie; a nota atualiza sozinha.", onde: "aguardar", aguardar: true },
  },
  {
    codigos: ["SPD998", "SPD999"],
    explicacao: {
      titulo: "Instabilidade na comunicação",
      dica: "Falha técnica na comunicação com a SEFAZ ou a prefeitura. O sistema tenta de novo sozinho; não reenvie para não duplicar.",
      onde: "aguardar",
      aguardar: true,
    },
  },
  {
    codigos: ["SPD003"],
    explicacao: { titulo: "Faltou um dado obrigatório", dica: "Algum dado obrigatório da nota veio vazio ou em formato inválido. Confira os cadastros e tente de novo.", onde: null },
  },
  {
    codigos: ["SPD004"],
    explicacao: { titulo: "A nota já estava autorizada", dica: "Não reenvie. Atualize a página para ver a nota autorizada.", onde: null },
  },
  {
    codigos: ["204", "539"],
    explicacao: {
      titulo: "Número de nota já usado",
      dica: "Esta numeração já foi usada em outra nota (às vezes em outro sistema). Ajuste o próximo número em Notas fiscais → Configuração.",
      onde: "numeracao",
    },
  },
  {
    codigos: ["778", "779", "780"],
    explicacao: { titulo: "NCM inválido", dica: "Confira o NCM do produto (8 dígitos da tabela vigente).", onde: "produto" },
  },
  {
    codigos: ["232"],
    explicacao: {
      titulo: "Falta a inscrição estadual do cliente",
      dica: "Este cliente tem inscrição estadual e ela precisa ir na nota. No cadastro do cliente, escolha Contribuinte e preencha a inscrição: buscar pelo CNPJ preenche sozinho.",
      onde: "cliente",
    },
  },
  {
    codigos: ["233", "234", "235", "236", "237", "238", "239"],
    explicacao: {
      titulo: "Inscrição estadual do cliente",
      dica: "A IE do cliente não confere com a SEFAZ. Confira a IE ou marque o cliente como isento / não contribuinte.",
      onde: "cliente",
    },
  },
  {
    codigos: ["207", "208", "209", "210", "229", "230"],
    explicacao: { titulo: "Dados da empresa emissora", dica: "CNPJ ou inscrição estadual da empresa não conferem com a SEFAZ. Revise os dados fiscais da empresa.", onde: "empresa" },
  },
  {
    codigos: ["280", "281", "282", "283", "284", "285", "286", "290", "291", "292", "293", "294", "295", "296", "297", "298"],
    explicacao: { titulo: "Certificado digital", dica: "O certificado A1 está vencido, é de outro CNPJ ou não foi aceito. Envie um certificado válido.", onde: "certificado" },
  },
  {
    codigos: ["301", "302", "303"],
    explicacao: {
      titulo: "Irregularidade cadastral",
      dica: "A SEFAZ negou o uso por irregularidade do emitente ou do destinatário. Regularize junto à SEFAZ antes de emitir de novo.",
      onde: "empresa",
    },
  },
  {
    codigos: ["590", "591", "592", "593", "594", "595", "596", "597"],
    explicacao: {
      titulo: "Código de tributação não combina com o regime",
      dica: "Empresa do Simples usa CSOSN; regime normal usa CST. Revise o perfil de tributação.",
      onde: "tributacao",
    },
  },
  {
    codigos: ["523", "524", "525", "526"],
    explicacao: { titulo: "CFOP não combina com o destino", dica: "CFOP 5xxx é para dentro do estado e 6xxx para fora. Revise o perfil de tributação ou o endereço do cliente.", onde: "tributacao" },
  },
  {
    codigos: ["464", "465", "466"],
    explicacao: { titulo: "CSC da NFC-e", dica: "O ID do token ou o CSC não conferem. Gere o CSC no portal da SEFAZ e atualize em Notas fiscais → Configuração.", onde: "empresa" },
  },
  {
    /* NT 2025.001: parcela vencendo no dia da emissão é venda à vista, e à vista
       não leva fatura nem duplicata. O Ktalogu já monta a nota assim desde
       18/09/2026; o código só aparece em nota recusada antes disso. */
    codigos: ["853"],
    explicacao: {
      titulo: "A nota levou duplicata numa venda à vista",
      dica: "A SEFAZ não aceita duplicata vencendo no mesmo dia da emissão. Não precisa mudar nada no pedido nem no cliente: clique em Corrigi, reenviar e a nota sai à vista, sem duplicata.",
      onde: null,
    },
  },
  {
    codigos: ["866", "867", "868", "869", "870", "871"],
    explicacao: { titulo: "Forma de pagamento", dica: "O grupo de pagamento não fecha com o total. Registre os pagamentos do pedido e reenvie.", onde: null },
  },
  {
    codigos: ["610", "629", "564", "531", "532", "533", "534", "535", "536"],
    explicacao: { titulo: "Totais não fecham", dica: "Os valores da nota não fecharam na conta da SEFAZ. Fale com o suporte da Ktalogu com o número do pedido.", onde: "suporte" },
  },
  {
    codigos: ["225", "215", "216", "217"],
    explicacao: { titulo: "Estrutura da nota recusada", dica: "A SEFAZ recusou a estrutura do documento. Veja a mensagem abaixo; se não for dado do cadastro, fale com o suporte.", onde: null },
  },
];

const POR_CODIGO = new Map<string, Explicacao>(REGRAS.flatMap((regra) => regra.codigos.map((codigo) => [codigo, regra.explicacao] as const)));

export function explicarRejeicao(
  codigo: string | null | undefined,
  mensagem: string | null | undefined,
  contexto: { teste?: boolean; modelo?: string | null } = {}
): Explicacao {
  const texto = String(mensagem || "").toLowerCase();

  /* A nota de teste vai para a própria empresa: a inscrição recusada é a dela. */
  if (contexto.teste && ["232", "233", "234", "235", "236", "237", "238", "239"].includes(String(codigo || "").trim())) {
    return {
      titulo: "A inscrição estadual da empresa não confere",
      dica: "A SEFAZ não encontrou a inscrição estadual cadastrada em Sua empresa. Clique em Buscar pelo CNPJ para trazer a oficial (confira os zeros do começo), salve e teste de novo.",
      onde: "empresa",
    };
  }

  /* Recusas de formato vêm em inglês técnico e com código genérico: o texto diz mais que o código. */
  if (texto.includes(":nnf'") || texto.includes(":tnf'")) {
    return {
      titulo: "A numeração da nota não estava pronta",
      dica: "A empresa ainda não tinha numeração para este tipo de nota. Isso já é ajustado sozinho: é só testar de novo.",
      onde: null,
    };
  }
  if (texto.includes("portalfiscal.inf.br") || texto.includes("pattern constraint")) {
    return {
      titulo: "Um dado da nota está em formato que não é aceito",
      dica: "Algum dado da empresa, do cliente ou do produto está num formato recusado. Confira os cadastros; se continuar, fale com o suporte do Ktalogu.",
      onde: null,
    };
  }

  /* O sistema de prefeitura da DSF (Campinas e outras) quebra com um erro
     interno, em inglês de programador, quando não acha a regra do imposto do
     serviço ("tipoIncidencia is null"). Na MK5 (21/09/2026) a causa foi o
     código do serviço na prefeitura: primeiro o item da lista nacional
     ("13.05"), depois um código de outra atividade, com a atividade de
     comércio escolhida. Mandar a cidade do ISS não bastou. */
  if (texto.includes("tipoincidencia") || texto.includes("incidenciatype")) {
    return {
      titulo: "A prefeitura não achou a regra do imposto deste serviço",
      dica: "O código do serviço na prefeitura e a atividade (CNAE) precisam ser os de uma atividade de serviço da empresa, cadastrada na prefeitura. Atividade de comércio não serve para nota de serviço. Em Campinas, por exemplo, o código é a atividade com mais dois números: 181309900 é impressão (atividade 1813-0/99). Corrija os dois em Notas fiscais › Configuração › Ajustes do contador e clique em Corrigi, reenviar.",
      onde: "tributacao",
    };
  }

  /* Padrão nacional: o código do serviço na prefeitura é um complemento que só
     algumas cidades cadastram. Em Parauapebas (01/10/2026) não existe nenhum, e
     tanto "001" quanto o número de uma nota antiga voltaram com esta recusa. */
  if (texto.includes("tributação municipal informado não existe") || String(codigo || "").trim().toUpperCase() === "E0314") {
    return {
      titulo: "A prefeitura não tem esse código do serviço",
      dica: "O código do serviço na prefeitura que está na tributação não existe na sua cidade. Se na nota que você emitiu no portal do governo o código municipal aparece como um traço, a sua prefeitura não usa esse código: apague o campo Código do serviço na prefeitura em Notas fiscais › Configuração, salve e reenvie.",
      onde: "tributacao",
    };
  }

  /* Padrão nacional: a inscrição municipal vai ou não vai conforme o cadastro
     que a prefeitura mantém no ambiente nacional, e o serviço de notas nem
     sempre acerta sozinho. Em Parauapebas (02/10/2026) ela é exigida e a nota
     foi sem ("A IM deve ser informada para o emitente", E0116). */
  if (texto.includes("im deve ser informada") || String(codigo || "").trim().toUpperCase() === "E0116") {
    return {
      titulo: "A prefeitura exige a inscrição municipal na nota",
      dica: "Em Notas fiscais › Configuração, no passo das notas, abra Mais opções da nota de serviço, mude Inscrição municipal na nota para Sempre enviar, salve e reenvie. Confira também em Sua empresa se a inscrição municipal está igual à que aparece numa nota já emitida.",
      onde: "empresa",
    };
  }
  if (texto.includes("im não deve ser informada") || texto.includes("im nao deve ser informada")) {
    return {
      titulo: "A prefeitura não aceita a inscrição municipal na nota",
      dica: "Em Notas fiscais › Configuração, no passo das notas, abra Mais opções da nota de serviço, mude Inscrição municipal na nota para Nunca enviar, salve e reenvie.",
      onde: "empresa",
    };
  }

  /* A prefeitura lista os campos do cliente (o "tomador") que chegaram vazios.
     Quase sempre é cadastro incompleto. Na MK5 (21/09/2026, Campinas) o
     cadastro estava completo e o Ktalogu mandou o cliente inteiro; a recusa
     veio com o código do serviço num campo que Campinas não usa, e a Spedy
     indicou outro arranjo dos códigos (ver codigosDoServico em montar.ts).
     Por isso a dica diz o que fazer nos dois casos. */
  if (texto.includes("tomador") && texto.includes("preenchimento obrigat")) {
    return {
      titulo: "Os dados do cliente não chegaram completos à prefeitura",
      dica: "A prefeitura exige o CPF ou CNPJ e o endereço completo do cliente: CEP, rua, número, bairro, cidade e UF. Complete o cadastro do cliente e clique em Corrigi, reenviar. Se o cadastro já estiver completo, clique em Corrigi, reenviar mesmo assim; se voltar, fale com o suporte do Ktalogu.",
      onde: "cliente",
    };
  }

  /* Quem não respondeu foi o serviço de notas, não a autoridade: nada foi recusado. */
  if (texto.includes("serviço de notas") || texto.includes("muitas notas ao mesmo tempo")) {
    return {
      titulo: "O serviço de notas não respondeu",
      dica: "A nota não chegou a ser autorizada. Tente de novo em alguns instantes.",
      onde: null,
    };
  }
  /* O serviço de notas nem sempre traduz o código da SEFAZ e devolve só
     "Mensagem de retorno da Sefaz não reconhecida. Cód: 853". O código de
     verdade está no texto: se ele tem explicação, ela vale mais que "a SEFAZ
     respondeu de um jeito inesperado". */
  const codigoNoTexto = /\bc[óo]d\.?:?\s*(\d{3})\b/i.exec(String(mensagem || ""))?.[1];
  const peloTexto = codigoNoTexto ? POR_CODIGO.get(codigoNoTexto) : undefined;
  if (peloTexto) return peloTexto;

  /* A resposta da SEFAZ veio sem um motivo legível: não dá para dizer o que corrigir, e chutar
     manda a empresa mexer no que já está certo. No cupom fiscal os dois pontos que valem conferir
     são o credenciamento do modelo 65 (pedido à parte do da nota de produto, um por ambiente) e o
     CSC do QR Code. Com os dois em ordem, a conversa é com o suporte: o problema é da ligação. */
  if (texto.includes("não reconhecida") || texto.includes("nao reconhecida")) {
    if (contexto.modelo === "nfce") {
      return {
        titulo: "A Secretaria da Fazenda não disse o motivo",
        dica: "A resposta veio sem um motivo legível, então não dá para saber o que corrigir pela mensagem. No site da Secretaria da Fazenda do seu estado, confira duas coisas: se a empresa está credenciada para emitir cupom fiscal no ambiente em uso (é um pedido à parte do da nota de produto) e se o CSC guardado aqui é igual ao que aparece lá. Se os dois estiverem certos, fale com o suporte do Ktalogu — aí o problema é na ligação com a Secretaria, não no seu cadastro.",
        onde: "csc",
      };
    }
    return {
      titulo: "A SEFAZ respondeu de um jeito inesperado",
      dica: "Tente de novo em alguns minutos. Se continuar, fale com o suporte do Ktalogu.",
      onde: "suporte",
    };
  }
  if (texto.includes("emissão de notas está indisponível")) {
    return { titulo: "Emissão indisponível no momento", dica: "Fale com o suporte do Ktalogu.", onde: null };
  }

  const limpo = String(codigo || "").trim().toUpperCase();
  const encontrado = POR_CODIGO.get(limpo);
  if (encontrado) return encontrado;

  if (texto.includes("ncm")) return { titulo: "NCM do produto", dica: "Confira o NCM do produto.", onde: "produto" };
  if (texto.includes("certificado")) return { titulo: "Certificado digital", dica: "Confira o certificado A1 da empresa.", onde: "certificado" };
  if (texto.includes("inscri") && texto.includes("destinat")) {
    return { titulo: "Inscrição estadual do cliente", dica: "Confira a IE do cliente ou marque como não contribuinte.", onde: "cliente" };
  }
  if (texto.includes("csc") || texto.includes("qr code") || texto.includes("qrcode")) {
    return { titulo: "CSC da NFC-e", dica: "Confira o ID do token e o CSC.", onde: "empresa" };
  }

  return { titulo: "A nota foi recusada", dica: "Leia a mensagem da autoridade abaixo, corrija o dado indicado e reenvie.", onde: null };
}
