import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { ambienteDaNfse, ambienteDaNota, blocosDeConfiguracao, exigenciasDaCidade, problemaNaSerieDoNacional, type EmissorGuardado } from "./emissor.ts";
import { faltasDoServico, lerRegrasDeMercadoria, lerRegrasDeServico } from "./regras.ts";
import { explicarRejeicao } from "./rejeicoes.ts";

/* A Focus (Parauapebas, 01/10/2026): nota de serviço ligada no Ktalogu oficial,
   ainda em modo de teste. */
const emissor = (ambiente: "sandbox" | "producao", nfse: Record<string, unknown>) =>
  ({ ambiente, regime: "simplesNacional", nfe: { ativo: false }, nfce: { ativo: false }, nfse: { ativo: true, forma: "annfs", ...nfse } }) as unknown as EmissorGuardado;

describe("modo de teste da nota de serviço", () => {
  it("no ambiente de testes continua sendo a simulação", () => {
    const e = emissor("sandbox", { ambiente: "simulacao" });
    assert.equal(ambienteDaNfse(e), "simulacao");
    assert.equal(blocosDeConfiguracao(e, {}, null).serviceInvoice?.environmentType, "simulation");
  });

  it("no Ktalogu oficial vira a homologação da prefeitura: a simulação a Spedy recusa", () => {
    for (const guardado of ["simulacao", undefined]) {
      const e = emissor("producao", { ambiente: guardado });
      assert.equal(ambienteDaNfse(e), "homologacao");
      assert.equal(ambienteDaNota(e, "nfse"), "homologacao");
      assert.equal(blocosDeConfiguracao(e, {}, null).serviceInvoice?.environmentType, "development");
    }
  });

  it("quem já emite de verdade segue emitindo de verdade", () => {
    const e = emissor("producao", { ambiente: "producao" });
    assert.equal(ambienteDaNfse(e), "producao");
    assert.equal(blocosDeConfiguracao(e, {}, null).serviceInvoice?.environmentType, "production");
  });
});

/* O que a Spedy devolve para as cidades do emissor nacional (Parauapebas). */
const NACIONAL = { series: true, cityServiceCode: true, federalServiceCode: true, nbsCode: false, useNationalLayout: true };

describe("nota de serviço no padrão nacional", () => {
  it("sem série a prefeitura nem lê a nota: quem não preencheu sai com a 1", () => {
    const e = emissor("producao", { ambiente: "simulacao", serie: null, cidade: { codigo: "1505536", nome: "Parauapebas", uf: "PA", opcoes: NACIONAL } });
    assert.equal(blocosDeConfiguracao(e, {}, null).serviceInvoice?.series, "1");
    assert.equal(blocosDeConfiguracao(e, {}, { serviceInvoice: { series: "" } }).serviceInvoice?.series, "1");
  });

  it("a série que a empresa escolheu, ou a que já está na Spedy, fica", () => {
    const cidade = { codigo: "1505536", nome: "Parauapebas", uf: "PA", opcoes: NACIONAL };
    assert.equal(blocosDeConfiguracao(emissor("producao", { serie: "5", cidade }), {}, null).serviceInvoice?.series, "5");
    assert.equal(blocosDeConfiguracao(emissor("producao", { serie: null, cidade }), {}, { serviceInvoice: { series: "3" } }).serviceInvoice?.series, "3");
  });

  it("fora do padrão nacional ninguém ganha série sem pedir", () => {
    const e = emissor("producao", { forma: "normal", serie: null, cidade: { codigo: "3509502", nome: "Campinas", uf: "SP", opcoes: { series: true } } });
    assert.equal("series" in (blocosDeConfiguracao(e, {}, null).serviceInvoice ?? {}), false);
  });

  it("a série do portal do governo (70000) não serve para quem emite por sistema", () => {
    assert.equal(problemaNaSerieDoNacional(null), null);
    assert.equal(problemaNaSerieDoNacional("1"), null);
    assert.equal(problemaNaSerieDoNacional("49999"), null);
    assert.match(problemaNaSerieDoNacional("70000") ?? "", /1 a 49999/);
    assert.match(problemaNaSerieDoNacional("A") ?? "", /1 a 49999/);
  });

  it("o NBS é pedido mesmo quando a Spedy não marca a cidade", () => {
    assert.equal(exigenciasDaCidade(NACIONAL).nbs, true);
    assert.equal(exigenciasDaCidade({ nbsCode: false }).nbs, false);
    const regras = lerRegrasDeServico({ aliquotaIss: 5, codigoLc116: "13.05", codigoMunicipal: "001" });
    assert.deepEqual(faltasDoServico(regras, exigenciasDaCidade(NACIONAL)), ["código NBS"]);
    assert.deepEqual(faltasDoServico({ ...regras, nbs: "1.2101.21.00" }, exigenciasDaCidade(NACIONAL)), []);
  });
});

describe("classificação do IBS/CBS", () => {
  it("zero não existe na tabela: guardado como zero, vale o padrão", () => {
    assert.equal(lerRegrasDeServico({ ibsCbsCst: 0, ibsCbsClassificacao: 0 }).ibsCbsClassificacao, null);
    assert.equal(lerRegrasDeServico({ ibsCbsCst: 0, ibsCbsClassificacao: 0 }).ibsCbsCst, 0);
    assert.equal(lerRegrasDeMercadoria({ ibsCbsClassificacao: 0 }).ibsCbsClassificacao, null);
    assert.equal(lerRegrasDeServico({ ibsCbsClassificacao: 1 }).ibsCbsClassificacao, 1);
  });
});

describe("código do serviço na prefeitura no padrão nacional", () => {
  const semCodigo = lerRegrasDeServico({ aliquotaIss: 5, codigoLc116: "13.05", nbs: "1.2101.21.00" });

  it("é opcional: a prefeitura que não tem complemento recusa qualquer código", () => {
    const exige = exigenciasDaCidade(NACIONAL);
    assert.equal(exige.codigoMunicipal, false);
    assert.equal(exige.codigoMunicipalOpcional, true);
    assert.deepEqual(faltasDoServico(semCodigo, exige), []);
  });

  it("fora do padrão nacional a cidade que exige continua exigindo", () => {
    const exige = exigenciasDaCidade({ cityServiceCode: true, federalServiceCode: true });
    assert.equal(exige.codigoMunicipal, true);
    assert.equal(exige.codigoMunicipalOpcional, false);
    assert.deepEqual(faltasDoServico(semCodigo, exige), ["código do serviço no município"]);
  });

  it("a recusa do código que não existe diz para apagar o campo", () => {
    const recusa = explicarRejeicao("E0314", "O código de tributação municipal informado não existe ou não está administrado pelo município de incidência do ISSQN na data de competência informada na DPS.", { teste: true, modelo: "nfse" });
    assert.equal(recusa.onde, "tributacao");
    assert.match(recusa.dica, /apague o campo/);
  });
});

describe("inscrição municipal no padrão nacional", () => {
  it("a recusa por falta da inscrição municipal diz onde ligar o envio", () => {
    const recusa = explicarRejeicao("E0116", "A IM deve ser informada para o emitente prestador do serviço na DPS, conforme informações complementares registradas no CNC NFS-e do município emissor informado na DPS.", { teste: true, modelo: "nfse" });
    assert.match(recusa.dica, /Sempre enviar/);
  });

  it("o que a empresa escolheu vai para as configurações", () => {
    const e = emissor("producao", { enviarInscricaoMunicipal: "yes" });
    assert.equal(blocosDeConfiguracao(e, {}, null).serviceInvoice?.sendCityTaxNumber, "yes");
  });
});
