/*
 * A aparência da loja pelo assistente: as regras sem banco (o que cada campo
 * é, como conferir cor e fonte, o que muda). Sem importação com "@/" para o
 * teste rodar no `node --test` puro (ver ../loja-e-documentos.test.ts).
 *
 * As colunas são as mesmas que a tela Catálogo › Aparência grava
 * (app/dashboard/catalog/page.tsx): vazio vira NULL, que é como a loja sabe
 * que deve usar o padrão dela.
 */

/* As fontes que a personalização avançada oferece. A CHAVE é a gravada no
   banco; a lista é a mesma de lib/catalog-fonts.ts, que é gerado por
   scripts/gen_fonts.py. O teste confere que as duas listas são iguais. */
export const FONTES_DA_LOJA: ReadonlyArray<readonly [string, string]> = [
  ["fraunces", "Fraunces — serifada com personalidade"],
  ["playfair-display", "Playfair Display — editorial clássica"],
  ["instrument-serif", "Instrument Serif — serifada enxuta"],
  ["lora", "Lora — leitura confortável"],
  ["eb-garamond", "EB Garamond — clássica atemporal"],
  ["cormorant-garamond", "Cormorant Garamond — refinada e fina"],
  ["libre-baskerville", "Libre Baskerville — livro tradicional"],
  ["crimson-pro", "Crimson Pro — humanista elegante"],
  ["merriweather", "Merriweather — robusta e legível"],
  ["source-serif-4", "Source Serif — técnica com serifa"],
  ["spectral", "Spectral — serifada contemporânea"],
  ["newsreader", "Newsreader — jornalística"],
  ["literata", "Literata — editorial moderna"],
  ["dm-serif-display", "DM Serif Display — títulos de alto contraste"],
  ["bodoni-moda", "Bodoni Moda — luxo e moda"],
  ["marcellus", "Marcellus — romana sofisticada"],
  ["syne", "Syne — display marcante"],
  ["unbounded", "Unbounded — geométrica forte"],
  ["anton", "Anton — condensada de alto impacto"],
  ["bebas-neue", "Bebas Neue — caixa alta esportiva"],
  ["archivo-black", "Archivo Black — peso máximo"],
  ["abril-fatface", "Abril Fatface — cartaz clássico"],
  ["alfa-slab-one", "Alfa Slab One — serifa pesada"],
  ["righteous", "Righteous — retrô arredondada"],
  ["darker-grotesque", "Darker Grotesque — condensada alternativa"],
  ["bricolage-grotesque", "Bricolage Grotesque — contemporânea"],
  ["space-grotesk", "Space Grotesk — técnica"],
  ["sora", "Sora — moderna equilibrada"],
  ["manrope", "Manrope — limpa e arredondada"],
  ["dm-sans", "DM Sans — neutra elegante"],
  ["outfit", "Outfit — geométrica leve"],
  ["figtree", "Figtree — amigável"],
  ["epilogue", "Epilogue — contrastada"],
  ["work-sans", "Work Sans — versátil"],
  ["inter", "Inter — padrão de interface"],
  ["plus-jakarta-sans", "Plus Jakarta Sans — sofisticada"],
  ["urbanist", "Urbanist — geométrica minimalista"],
  ["jost", "Jost — inspirada na Futura"],
  ["lexend", "Lexend — foco em legibilidade"],
  ["albert-sans", "Albert Sans — geométrica suave"],
  ["onest", "Onest — neutra atual"],
  ["schibsted-grotesk", "Schibsted Grotesk — editorial digital"],
  ["hanken-grotesk", "Hanken Grotesk — grotesca amigável"],
  ["archivo", "Archivo — grotesca de alto desempenho"],
  ["poppins", "Poppins — geométrica popular"],
  ["montserrat", "Montserrat — urbana e conhecida"],
  ["raleway", "Raleway — elegante e fina"],
  ["nunito", "Nunito — arredondada acolhedora"],
  ["nunito-sans", "Nunito Sans — versão sóbria"],
  ["rubik", "Rubik — cantos suaves"],
  ["karla", "Karla — grotesca compacta"],
  ["lato", "Lato — corporativa clássica"],
  ["open-sans", "Open Sans — neutra universal"],
  ["roboto", "Roboto — padrão do Android"],
  ["source-sans-3", "Source Sans — limpa e técnica"],
  ["quicksand", "Quicksand — leve e arredondada"],
  ["jetbrains-mono", "JetBrains Mono — monoespaçada moderna"],
  ["ibm-plex-mono", "IBM Plex Mono — técnica corporativa"],
  ["space-mono", "Space Mono — retrô futurista"],
  ["roboto-mono", "Roboto Mono — monoespaçada neutra"],
  ["caveat", "Caveat — manuscrita espontânea"],
  ["dancing-script", "Dancing Script — caligráfica alegre"],
  ["pacifico", "Pacifico — script descontraída"],
  ["sacramento", "Sacramento — fina e delicada"],
  ["great-vibes", "Great Vibes — caligrafia formal"],
];

/* Os modelos que dá para escolher. O "neo" ainda é aceito pelo banco, mas a
   tela Catálogo não o oferece e a loja o desenha como o Padrão: quem já o tem
   lê "Padrão", e o assistente nunca o escolhe. */
export const TEMAS = ["default", "vitrine", "vendor", "boutique"] as const;
export type Tema = (typeof TEMAS)[number];
export const NOME_DO_TEMA: Record<Tema, string> = { default: "Padrão", vitrine: "Vitrine", vendor: "Vendor", boutique: "Ateliê" };
const TEMA_PELO_NOME: Record<string, Tema> = {
  padrao: "default",
  default: "default",
  vitrine: "vitrine",
  vendor: "vendor",
  atelie: "boutique",
  /* O nome antigo do modelo: quem ainda o chama assim cai no mesmo. */
  boutique: "boutique",
};

export type TipoDoCampo = "texto" | "cor" | "fonte";

export type CampoDaAparencia = {
  coluna: string;
  tipo: TipoDoCampo;
  rotulo: string;
  /* Só aparece na loja com a personalização avançada ligada. */
  avancado?: boolean;
  max?: number;
  /* Não pode ficar vazio (a cor principal). */
  obrigatorio?: boolean;
};

/* O nome do campo para o assistente → a coluna do perfil. */
export const CAMPOS_DA_APARENCIA: Record<string, CampoDaAparencia> = {
  nome: { coluna: "catalog_name", tipo: "texto", rotulo: "Nome da loja", max: 80 },
  slogan: { coluna: "catalog_slogan", tipo: "texto", rotulo: "Slogan", max: 160 },
  cor_principal: { coluna: "primary_color", tipo: "cor", rotulo: "Cor principal", obrigatorio: true },
  cor_do_nome: { coluna: "catalog_name_color", tipo: "cor", rotulo: "Cor do nome no cabeçalho" },
  cor_do_slogan: { coluna: "catalog_slogan_color", tipo: "cor", rotulo: "Cor do slogan no cabeçalho" },
  cor_dos_icones: { coluna: "catalog_header_icon_color", tipo: "cor", rotulo: "Cor dos ícones do cabeçalho" },
  cor_do_rodape: { coluna: "catalog_footer_color", tipo: "cor", rotulo: "Cor do rodapé" },
  cor_do_cabecalho: { coluna: "catalog_header_color", tipo: "cor", rotulo: "Cor do cabeçalho", avancado: true },
  cor_do_texto_do_cabecalho: { coluna: "catalog_header_text_color", tipo: "cor", rotulo: "Cor do texto do cabeçalho", avancado: true },
  cor_do_menu: { coluna: "catalog_menu_color", tipo: "cor", rotulo: "Cor da barra do menu", avancado: true },
  cor_do_texto_do_menu: { coluna: "catalog_menu_text_color", tipo: "cor", rotulo: "Cor do texto do menu", avancado: true },
  cor_do_fundo: { coluna: "catalog_page_bg_color", tipo: "cor", rotulo: "Cor do fundo da página", avancado: true },
  cor_dos_botoes: { coluna: "catalog_card_button_color", tipo: "cor", rotulo: "Cor dos botões dos produtos", avancado: true },
  cor_da_barra_de_compra: { coluna: "catalog_buybar_bg_color", tipo: "cor", rotulo: "Cor da barra de compra", avancado: true },
  cor_do_botao_de_compra: { coluna: "catalog_buybar_button_color", tipo: "cor", rotulo: "Cor do botão da barra de compra", avancado: true },
  cor_do_texto_da_barra_de_compra: { coluna: "catalog_buybar_text_color", tipo: "cor", rotulo: "Cor dos textos da barra de compra", avancado: true },
  fonte_dos_titulos: { coluna: "catalog_font_heading", tipo: "fonte", rotulo: "Fonte dos títulos", avancado: true },
  fonte_dos_textos: { coluna: "catalog_font_body", tipo: "fonte", rotulo: "Fonte dos textos", avancado: true },
  titulo_no_google: { coluna: "catalog_meta_title", tipo: "texto", rotulo: "Título no Google", max: 70 },
  descricao_no_google: { coluna: "catalog_meta_description", tipo: "texto", rotulo: "Descrição no Google", max: 200 },
  titulo_ao_compartilhar: { coluna: "catalog_og_title", tipo: "texto", rotulo: "Título ao compartilhar o link", max: 90 },
  descricao_ao_compartilhar: { coluna: "catalog_og_description", tipo: "texto", rotulo: "Descrição ao compartilhar o link", max: 200 },
};

/* As colunas que a leitura busca. */
export const COLUNAS_DA_APARENCIA = [
  "id",
  "slug",
  "store_name",
  "logo_url",
  "catalog_logo_url",
  "catalog_favicon_url",
  "catalog_og_image_url",
  "catalog_theme",
  "catalog_advanced_enabled",
  ...new Set(Object.values(CAMPOS_DA_APARENCIA).map((campo) => campo.coluna)),
].join(",");

/** "#abc", "abc", "#aabbcc" → "#AABBCC" (como a tela grava). `null` = não é uma cor. */
export function corHex(valor: unknown): string | null {
  const limpo = String(valor ?? "").trim().replace(/^#/, "").toUpperCase();
  if (/^[0-9A-F]{6}$/.test(limpo)) return `#${limpo}`;
  if (/^[0-9A-F]{3}$/.test(limpo)) return `#${limpo.split("").map((letra) => letra + letra).join("")}`;
  return null;
}

function semAcento(valor: string) {
  return valor.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
}

/** A chave da fonte pelo que o assistente mandou: a chave ("dm-sans") ou o nome ("DM Sans"). */
export function chaveDaFonte(valor: unknown): string | null {
  const pedido = semAcento(String(valor ?? "")).replace(/\s+/g, " ");
  if (!pedido) return null;
  const comoChave = pedido.replace(/[\s_]+/g, "-");
  for (const [chave, rotulo] of FONTES_DA_LOJA) {
    if (chave === comoChave) return chave;
    if (semAcento(rotulo.split("—")[0]) === pedido) return chave;
  }
  return null;
}

export function nomeDaFonte(chave: string | null | undefined) {
  if (!chave) return null;
  const achada = FONTES_DA_LOJA.find(([candidata]) => candidata === chave);
  return achada ? achada[1].split("—")[0].trim() : chave;
}

export function temaPeloNome(valor: unknown): Tema | null {
  return TEMA_PELO_NOME[semAcento(String(valor ?? ""))] ?? null;
}

export type MudancaDaAparencia = {
  /* Coluna → valor novo (null = volta ao padrão da loja). */
  colunas: Record<string, string | boolean | null>;
  /* O valor de antes de cada coluna que muda: é o que desfaz. */
  antes: Record<string, string | boolean | null>;
  /* Linhas legíveis do que muda, para a prévia e o resultado. */
  linhas: Array<{ campo: string; antes: string; depois: string }>;
  avisos: string[];
};

function legivel(campo: CampoDaAparencia, valor: unknown) {
  if (valor === null || valor === undefined || valor === "") return "padrão da loja";
  if (campo.tipo === "fonte") return nomeDaFonte(String(valor)) ?? String(valor);
  return String(valor);
}

export type PedidoDeAparencia = {
  valores: Record<string, unknown>;
  voltarAoPadrao: string[];
  tema?: unknown;
  avancada?: unknown;
};

/**
 * Do que o assistente pediu às colunas que mudam, conferindo cada valor.
 * `atual` é o perfil como está (para o "antes" e para saber se a
 * personalização avançada está ligada).
 */
export function montarMudancaDaAparencia(
  pedido: PedidoDeAparencia,
  atual: Record<string, unknown>
): { ok: true; mudanca: MudancaDaAparencia } | { ok: false; erro: string } {
  const colunas: MudancaDaAparencia["colunas"] = {};
  const antesDasColunas: MudancaDaAparencia["antes"] = {};
  const linhas: MudancaDaAparencia["linhas"] = [];
  const avisos: string[] = [];
  let mexeNoAvancado = false;

  const anotar = (campo: CampoDaAparencia, valor: string | null) => {
    const antes = ((atual[campo.coluna] as string | null | undefined) ?? null) || null;
    if (antes === valor) return;
    colunas[campo.coluna] = valor;
    antesDasColunas[campo.coluna] = antes;
    linhas.push({ campo: campo.rotulo, antes: legivel(campo, antes), depois: legivel(campo, valor) });
    if (campo.avancado) mexeNoAvancado = true;
  };

  for (const [nome, bruto] of Object.entries(pedido.valores)) {
    const campo = CAMPOS_DA_APARENCIA[nome];
    if (!campo || bruto === undefined || bruto === null) continue;
    if (pedido.voltarAoPadrao.includes(nome)) {
      return { ok: false, erro: `"${nome}" veio com um valor novo e também em voltar_ao_padrao. Escolha um dos dois.` };
    }
    if (campo.tipo === "cor") {
      const cor = corHex(bruto);
      if (!cor) return { ok: false, erro: `${campo.rotulo}: "${String(bruto)}" não é uma cor. Use o código da cor, como #1f6feb.` };
      anotar(campo, cor);
    } else if (campo.tipo === "fonte") {
      const chave = chaveDaFonte(bruto);
      if (!chave) return { ok: false, erro: `${campo.rotulo}: a fonte "${String(bruto)}" não está na lista. Veja as fontes em ver_aparencia_da_loja.` };
      anotar(campo, chave);
    } else {
      const texto = String(bruto).replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
      if (!texto) continue;
      if (campo.max && texto.length > campo.max) return { ok: false, erro: `${campo.rotulo}: até ${campo.max} letras.` };
      anotar(campo, texto);
    }
  }

  for (const nome of pedido.voltarAoPadrao) {
    const campo = CAMPOS_DA_APARENCIA[nome];
    if (!campo) {
      return { ok: false, erro: `voltar_ao_padrao: "${nome}" não é um campo da aparência. Campos: ${Object.keys(CAMPOS_DA_APARENCIA).join(", ")}.` };
    }
    if (campo.obrigatorio) return { ok: false, erro: `${campo.rotulo} não pode ficar em branco: mande uma cor nova.` };
    anotar(campo, null);
  }

  if (pedido.tema !== undefined && pedido.tema !== null) {
    const tema = temaPeloNome(pedido.tema);
    if (!tema) return { ok: false, erro: `Modelo desconhecido. Use um destes: ${TEMAS.map((t) => NOME_DO_TEMA[t]).join(", ")}.` };
    const antes: Tema = TEMAS.includes(atual.catalog_theme as Tema) ? (atual.catalog_theme as Tema) : "default";
    /* Compara com o gravado: o "neo" antigo lê como Padrão, mas escolher
       Padrão grava "default" de verdade. */
    if ((atual.catalog_theme ?? "default") !== tema) {
      colunas.catalog_theme = tema;
      antesDasColunas.catalog_theme = (atual.catalog_theme as string | null | undefined) ?? null;
      linhas.push({ campo: "Modelo da loja", antes: NOME_DO_TEMA[antes], depois: NOME_DO_TEMA[tema] });
    }
  }

  const avancadaHoje = atual.catalog_advanced_enabled === true;
  if (typeof pedido.avancada === "boolean") {
    if (pedido.avancada !== avancadaHoje) {
      colunas.catalog_advanced_enabled = pedido.avancada;
      antesDasColunas.catalog_advanced_enabled = avancadaHoje;
      linhas.push({ campo: "Personalização avançada", antes: avancadaHoje ? "ligada" : "desligada", depois: pedido.avancada ? "ligada" : "desligada" });
    }
    if (pedido.avancada === false && mexeNoAvancado) {
      avisos.push("A personalização avançada fica desligada: as cores e fontes avançadas ficam guardadas, mas só aparecem na loja quando ela for ligada.");
    }
  } else if (mexeNoAvancado && !avancadaHoje) {
    /* Escolher uma cor avançada e ela não aparecer na loja seria a pior surpresa. */
    colunas.catalog_advanced_enabled = true;
    antesDasColunas.catalog_advanced_enabled = false;
    linhas.push({ campo: "Personalização avançada", antes: "desligada", depois: "ligada" });
    avisos.push("A personalização avançada foi ligada junto, porque estas cores e fontes só aparecem na loja com ela ligada.");
  }

  if (!linhas.length) return { ok: false, erro: "Nada muda: a loja já está assim." };
  return { ok: true, mudanca: { colunas, antes: antesDasColunas, linhas, avisos } };
}
