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

import { lerArgumentos } from "./esquema.ts";
import {
  ajustarCorte,
  ajustarEfeitoDaLogo,
  CABECALHO_DA_LOJA,
  camposDoGrupo,
  CHAT_DA_LOJA,
  colunasDaModeracao,
  comoDesfazer,
  CONTATO_E_RODAPE,
  CORTE_DE_PRODUCAO,
  contatosNosTextos,
  enderecoDoPonto,
  lerGrupo,
  linkDaRede,
  montarMudanca,
  montarPonto,
  motivosSensiveis,
  opcaoPeloNome,
  OPCOES_DE_COMPRA,
  REGRAS_DA_LOJA,
  SEO_DA_LOJA,
  SITUACAO_DA_LOJA,
  telefoneComMascara,
  usuarioDoX,
  type Grupo,
} from "./ferramentas/loja-regras-e-contato-regras.ts";

/* Os valores que o banco aceita (CHECK de profiles, conferidas no banco em 14/10/2026). */
const CHECKS: Record<string, string[]> = {
  catalog_price_mode: ["public", "hidden", "clients"],
  catalog_purchase_mode: ["cart", "quote", "whatsapp", "showcase"],
  catalog_access_mode: ["public", "clients"],
  catalog_signup_mode: ["open", "approval", "closed"],
  catalog_stock_display: ["exact", "low_only", "never"],
  catalog_sold_out_mode: ["show", "hide", "quote"],
  catalog_status: ["open", "paused", "closed"],
  catalog_vitrine_product_layout: ["mosaic", "standard"],
  catalog_logo_effect: ["none", "rotate_3d", "pulse_glow", "blink"],
};

const GRUPOS: Record<string, Grupo> = {
  regras: REGRAS_DA_LOJA,
  situacao: SITUACAO_DA_LOJA,
  cabecalho: CABECALHO_DA_LOJA,
  contato: CONTATO_E_RODAPE,
  seo: SEO_DA_LOJA,
  corte: CORTE_DE_PRODUCAO,
  chat: CHAT_DA_LOJA,
};

test("toda opção grava um valor que o banco aceita", () => {
  for (const grupo of Object.values(GRUPOS)) {
    for (const campo of Object.values(grupo)) {
      if (campo.tipo !== "opcao") continue;
      assert.deepEqual(campo.opcoes.map((o) => o.valor).sort(), [...CHECKS[campo.coluna]].sort(), campo.coluna);
      assert.ok(CHECKS[campo.coluna].includes(campo.padrao), `${campo.coluna}: padrão`);
    }
  }
});

test("o esquema de cada grupo aceita os nomes amigáveis e recusa o resto", () => {
  for (const [nome, grupo] of Object.entries(GRUPOS)) {
    const campos = camposDoGrupo(grupo);
    assert.ok(Object.keys(campos).length > 0, nome);
  }
  const campos = camposDoGrupo(REGRAS_DA_LOJA);
  assert.ok(lerArgumentos(campos, { quem_ve_o_preco: "esconder preço", como_o_cliente_fecha: "whatsapp" }).ok);
  assert.equal(lerArgumentos(campos, { quem_ve_o_preco: "ninguém" }).ok, false);
  assert.equal(lerArgumentos(campos, { texto_no_lugar_do_preco: "x".repeat(61) }).ok, false, "até 60 letras");
  assert.equal(lerArgumentos(campos, { aviso_embaixo_do_preco: "x".repeat(141) }).ok, false, "até 140 letras");
  assert.equal(lerArgumentos(campos, { recado_da_situacao: "x".repeat(501) }).ok, false, "até 500 letras");
  assert.equal(lerArgumentos(campos, { inventado: 1 }).ok, false);
  assert.equal(lerArgumentos(camposDoGrupo(CABECALHO_DA_LOJA), { velocidade_do_efeito: 49 }).ok, false, "velocidade 50–200");
  assert.equal(lerArgumentos(camposDoGrupo(CABECALHO_DA_LOJA), { intensidade_do_efeito: 181 }).ok, false, "intensidade 40–180");
  assert.equal(lerArgumentos(camposDoGrupo(CHAT_DA_LOJA), { saudacao: "x".repeat(401) }).ok, false, "saudação até 400");
});

test("opção pelo nome, sem acento e sem caixa, ou pelo valor gravado", () => {
  assert.equal(opcaoPeloNome(OPCOES_DE_COMPRA, "Só vitrine")?.valor, "showcase");
  assert.equal(opcaoPeloNome(OPCOES_DE_COMPRA, "so vitrine")?.valor, "showcase");
  assert.equal(opcaoPeloNome(OPCOES_DE_COMPRA, "quote")?.valor, "quote");
  assert.equal(opcaoPeloNome(OPCOES_DE_COMPRA, "loja"), null);
});

test("regras: só o que muda, com o antes, e o desfazer devolve como era", () => {
  const atual = { catalog_price_mode: "public", catalog_price_hidden_text: null, catalog_min_order_total: "50.00", catalog_reviews_enabled: null };
  const r = montarMudanca(
    REGRAS_DA_LOJA,
    { quem_ve_o_preco: "esconder preço", texto_no_lugar_do_preco: "Consulte", pedido_minimo_em_reais: 0, mostrar_avaliacoes: true },
    [],
    atual
  );
  assert.ok(r.ok);
  if (!r.ok) return;
  assert.deepEqual(r.mudanca.colunas, { catalog_price_mode: "hidden", catalog_price_hidden_text: "Consulte", catalog_min_order_total: null });
  assert.deepEqual(comoDesfazer(REGRAS_DA_LOJA, r.mudanca.antes), {
    quem_ve_o_preco: "preço para todos",
    pedido_minimo_em_reais: 50,
    voltar_ao_padrao: ["texto_no_lugar_do_preco"],
  });
  const linha = r.mudanca.linhas.find((l) => l.campo === "Pedido mínimo em reais");
  assert.equal(linha?.depois, "sem mínimo");
});

test("regras: recusa o que não dá", () => {
  assert.equal(montarMudanca(REGRAS_DA_LOJA, { mostrar_codigo_sku: false }, [], {}).ok, false, "nada muda: já é o padrão");
  assert.equal(montarMudanca(REGRAS_DA_LOJA, { aviso_embaixo_do_preco: "x" }, ["aviso_embaixo_do_preco"], {}).ok, false);
  assert.equal(montarMudanca(REGRAS_DA_LOJA, {}, ["quem_ve_o_preco"], {}).ok, false, "opção não fica em branco");
  assert.equal(montarMudanca(REGRAS_DA_LOJA, {}, ["limite_de_ultimas_unidades"], {}).ok, false, "o limite não tem branco");
  assert.equal(montarMudanca(REGRAS_DA_LOJA, { aviso_embaixo_do_preco: "<b> </b>" }, [], {}).ok, false, "vazio depois de limpo");
});

test("sensível: fechar, pausar, só clientes, preço, modo de compra, cadastro fechado e sair do Google", () => {
  assert.equal(motivosSensiveis({ catalog_status: "paused" }, {}).length, 1);
  assert.equal(motivosSensiveis({ catalog_status: "closed" }, { catalog_status: "paused" }).length, 1);
  assert.equal(motivosSensiveis({ catalog_status: "open" }, { catalog_status: "closed" }).length, 0, "reabrir grava direto");
  assert.equal(motivosSensiveis({ catalog_access_mode: "clients" }, {}).length, 1);
  assert.equal(motivosSensiveis({ catalog_access_mode: "public" }, { catalog_access_mode: "clients" }).length, 0);
  assert.equal(motivosSensiveis({ catalog_price_mode: "public" }, { catalog_price_mode: "hidden" }).length, 1, "qualquer mudança no preço");
  assert.equal(motivosSensiveis({ catalog_purchase_mode: "quote" }, {}).length, 1);
  assert.equal(motivosSensiveis({ catalog_signup_mode: "closed" }, {}).length, 1);
  assert.equal(motivosSensiveis({ catalog_signup_mode: "approval" }, {}).length, 0);
  assert.equal(motivosSensiveis({ catalog_noindex: true }, { catalog_noindex: false }).length, 1);
  assert.equal(motivosSensiveis({ catalog_noindex: false }, { catalog_noindex: true }).length, 0);
  assert.equal(motivosSensiveis({ catalog_show_sku: true }, {}).length, 0);
});

test("abrir ou fechar: situação, recado e data", () => {
  const r = montarMudanca(SITUACAO_DA_LOJA, { situacao: "em pausa", recado: "Férias!", ate_quando: "2026-11-01" }, [], { catalog_status: "open" });
  assert.ok(r.ok);
  if (!r.ok) return;
  assert.deepEqual(r.mudanca.colunas, { catalog_status: "paused", catalog_status_message: "Férias!", catalog_status_until: "2026-11-01" });
  assert.ok(motivosSensiveis(r.mudanca.colunas, { catalog_status: "open" }).length > 0);
  assert.equal(r.mudanca.linhas.find((l) => l.campo === "Previsão de volta")?.depois, "01/11/2026");
});

test("texto do cliente passa pela peneira de contatos; endereço e telefone não", () => {
  const r = montarMudanca(REGRAS_DA_LOJA, { aviso_embaixo_do_preco: "Chame no (11) 98765-4321" }, [], {});
  assert.ok(r.ok && contatosNosTextos(REGRAS_DA_LOJA, r.mudanca).length === 1);
  const c = montarMudanca(CONTATO_E_RODAPE, { endereco: "Rua A, 10 - Centro", telefone: "11987654321" }, [], {});
  assert.ok(c.ok && contatosNosTextos(CONTATO_E_RODAPE, c.mudanca).length === 0);
  const chat = montarMudanca(CHAT_DA_LOJA, { saudacao: "Oi! Pague no pix chave@exemplo.com" }, [], {});
  assert.ok(chat.ok && contatosNosTextos(CHAT_DA_LOJA, chat.mudanca).length === 1);
});

test("telefone com DDD vira a máscara da tela", () => {
  assert.deepEqual(telefoneComMascara("11987654321"), { ok: true, valor: "(11) 98765-4321" });
  assert.deepEqual(telefoneComMascara("+55 (11) 3333-4444"), { ok: true, valor: "(11) 3333-4444" });
  assert.equal(telefoneComMascara("98765-4321").ok, false);
  const r = montarMudanca(CONTATO_E_RODAPE, { whatsapp_da_loja: "(11) 98765-4321" }, [], { whatsapp: "(11) 98765-4321" });
  assert.equal(r.ok, false, "o mesmo número não muda nada");
});

test("redes sociais: @ vira link; só https e só do site da rede", () => {
  assert.deepEqual(linkDaRede("instagram", "@minha.loja"), { ok: true, valor: "https://instagram.com/minha.loja" });
  assert.deepEqual(linkDaRede("instagram", "minhaloja"), { ok: true, valor: "https://instagram.com/minhaloja" });
  assert.deepEqual(linkDaRede("twitter", "@loja"), { ok: true, valor: "https://x.com/loja" });
  assert.deepEqual(linkDaRede("youtube", "@canal"), { ok: true, valor: "https://youtube.com/@canal" });
  assert.deepEqual(linkDaRede("instagram", "instagram.com/loja"), { ok: true, valor: "https://instagram.com/loja" });
  assert.deepEqual(linkDaRede("facebook", "https://www.facebook.com/loja"), { ok: true, valor: "https://www.facebook.com/loja" });
  assert.equal(linkDaRede("instagram", "https://golpe.com/instagram.com/loja").ok, false, "outro site");
  assert.equal(linkDaRede("instagram", "https://instagram.com.golpe.com/loja").ok, false, "subdomínio enganoso");
  assert.equal(linkDaRede("instagram", "http://instagram.com/loja").ok, false, "sem https");
  assert.equal(linkDaRede("instagram", "https://instagram.com/").ok, false, "sem perfil");
  assert.equal(linkDaRede("linkedin", "@empresa").ok, false, "LinkedIn só com link");
  assert.equal(linkDaRede("instagram", "javascript:alert(1)").ok, false);
});

test("usuário no X e sair do Google", () => {
  assert.deepEqual(usuarioDoX("sualoja"), { ok: true, valor: "@sualoja" });
  assert.deepEqual(usuarioDoX("https://x.com/sualoja"), { ok: true, valor: "@sualoja" });
  assert.equal(usuarioDoX("@nome com espaço").ok, false);
  const r = montarMudanca(SEO_DA_LOJA, { aparecer_no_google: false }, [], { catalog_noindex: false });
  assert.ok(r.ok && r.mudanca.colunas.catalog_noindex === true);
  if (!r.ok) return;
  assert.deepEqual(comoDesfazer(SEO_DA_LOJA, r.mudanca.antes), { aparecer_no_google: true });
});

test("efeito da logo: escolher liga; sem efeito desliga e volta a 100%", () => {
  const liga = montarMudanca(CABECALHO_DA_LOJA, { efeito_da_logo: "rotação 3D", velocidade_do_efeito: 150 }, [], { catalog_logo_effect: "none" });
  assert.ok(liga.ok);
  if (!liga.ok) return;
  assert.ok(ajustarEfeitoDaLogo(liga.mudanca, { catalog_logo_effect: "none" }).ok);
  assert.equal(liga.mudanca.colunas.catalog_logo_effect_enabled, true);
  assert.equal(liga.mudanca.colunas.catalog_logo_effect_speed, 150);

  const atual = { catalog_logo_effect_enabled: true, catalog_logo_effect: "blink", catalog_logo_effect_speed: 150, catalog_logo_effect_intensity: 120 };
  const desliga = montarMudanca(CABECALHO_DA_LOJA, { efeito_da_logo: "sem efeito" }, [], atual);
  assert.ok(desliga.ok);
  if (!desliga.ok) return;
  assert.ok(ajustarEfeitoDaLogo(desliga.mudanca, atual).ok);
  assert.deepEqual(desliga.mudanca.colunas, {
    catalog_logo_effect: "none",
    catalog_logo_effect_enabled: false,
    catalog_logo_effect_speed: 100,
    catalog_logo_effect_intensity: 100,
  });
  assert.deepEqual(comoDesfazer(CABECALHO_DA_LOJA, desliga.mudanca.antes), { efeito_da_logo: "brilho ritmado", velocidade_do_efeito: 150, intensidade_do_efeito: 120 });

  const soRitmo = montarMudanca(CABECALHO_DA_LOJA, { velocidade_do_efeito: 120 }, [], { catalog_logo_effect_enabled: false });
  assert.ok(soRitmo.ok && !ajustarEfeitoDaLogo(soRitmo.mudanca, { catalog_logo_effect_enabled: false }).ok, "ritmo sem efeito é recusado");
});

test("corte de produção: ligar pede hora; desligar apaga a hora", () => {
  const semHora = montarMudanca(CORTE_DE_PRODUCAO, { ligado: true }, [], {});
  assert.ok(semHora.ok && !ajustarCorte(semHora.mudanca, {}).ok);
  const comHora = montarMudanca(CORTE_DE_PRODUCAO, { ligado: true, hora: "16:00" }, [], {});
  assert.ok(comHora.ok && ajustarCorte(comHora.mudanca, {}).ok);
  const atual = { production_cutoff_enabled: true, production_cutoff_time: "15:30" };
  const desliga = montarMudanca(CORTE_DE_PRODUCAO, { ligado: false }, [], atual);
  assert.ok(desliga.ok);
  if (!desliga.ok) return;
  assert.ok(ajustarCorte(desliga.mudanca, atual).ok);
  assert.deepEqual(desliga.mudanca.colunas, { production_cutoff_enabled: false, production_cutoff_time: null });
  assert.deepEqual(comoDesfazer(CORTE_DE_PRODUCAO, desliga.mudanca.antes), { ligado: true, hora: "15:30" });
});

test("leitura: cada campo com o valor de hoje e o significado", () => {
  const lido = lerGrupo(REGRAS_DA_LOJA, { catalog_purchase_mode: "showcase" }) as Record<string, { hoje: string; significado_de_hoje?: string }>;
  assert.equal(lido.como_o_cliente_fecha.hoje, "só vitrine");
  assert.match(lido.como_o_cliente_fecha.significado_de_hoje ?? "", /Sem botão/);
  assert.equal(lido.quem_ve_o_preco.hoje, "preço para todos", "NULL vale o padrão");
  assert.equal(lido.texto_no_lugar_do_preco.hoje, 'em branco (vale "Sob consulta")');
});

test("ponto de retirada: as regras da tela de Logística", () => {
  const ok = montarPonto({ nome: "Balcão", rua: "Rua A", numero: "10", cidade: "Campinas", uf: "sp", cep: "13010-000", preco: 5.555, pronto_em_dias: 1 }, null);
  assert.ok(ok.ok);
  if (!ok.ok) return;
  assert.equal(ok.ponto.state, "SP");
  assert.equal(ok.ponto.zip, "13010000");
  assert.equal(ok.ponto.price, 5.56);
  assert.equal(enderecoDoPonto(ok.ponto), "Rua A, 10 • Campinas / SP • CEP 13010-000");
  assert.equal(montarPonto({ nome: "Balcão", cidade: "Campinas" }, null).ok, false, "falta a rua");
  assert.equal(montarPonto({ rua: "Rua A", cidade: "Campinas" }, null).ok, false, "falta o nome");
  assert.equal(montarPonto({ nome: "B", rua: "R", cidade: "C", cep: "123" }, null).ok, false, "CEP curto");
  assert.equal(montarPonto({ nome: "B", rua: "R", cidade: "C", uf: "São Paulo" }, null).ok, false, "UF por extenso");
  const contato = montarPonto({ nome: "B", rua: "R", cidade: "C", instrucoes: "Ligue (11) 98765-4321" }, null);
  assert.ok(contato.ok && contato.contatos.length === 1, "instrução com telefone novo passa pela peneira");
  const alterado = montarPonto({ ativo: false }, ok.ponto);
  assert.ok(alterado.ok && alterado.ponto.active === false && alterado.ponto.name === "Balcão");
});

test("moderação grava as mesmas colunas da rota do painel", () => {
  assert.deepEqual(colunasDaModeracao("aprovar", "T"), { status: "approved", moderated_at: "T", approved_at: "T", rejected_at: null });
  assert.deepEqual(colunasDaModeracao("recusar", "T"), { status: "rejected", moderated_at: "T", approved_at: null, rejected_at: "T" });
});
