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

import {
  CANAL_DO_EDITOR,
  CHAVE_DA_GRADE_INVENTADA,
  NOME_DO_TEMA,
  ehFamiliaVendor,
  ehGradeFixa,
  gradeInventada,
  indiceNaLista,
  lerMensagemDaLoja,
  moverNaPagina,
  mudou,
  paginaParaGravar,
  problemaDoEndereco,
  problemasDaPagina,
  rascunhoInicial,
  rascunhoParaALoja,
  secaoDaLinha,
  secaoNova,
  temaDaLoja,
  type SecaoDoEditor,
} from "./pagina-inicial.ts";
import { criarPassagemDoEditor, lojaLocalValida } from "./loja/passagem-do-editor.ts";

function linha(id: string, extra: Record<string, unknown> = {}) {
  return {
    id,
    title: `Seção ${id}`,
    config: { mode: "manual_products" },
    section_type: "manual_products",
    position: 0,
    active: true,
    layout_width: "full",
    title_align: "left",
    title_size: "lg",
    background_color: "#ffffff",
    text_color: "#000000",
    ...extra,
  };
}

test("a linha do banco vira seção do editor (título antigo com configuração dentro)", () => {
  const antiga = secaoDaLinha(
    linha("a", { title: `Promo[[KTCFG:${encodeURIComponent(JSON.stringify({ mode: "image_banner", image_url: "https://x/b.svg" }))}]]`, config: null }),
    []
  );
  assert.equal(antiga.title, "Promo");
  assert.equal(antiga.modo, "image_banner");
  assert.equal(antiga.config.image_url, "https://x/b.svg");

  const comProdutos = secaoDaLinha(linha("b"), ["p1", "p2"]);
  assert.deepEqual(comProdutos.produtos, ["p1", "p2"]);
  assert.equal(secaoDaLinha(linha("c", { config: { mode: "category_products" } }), ["p1"]).produtos.length, 0);
  assert.equal(secaoDaLinha(linha("d", { config: { image_url: "https://x" } }), []).modo, "image_banner");
});

test("rascunho inicial: Padrão ganha a grade inventada, Vendor novo começa pela home automática", () => {
  const secoes = [secaoDaLinha(linha("a"), [])];
  const padrao = rascunhoInicial("default", secoes, { homeEditada: false, arranjoAutomatico: null });
  assert.deepEqual(padrao.map((s) => s.chave), ["a", CHAVE_DA_GRADE_INVENTADA]);

  const comGrade = [...secoes, secaoDaLinha(linha("g", { section_type: "all_products", config: { mode: "all_products" } }), [])];
  assert.equal(rascunhoInicial("vitrine", comGrade, { homeEditada: false, arranjoAutomatico: null }).length, 2);

  const auto = [secaoNova("featured_products")];
  const vendor = rascunhoInicial("vendor", secoes, { homeEditada: false, arranjoAutomatico: auto });
  assert.deepEqual(vendor.map((s) => [s.modo, s.ativa]), [["featured_products", true], ["manual_products", false]]);
  assert.deepEqual(rascunhoInicial("vendor", secoes, { homeEditada: true, arranjoAutomatico: auto }).map((s) => s.chave), ["a"]);

  /* A Boutique é da família Vendor: mesma regra. */
  const boutique = rascunhoInicial("boutique", secoes, { homeEditada: false, arranjoAutomatico: auto });
  assert.deepEqual(boutique.map((s) => [s.modo, s.ativa]), [["featured_products", true], ["manual_products", false]]);
});

test("os modelos da loja: a família Vendor e os nomes", () => {
  assert.equal(temaDaLoja("boutique"), "boutique");
  assert.equal(temaDaLoja(" Vendor "), "vendor");
  assert.equal(temaDaLoja("neo"), "default");
  assert.equal(temaDaLoja("inventado"), "default");
  assert.equal(ehFamiliaVendor("vendor"), true);
  assert.equal(ehFamiliaVendor("boutique"), true);
  for (const tema of ["default", "vitrine", "neo", null]) assert.equal(ehFamiliaVendor(tema), false);
  assert.equal(NOME_DO_TEMA.boutique, "Ateliê");
  /* Grade fixa só fora da família Vendor. */
  const grade = secaoDaLinha(linha("g", { section_type: "all_products", config: { mode: "all_products" } }), []);
  assert.equal(ehGradeFixa("vitrine", grade), true);
  assert.equal(ehGradeFixa("boutique", grade), false);
});

test("a grade inventada só vai ao banco se mexeram nela", () => {
  const a = secaoDaLinha(linha("a"), []);
  const grade = gradeInventada();
  assert.deepEqual(paginaParaGravar([a, grade]).map((s) => s.id), ["a"]);

  const movida = paginaParaGravar([grade, a]);
  assert.equal(movida.length, 2);
  assert.equal(movida[0].section_type, "all_products");
  assert.equal(movida[0].id, null);
  assert.equal(movida[1].placement, "below");

  const renomeada = paginaParaGravar([a, { ...grade, title: "Tudo da loja" }]);
  assert.equal(renomeada.length, 2);
});

test("o que vai ao banco: modo no config, produtos só nas escolhidas, acima e abaixo da grade", () => {
  const banner = { ...secaoNova("image_banner"), config: { mode: "image_banner", formato: "cinema", image_url: "https://x/1.png" } };
  const escolhidos = { ...secaoNova("manual_products"), produtos: ["p1", "p2"] };
  const grade = secaoDaLinha(linha("g", { section_type: "all_products", config: { mode: "all_products" } }), []);
  const depois = { ...secaoNova("image_grid") };
  const gravar = paginaParaGravar([banner, escolhidos, grade, depois]);
  assert.deepEqual(gravar.map((s) => s.placement), ["above", "above", "above", "below"]);
  assert.equal(gravar[0].config.mode, "image_banner");
  assert.equal(gravar[0].section_type, "manual_products");
  assert.deepEqual(gravar[1].produtos, ["p1", "p2"]);
  assert.equal(gravar[0].produtos, undefined);
  assert.equal(gravar[2].section_type, "all_products");
});

test("subir e descer pulam as escondidas; o + da loja acha o lugar na lista", () => {
  const a = { ...secaoNova("image_banner"), chave: "a" };
  const b = { ...secaoNova("image_grid"), chave: "b", ativa: false };
  const c = { ...secaoNova("featured_products"), chave: "c" };
  const lista: SecaoDoEditor[] = [a, b, c];
  assert.deepEqual(moverNaPagina(lista, "c", -1).map((s) => s.chave), ["c", "a", "b"]);
  assert.equal(moverNaPagina(lista, "a", -1), lista);
  assert.equal(indiceNaLista(lista, 0), 0);
  assert.equal(indiceNaLista(lista, 1), 2);
  assert.equal(indiceNaLista(lista, 2), 3);
});

test("mudou compara o que vai ao banco", () => {
  const a = secaoDaLinha(linha("a"), ["p1"]);
  assert.equal(mudou([a], [a]), false);
  assert.equal(mudou([{ ...a, title: "Outro" }], [a]), true);
  assert.equal(mudou([{ ...a, produtos: ["p2"] }], [a]), true);
});

test("links: endereço com https, caminho da loja; incompletos barram a publicação", () => {
  assert.equal(problemaDoEndereco("https://site.com.br/x"), null);
  assert.equal(problemaDoEndereco("/aurora/c/canecas"), null);
  assert.equal(problemaDoEndereco("site.com.br"), null);
  assert.ok(problemaDoEndereco("javascript:alert(1)"));
  assert.ok(problemaDoEndereco("http://site.com.br"));
  assert.ok(problemaDoEndereco("//site.com.br"));

  const grade = {
    ...secaoNova("image_grid"),
    config: { mode: "image_grid", layout: "2", itens: [{ imagem: "https://x/1.png", link: { tipo: "produto" } }] },
  };
  const semCategoria = secaoNova("category_products");
  const problemas = problemasDaPagina([grade, semCategoria]);
  assert.equal(problemas.length, 2);
  assert.match(problemas[0].texto, /produto/);
  assert.match(problemas[1].texto, /categoria/);
  assert.equal(problemasDaPagina([{ ...semCategoria, ativa: false }]).length, 0);
});

test("a loja recebe só as ligadas, com a chave do editor", () => {
  const a = { ...secaoNova("image_banner"), chave: "a" };
  const b = { ...secaoNova("manual_products"), chave: "b", ativa: false, produtos: ["p1"] };
  const enviado = rascunhoParaALoja([a, b]);
  assert.deepEqual(enviado.map((s) => s.id), ["a"]);
  assert.equal(enviado[0].rotulo, "Banner");
});

test("mensagens da loja fora do canal ou da lista de ações são ignoradas", () => {
  assert.equal(lerMensagemDaLoja({ tipo: "acao", acao: "subir", id: "x" }), null);
  assert.equal(lerMensagemDaLoja({ canal: CANAL_DO_EDITOR, tipo: "acao", acao: "publicar", id: "x" }), null);
  assert.deepEqual(lerMensagemDaLoja({ canal: CANAL_DO_EDITOR, tipo: "acao", acao: "inserir", id: null, indice: 2 }), {
    tipo: "acao",
    acao: "inserir",
    id: null,
    indice: 2,
  });
  const pronto = lerMensagemDaLoja({
    canal: CANAL_DO_EDITOR,
    tipo: "pronto",
    tema: "vendor",
    homeEditada: false,
    arranjoAutomatico: [{ id: "auto:mais-vendidos", title: "Mais vendidos", config: { mode: "featured_products", quantidade: 4 } }, { config: { mode: "lixo" } }],
  });
  assert.ok(pronto && pronto.tipo === "pronto");
  assert.equal(pronto.tema, "vendor");
  assert.equal(pronto.arranjoAutomatico?.length, 1);
  assert.equal(pronto.arranjoAutomatico?.[0].id, null);
});

test("a passagem do painel é a mesma conta que a loja confere", () => {
  const chave = "segredo";
  const passagem = criarPassagemDoEditor({ dono: "u1", slug: "Aurora", origemDoPainel: "https://admin.ktalogu.com.br", agoraS: 1000 }, chave);
  const [carga, assinatura] = passagem.split(".");
  assert.equal(assinatura, createHmac("sha256", chave).update(`editor-da-loja:v1:${carga}`).digest("hex"));
  assert.deepEqual(JSON.parse(Buffer.from(carga, "base64url").toString()), { u: "u1", s: "aurora", o: "https://admin.ktalogu.com.br", e: 1000 + 7200 });
  assert.equal(lojaLocalValida("http://localhost:3005/"), "http://localhost:3005");
  assert.equal(lojaLocalValida("https://ruim.com"), null);
  assert.equal(lojaLocalValida("http://localhost.evil.com:3005"), null);
});
