/*
  O que a pessoa escolhe antes de baixar o catálogo em PDF.

  Tudo aqui chega do navegador, então nada é confiado: o que não for uma das
  escolhas conhecidas volta para o padrão, e texto livre tem tamanho máximo.
  O padrão é o catálogo que o Natan aprovou em 19/09/2026: celular, vitrine
  de 4 por página, com preço, tabela de quantidade, botão Comprar, índice e
  páginas de abertura.
*/

export type FormatoDoCatalogo = "celular" | "a4";
/* Só vale no celular. O A4 é sempre a grade de 6 por página. */
export type LayoutDoCatalogo = "vitrine" | "destaque";
/* Para onde o toque no produto leva. */
export type BotaoDoCatalogo = "loja" | "whatsapp" | "nenhum";

export type OpcoesDoCatalogo = {
  formato: FormatoDoCatalogo;
  layout: LayoutDoCatalogo;
  /* `null` = a loja inteira. */
  categorias: string[] | null;
  mostrarPreco: boolean;
  /* A tabela "quanto mais, menos paga" e o selo "até -35%". */
  mostrarEscada: boolean;
  botao: BotaoDoCatalogo;
  /* O selo da capa ("Catálogo 2026"). */
  titulo: string;
  /* A frase grande da capa. Vazia = o slogan da loja, ou o nome dela. */
  subtitulo: string;
  indice: boolean;
  /* Página de abertura de cada categoria grande. */
  divisores: boolean;
  /* Deixa de fora quem não tem foto. */
  soComFoto: boolean;
};

export const LIMITE_DO_TITULO = 40;
export const LIMITE_DO_SUBTITULO = 90;
export const LIMITE_DE_CATEGORIAS = 200;

/* Quantos produtos cabem num PDF que ainda se manda pelo WhatsApp. A maior
   loja tem 246 produtos: na vitrine (4 por página) ela cabe inteira; no
   destaque (1 por página) seriam 246 páginas, e aí a pessoa escolhe as
   categorias. */
export const LIMITE_DE_PRODUTOS = { grade: 300, destaque: 80 } as const;

export function tituloPadrao(ano: number) {
  return `Catálogo ${ano}`;
}

/* O ano de quem gera, não o do servidor: na virada, a VPS em UTC já estaria
   no ano seguinte três horas antes do Brasil. */
export function anoEmSaoPaulo(agora = new Date()) {
  return Number(new Intl.DateTimeFormat("en-US", { timeZone: "America/Sao_Paulo", year: "numeric" }).format(agora));
}

export function opcoesPadrao(ano: number): OpcoesDoCatalogo {
  return {
    formato: "celular",
    layout: "vitrine",
    categorias: null,
    mostrarPreco: true,
    mostrarEscada: true,
    botao: "loja",
    titulo: tituloPadrao(ano),
    subtitulo: "",
    indice: true,
    divisores: true,
    soComFoto: false,
  };
}

/* O destaque (1 produto por página) só existe no celular. */
export function emDestaque(opcoes: Pick<OpcoesDoCatalogo, "formato" | "layout">) {
  return opcoes.formato === "celular" && opcoes.layout === "destaque";
}

export function limiteDeProdutos(opcoes: Pick<OpcoesDoCatalogo, "formato" | "layout">) {
  return emDestaque(opcoes) ? LIMITE_DE_PRODUTOS.destaque : LIMITE_DE_PRODUTOS.grade;
}

/* Uma linha só, sem espaço sobrando e sem caractere de controle. */
function textoCurto(valor: unknown, limite: number) {
  return Array.from(String(valor ?? ""))
    .map((letra) => (letra.charCodeAt(0) < 32 || letra.charCodeAt(0) === 127 ? " " : letra))
    .join("")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, limite)
    .trim();
}

function escolha<T extends string>(valor: unknown, aceitas: readonly T[], padrao: T): T {
  return aceitas.includes(valor as T) ? (valor as T) : padrao;
}

function ligado(valor: unknown, padrao: boolean) {
  return typeof valor === "boolean" ? valor : padrao;
}

export function lerOpcoes(bruto: unknown, ano: number): OpcoesDoCatalogo {
  const padrao = opcoesPadrao(ano);
  const dado = bruto && typeof bruto === "object" && !Array.isArray(bruto) ? (bruto as Record<string, unknown>) : {};

  const categorias = Array.isArray(dado.categorias)
    ? [...new Set(dado.categorias.map((id) => String(id ?? "").trim()).filter((id) => id && id.length <= 80))].slice(0, LIMITE_DE_CATEGORIAS)
    : null;

  return {
    formato: escolha(dado.formato, ["celular", "a4"] as const, padrao.formato),
    layout: escolha(dado.layout, ["vitrine", "destaque"] as const, padrao.layout),
    /* Lista vazia é "nenhuma escolhida", e isso não gera catálogo: vale
       como a loja inteira, que é o que a tela mostra marcado. */
    categorias: categorias && categorias.length ? categorias : null,
    mostrarPreco: ligado(dado.mostrarPreco, padrao.mostrarPreco),
    mostrarEscada: ligado(dado.mostrarEscada, padrao.mostrarEscada),
    botao: escolha(dado.botao, ["loja", "whatsapp", "nenhum"] as const, padrao.botao),
    titulo: textoCurto(dado.titulo, LIMITE_DO_TITULO) || padrao.titulo,
    subtitulo: textoCurto(dado.subtitulo, LIMITE_DO_SUBTITULO),
    indice: ligado(dado.indice, padrao.indice),
    divisores: ligado(dado.divisores, padrao.divisores),
    soComFoto: ligado(dado.soComFoto, padrao.soComFoto),
  };
}
