import { test } from "node:test";
import assert from "node:assert/strict";

import {
  agruparPorModelo,
  dataDeReposicao,
  descricaoParaLoja,
  lerItemDoCatalogo,
  montarProdutoDaXbz,
  nomeParaLoja,
  normalizarNcm,
  ordenarAchados,
  palavrasDaBusca,
  regraDeQuantidade,
  rotuloDaCor,
  textoParaBusca,
  type CorDoCatalogo,
} from "./xbz.catalogo.ts";
import { mapearStatusXbz } from "./xbz.status.ts";

/* Itens de verdade do GetListaDeProdutos (05/10/2026), com o que importa. */
const base = {
  IdPessoa: 0,
  WebTipoId: 0,
  WebTipo: "",
  WebSubTipoId: 0,
  WebSubTipo: "",
  PontaDeEstoque: false,
  IdStatusConfiabilidade: 10,
  StatusConfiabilidade: "Quantidade CONFIÁVEL. Confirmada através de inventário realizado recentemente.",
  ReposicaoDataPrevista: "0001-01-01T00:00:00",
};
const CANECA_DESCRICAO =
  "Caneca acrílica 400ml com detalhe oval no pegador, revestimento interno e detalhes em inox. Tampa plástica resistente com sistema giratório para abertura(não é térmica).";

const canecaAzul = {
  ...base,
  IdProduto: 1,
  CodigoXbz: "X000019",
  CodigoComposto: "06520-AZU",
  CodigoAmigavel: "06520",
  Nome: "CANECA ACRÍLICA 400 ML COM TAMPA",
  Descricao: CANECA_DESCRICAO,
  SiteLink: "http://www.xbzbrindes.com.br/06520",
  ImageLink: "https://cdn.xbzbrindes.com.br/img/produtos/3/6520-AZU-Caneca-400ml-Acrilica-249.jpg",
  CorWebPrincipal: "AZUL",
  CorWebSecundaria: "AZUL",
  Peso: 154,
  Altura: 0,
  Largura: 0,
  Profundidade: 0,
  PrecoVenda: 12.56,
  PrecoVendaFormatado: "12,56",
  QuantidadeDisponivelEstoquePrincipal: 462,
  QuantidadeDisponivel: 6591,
  Ncm: "73239300",
};
const canecaLaranja = {
  ...canecaAzul,
  IdProduto: 49,
  CodigoXbz: "X000493",
  CodigoComposto: "06520-LAR",
  ImageLink: "https://cdn.xbzbrindes.com.br/img/produtos/3/6520-LAR-Caneca-400ml-Acrilica-251.jpg",
  CorWebPrincipal: "LARANJA",
  CorWebSecundaria: "INOX",
  Peso: 183,
  Altura: 12.5,
  Largura: 8.7,
  QuantidadeDisponivelEstoquePrincipal: 130,
  QuantidadeDisponivel: 4261,
};
const caneta = {
  ...base,
  IdProduto: 119,
  CodigoXbz: "X001198",
  CodigoComposto: "00518-PRA/AZU",
  CodigoAmigavel: "00518",
  Nome: "CANETA PLÁSTICA C/ DET EMBORRACHADO",
  Descricao: "Caneta plástica com detalhe emborrachado, carga esferográfica azul e acionamento por clique.    OBS.: PEDIDOS MÍNIMO DE 50 PEÇAS!  ",
  SiteLink: "https://www.xbzbrindes.com.br/00518",
  ImageLink: "https://cdn.xbzbrindes.com.br/img/produtos/3/518-AZU-Caneta-Plastica-292.jpg",
  CorWebPrincipal: "PRATA",
  CorWebSecundaria: "AZUL",
  Peso: 10,
  Altura: 14,
  Largura: 3.6,
  Profundidade: 0,
  PrecoVenda: 1.06,
  QuantidadeDisponivelEstoquePrincipal: 9778,
  QuantidadeDisponivel: 12888,
  Ncm: "96081000",
};

const ler = (bruto: unknown) => {
  const lido = lerItemDoCatalogo(bruto);
  assert.ok(lido, "o item devia ser lido");
  return lido as CorDoCatalogo;
};

test("lê o item da lista nova com tudo o que a XBZ manda", () => {
  const cor = ler(canecaAzul);
  assert.equal(cor.codigoXbz, "X000019");
  assert.equal(cor.modelo, "06520");
  assert.equal(cor.cor, "Azul");
  assert.equal(cor.preco, 12.56);
  assert.equal(cor.estoque, 6591);
  assert.equal(cor.estoquePrincipal, 462);
  assert.equal(cor.pesoG, 154);
  assert.equal(cor.alturaCm, null, "zero é 'não informado'");
  assert.equal(cor.ncm, "73239300");
  assert.equal(cor.reposicaoPrevista, null);
  assert.equal(cor.estoqueConfiavel, true);
  assert.equal(cor.siteLink, "http://www.xbzbrindes.com.br/06520");
});

test("lê também a lista antiga (camelCase, sem preço nem estoque)", () => {
  const cor = ler({
    id: 1,
    nome: "CANECA ACRÍLICA 400 ML COM TAMPA",
    codigoXbz: "X000019",
    codigoComposto: "06520-AZU",
    codigoAmigavel: "06520",
    imageLink: "https://cdn.xbzbrindes.com.br/img/x.jpg",
  });
  assert.equal(cor.modelo, "06520");
  assert.equal(cor.preco, null);
  assert.equal(cor.estoque, 0);
  assert.equal(cor.imagem, "https://cdn.xbzbrindes.com.br/img/x.jpg");
});

test("item sem código não serve", () => {
  assert.equal(lerItemDoCatalogo({ Nome: "x" }), null);
  assert.equal(lerItemDoCatalogo(null), null);
  assert.equal(lerItemDoCatalogo([1, 2]), null);
});

test("estoque negativo da XBZ vira zero", () => {
  const cor = ler({ ...canecaAzul, QuantidadeDisponivel: -55, QuantidadeDisponivelEstoquePrincipal: -55 });
  assert.equal(cor.estoque, 0);
  assert.equal(cor.estoquePrincipal, 0);
});

test("NCM com a letra O no lugar do zero", () => {
  assert.equal(normalizarNcm("420292OO"), "42029200");
  assert.equal(normalizarNcm("3923309O"), "39233090");
  assert.equal(normalizarNcm("7323.93.00"), "73239300");
  assert.equal(normalizarNcm("1234"), null);
  assert.equal(normalizarNcm(null), null);
});

test("reposição: 0001-01-01 é sem previsão", () => {
  assert.equal(dataDeReposicao("0001-01-01T00:00:00"), null);
  assert.equal(dataDeReposicao("2026-11-16T00:00:00"), "2026-11-16");
  assert.equal(dataDeReposicao(""), null);
});

test("nome da cor pelo fim do código composto", () => {
  assert.equal(rotuloDaCor("06520-AZE", "06520", "AZUL", "AZUL"), "Azul escuro");
  assert.equal(rotuloDaCor("00518-PRA/AZU", "00518", "PRATA", "AZUL"), "Prata e azul");
  assert.equal(rotuloDaCor("P@12288-ROS/ROS", "P@12288", "ROSA", "ROSA"), "Rosa");
  assert.equal(rotuloDaCor("11193-PRE/FOS", "11193", "PRETO", "PRETO"), "Preto fosco");
  /* Sigla desconhecida: a cor que a XBZ informa. */
  assert.equal(rotuloDaCor("01228P-AZ1", "01228P", "AZUL", "AZUL"), "Azul");
  assert.equal(rotuloDaCor("06520-LAR", "06520", "LARANJA", "INOX"), "Laranja");
  assert.equal(rotuloDaCor("067-8GB", "067-8GB", "PRATA", "PRATA"), "8GB");
});

test("cores com o mesmo nome no mesmo modelo ganham o código", () => {
  const modelo = "01228P";
  const cores = ["AZ1", "AZ2", "BCO", "BC1", "RSC"].map((sufixo, indice) => {
    const daXbz = sufixo.startsWith("AZ") ? "AZUL" : sufixo.startsWith("B") ? "BRANCO" : "ROSA";
    return ler({ ...canecaAzul, CodigoXbz: `X9${indice}`, CodigoComposto: `${modelo}-${sufixo}`, CodigoAmigavel: modelo, CorWebPrincipal: daXbz, CorWebSecundaria: daXbz });
  });
  const [agrupado] = agruparPorModelo(cores);
  assert.deepEqual(
    agrupado.cores.map((cor) => cor.cor),
    ["Azul (AZ1)", "Azul (AZ2)", "Branco (BC1)", "Branco (BCO)", "Rosa claro"]
  );
});

test("as cores do mesmo modelo viram um produto só", () => {
  const modelos = agruparPorModelo([ler(canecaAzul), ler(canecaLaranja), ler(caneta)]);
  assert.equal(modelos.length, 2);
  const caneca = modelos.find((modelo) => modelo.codigo === "06520");
  assert.ok(caneca);
  assert.equal(caneca.cores.length, 2);
  assert.equal(caneca.estoque, 6591 + 4261);
  assert.equal(caneca.precoMinimo, 12.56);
  assert.equal(caneca.nome, "CANECA ACRÍLICA 400 ML COM TAMPA");
  assert.equal(caneca.imagem, canecaAzul.ImageLink, "a foto é a da cor com mais estoque");
});

test("regra de compra escrita na descrição", () => {
  assert.deepEqual(regraDeQuantidade("Caneta... OBS.: PEDIDOS MÍNIMO DE 50 PEÇAS!"), { minimo: 50, multiplo: null });
  assert.deepEqual(regraDeQuantidade("Sacola kraft. OBS.: PEDIDO MÍNIMO E MÚLTIPLO DE 25!"), { minimo: 25, multiplo: 25 });
  assert.deepEqual(regraDeQuantidade("Folhinha. OBS.: PEDIDOS APENAS MÚLTIPLOS DE 100 PEÇAS!"), { minimo: 100, multiplo: 100 });
  assert.deepEqual(regraDeQuantidade("Balde. OBS.: PEDIDO MINIMO 30 PECAS!"), { minimo: 30, multiplo: null });
  assert.deepEqual(regraDeQuantidade(CANECA_DESCRICAO), { minimo: null, multiplo: null });
});

test("a descrição da loja perde a regra de compra e o link da XBZ", () => {
  assert.equal(
    descricaoParaLoja(caneta.Descricao),
    "Caneta plástica com detalhe emborrachado, carga esferográfica azul e acionamento por clique."
  );
  assert.equal(descricaoParaLoja("OBS : PEDIDOS SOMENTE MULTIPLOS DE 25 PECAS."), "");
  assert.equal(descricaoParaLoja("https://www.xbzbrindes.com.br/13066a"), "");
  assert.equal(descricaoParaLoja("OBS.: NÃO É UM MODELO TÉRMICO."), "OBS.: NÃO É UM MODELO TÉRMICO.", "o resto da observação fica");
});

test("nome da XBZ arrumado para a loja", () => {
  assert.equal(nomeParaLoja("CANECA ACRÍLICA 400 ML COM TAMPA"), "Caneca Acrílica 400 ml com Tampa");
  assert.equal(nomeParaLoja("GARRAFA TÉRMICA 1L C/ CAPA "), "Garrafa Térmica 1L c/ Capa");
  assert.equal(nomeParaLoja("PEN DRIVE ALUMÍNIO 8GB"), "Pen Drive Alumínio 8GB");
  assert.equal(nomeParaLoja("CANETA PLÁSTICA COM LED E USB"), "Caneta Plástica com LED e USB");
  assert.equal(nomeParaLoja("GUARDA-CHUVA AUTOMÁTICO"), "Guarda-chuva Automático");
});

test("busca: palavras sem acento e sem curinga do banco", () => {
  assert.deepEqual(palavrasDaBusca("Caneca  ACRÍLICA azul"), ["caneca", "acrilica", "azul"]);
  assert.deepEqual(palavrasDaBusca("100% algodão_x"), ["100", "algodao"]);
  assert.deepEqual(palavrasDaBusca("06520"), ["06520"]);
  assert.equal(palavrasDaBusca("a b c d e f g h i j").length, 0);
  assert.ok(textoParaBusca(ler(canecaAzul)).includes("caneca acrilica 400 ml com tampa azul"));
});

test("busca: código exato vem antes de nome parecido", () => {
  const modelos = agruparPorModelo([ler(canecaAzul), ler(caneta)]);
  const [primeiro] = ordenarAchados(modelos, ["00518"]);
  assert.equal(primeiro.codigo, "00518");
});

test("cadastro: preço da XBZ vira custo, a margem faz o preço de venda", () => {
  const [modelo] = agruparPorModelo([ler(canecaAzul), ler({ ...canecaLaranja, PrecoVenda: 14.06 })]);
  const produto = montarProdutoDaXbz(modelo, { margem: 100 });
  assert.equal(produto.nome, "Caneca Acrílica 400 ml com Tampa");
  assert.equal(produto.sku, "06520");
  assert.equal(produto.custo, 12.56);
  assert.equal(produto.preco, 25.12);
  assert.equal(produto.sobConsulta, false);
  assert.equal(produto.ncm, "73239300");
  assert.equal(produto.pesoKg, 0.183, "o maior peso entre as cores");
  assert.equal(produto.alturaCm, 12.5);
  assert.equal(produto.comprimentoCm, 8.7, "sem profundidade na XBZ, fica o menor lado (a caneca é redonda)");
  assert.deepEqual(
    produto.cores.map((cor) => [cor.rotulo, cor.acrescimo]),
    [
      ["Azul", 0],
      ["Laranja", 3],
    ]
  );
});

test("cadastro: só as cores escolhidas, e uma cor só vai para a descrição", () => {
  const [modelo] = agruparPorModelo([ler(canecaAzul), ler(canecaLaranja)]);
  const produto = montarProdutoDaXbz(modelo, { margem: 50, cores: ["X000493"], nome: "  Caneca da Firma " });
  assert.equal(produto.nome, "Caneca da Firma");
  assert.equal(produto.cores.length, 1);
  assert.equal(produto.preco, 18.84);
  assert.ok(produto.descricao.endsWith("Cor: Laranja."));
  assert.throws(() => montarProdutoDaXbz(modelo, { margem: 50, cores: ["NAO-EXISTE"] }), /ao menos uma cor/);
});

test("cadastro: pedido mínimo, medida absurda e produto sem preço", () => {
  const [penas] = agruparPorModelo([ler({ ...caneta, Altura: 1303 })]);
  const produto = montarProdutoDaXbz(penas, { margem: 0 });
  assert.equal(produto.quantidadeMinima, 50);
  assert.equal(produto.alturaCm, null, "1.303 cm é erro de digitação, não vira medida de frete");
  assert.equal(produto.larguraCm, 3.6);
  assert.ok(!produto.descricao.includes("PEDIDOS"));

  const [semPreco] = agruparPorModelo([ler({ ...canecaAzul, PrecoVenda: 0 })]);
  const gratis = montarProdutoDaXbz(semPreco, { margem: 100 });
  assert.equal(gratis.custo, null);
  assert.equal(gratis.preco, 0);
  assert.equal(gratis.sobConsulta, true);
});

test("cadastro: margem fora do razoável é contida", () => {
  const [modelo] = agruparPorModelo([ler(canecaAzul)]);
  assert.equal(montarProdutoDaXbz(modelo, { margem: -50 }).preco, 12.56);
  assert.equal(montarProdutoDaXbz(modelo, { margem: Number.NaN }).preco, 12.56);
  assert.equal(montarProdutoDaXbz(modelo, { margem: 99_999 }).preco, 138.16);
});

test("status da XBZ, inclusive frase que a documentação não cita", () => {
  assert.equal(mapearStatusXbz("AGUARDANDO APROVAÇÃO DO SETOR DE VENDAS"), "AGUARDANDO");
  assert.equal(mapearStatusXbz("PEDIDO EMITIDO"), "AGUARDANDO");
  assert.equal(mapearStatusXbz("EM PROCESSO DE SEPARAÇÃO"), "PRODUCAO");
  assert.equal(mapearStatusXbz("AGUARDANDO PAGAMENTO PARA INICIAR A SEPARAÇÃO"), "AGUARDANDO");
  assert.equal(mapearStatusXbz("AGUARDANDO TRANSPORTADORA"), "ENVIADO");
  assert.equal(mapearStatusXbz("RETIRADO/ENVIADO/FINALIZADO"), "FINALIZADO");
  assert.equal(mapearStatusXbz("PEDIDO CANCELADO"), "CANCELADO");
  assert.equal(mapearStatusXbz("CANCELADO PELO CLIENTE"), "CANCELADO");
  assert.equal(mapearStatusXbz("EM GRAVAÇÃO"), "PRODUCAO");
  assert.equal(mapearStatusXbz(""), "AGUARDANDO");
  assert.equal(mapearStatusXbz(null), "AGUARDANDO");
});

test("ataque: descrição enorme e cheia de armadilha termina rápido", () => {
  const armadilha = `${"OBS.: PEDIDOS ".repeat(20_000)}${"MÍNIMO E ".repeat(20_000)}${"www.".repeat(20_000)}`;
  const inicio = Date.now();
  regraDeQuantidade(armadilha);
  descricaoParaLoja(armadilha);
  palavrasDaBusca(armadilha);
  assert.ok(Date.now() - inicio < 1500, `levou ${Date.now() - inicio} ms`);
});
