/*
  Os produtos da loja do jeito que o catálogo em PDF desenha.

  Tudo aqui é conta, sem banco e sem rede: recebe as linhas que a vitrine
  também lê (produto ativo e na loja, com atributos, faixas de preço e
  fotos) e devolve preço, escada, cores e opções prontos para a página.

  O "a partir de" segue a regra da loja (`precoInicial` do template da
  vitrine): o menor degrau da tabela de quantidade, ou o preço cheio. Assim o
  cliente não vê um valor no PDF e outro no site.
*/

import { corDoRotulo, corPrecisaDeAnel, variacoesDaVitrine } from "./variacoes-da-loja.ts";
import type { CoresDoCatalogo, LogosDoCatalogo } from "./marca.ts";

export type PrecoDoCatalogo =
  | { tipo: "consulta"; unidade: string }
  | { tipo: "normal"; valor: number; unidade: string; aPartirDe: boolean; quantidadeRef: number | null };

export type FaixaDoCatalogo = { min: number; max: number | null; valor: number };

export type ProdutoDoCatalogo = {
  id: string;
  categoriaId: string;
  nome: string;
  descricao: string;
  url: string;
  linkWhatsapp: string;
  fotosOriginais: string[];
  /* Preenchidas depois, por quem prepara as fotos. Vazias = sem foto. */
  fotoCartao: string | null;
  fotoGrande: string | null;
  fotoCapa: string | null;
  fotoMini: string | null;
  fotosExtras: string[];
  /* Produto recortado em fundo branco (entra inteiro no quadro). */
  recorte: boolean;
  preco: PrecoDoCatalogo;
  faixas: FaixaDoCatalogo[];
  economia: number | null;
  minimo: number | null;
  cores: { label: string; hex: string; anel: boolean }[];
  nomeDasCores: string | null;
  opcoes: { nome: string; itens: { label: string; delta: number }[] }[];
};

export type CategoriaDoCatalogo = {
  id: string;
  nome: string;
  produtos: ProdutoDoCatalogo[];
  menorPreco: number | null;
};

export type WhatsappDaLoja = { numero: string; rotulo: string; link: string };

export type LojaDoCatalogo = {
  nome: string;
  slogan: string;
  urlDaLoja: string;
  urlCurta: string;
  /* `null` = a loja não cadastrou WhatsApp; o catálogo leva para a loja. */
  whatsapp: WhatsappDaLoja | null;
  instagram: { rotulo: string; link: string } | null;
  endereco: string;
  cores: CoresDoCatalogo;
  logo: LogosDoCatalogo;
  /* As pilhas de fonte do CSS, as folhas do Google e se o título ficou sem
     negrito (fonte de um peso só: aí o navegador não inventa negrito). */
  fontes: { titulo: string; texto: string; folhas: string[]; soPesoNormal: boolean };
  categorias: CategoriaDoCatalogo[];
  totais: { produtos: number; categorias: number };
  destaquesDaCapa: ProdutoDoCatalogo[];
  qrSvg: string;
  data: string;
};

/* ------------------------------------------------------------ as linhas */

/* O que o catálogo lê de cada produto. As mesmas colunas da vitrine. */
export const SELECT_DO_PRODUTO =
  "id,name,description,price,image_url,unit_type,price_on_request,use_variation_price_only,min_sale_qty_enabled,min_sale_qty,category_id,catalog_position,created_at," +
  "product_attributes(id,name,options,is_required,position,show_in_store,display_style,allow_multiple)," +
  "product_price_tiers(min_qty,max_qty,unit_price,sort_order,active)," +
  "product_images(image_url,sort_order,is_primary)";

export type LinhaDoProduto = {
  id: string;
  name: string | null;
  description: string | null;
  price: number | string | null;
  image_url: string | null;
  unit_type: string | null;
  price_on_request: boolean | null;
  min_sale_qty_enabled: boolean | null;
  min_sale_qty: number | string | null;
  category_id: string | null;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  product_attributes?: any[] | null;
  product_price_tiers?: { min_qty: number | string | null; max_qty: number | string | null; unit_price: number | string | null; active?: boolean | null }[] | null;
  product_images?: { image_url: string | null; sort_order: number | null; is_primary: boolean | null }[] | null;
};

export type LinhaDaCategoria = { id: string; name: string | null; parent_id: string | null };

/* ------------------------------------------------------------- contatos */

export function whatsappDaLoja(numeroBruto: unknown): WhatsappDaLoja | null {
  let d = String(numeroBruto ?? "").replace(/\D/g, "");
  if (d.length < 10) return null;
  if (d.length <= 11) d = `55${d}`;
  const local = d.slice(2);
  const rotulo =
    local.length === 11
      ? `(${local.slice(0, 2)}) ${local.slice(2, 7)}-${local.slice(7)}`
      : local.length === 10
        ? `(${local.slice(0, 2)}) ${local.slice(2, 6)}-${local.slice(6)}`
        : local;
  return { numero: d, rotulo, link: `https://wa.me/${d}` };
}

export function instagramDaLoja(bruto: unknown) {
  const t = String(bruto ?? "").trim();
  if (!t) return null;
  const usuario = t
    .replace(/^https?:\/\/(www\.)?instagram\.com\//i, "")
    .replace(/[/?#].*$/, "")
    .replace(/^@/, "")
    .trim();
  if (!usuario || usuario.length > 60 || /\s/.test(usuario)) return null;
  return { rotulo: `@${usuario}`, link: `https://instagram.com/${encodeURIComponent(usuario)}` };
}

/* A descrição vem em HTML do editor. Aqui vira uma linha de texto. */
export function textoPuro(html: unknown, limite: number) {
  const t = String(html ?? "")
    .replace(/<style[\s\S]*?<\/style>|<script[\s\S]*?<\/script>/gi, " ")
    .replace(/<[^>]+>/g, " ")
    .replace(/&nbsp;/gi, " ")
    .replace(/&quot;/gi, '"')
    .replace(/&#39;|&apos;/gi, "'")
    .replace(/&lt;/gi, "<")
    .replace(/&gt;/gi, ">")
    .replace(/&amp;/gi, "&")
    .replace(/\s+/g, " ")
    .trim();
  return t.length > limite ? `${t.slice(0, limite).trimEnd()}…` : t;
}

/* ------------------------------------------------------------- produto */

export function montarProduto(
  bruto: LinhaDoProduto,
  contexto: { urlDoProduto: (id: string) => string; whatsapp: WhatsappDaLoja | null; categoriaId: string }
): ProdutoDoCatalogo {
  const galeria = [...(bruto.product_images || [])]
    .filter((img) => img && img.image_url)
    .sort((a, b) => Number(b.is_primary === true) - Number(a.is_primary === true) || (a.sort_order ?? 0) - (b.sort_order ?? 0))
    .map((img) => String(img.image_url));
  const fotos = [...new Set([bruto.image_url, ...galeria].map((url) => String(url ?? "").trim()).filter(Boolean))];

  const faixas: FaixaDoCatalogo[] = (bruto.product_price_tiers || [])
    .filter((t) => t && t.active !== false && Number(t.unit_price) > 0)
    .sort((a, b) => Number(a.min_qty) - Number(b.min_qty))
    .map((t) => ({
      min: Number(t.min_qty) || 0,
      max: t.max_qty === null || t.max_qty === undefined || t.max_qty === "" ? null : Number(t.max_qty),
      valor: Number(t.unit_price),
    }));

  const variacoes = variacoesDaVitrine(bruto.product_attributes || []);
  const atributoDeCor = variacoes.escolhas.find((a) => a.estilo === "cores");
  const cores = (atributoDeCor?.opcoes || []).map((op) => {
    const cor = op.swatch ? { tipo: "chapada" as const, fundo: op.swatch } : corDoRotulo(op.label);
    return { label: op.label, hex: cor?.fundo || "#CBD5E1", anel: cor ? corPrecisaDeAnel(cor) : false };
  });
  const opcoes = variacoes.escolhas
    .filter((a) => a !== atributoDeCor)
    .map((a) => ({ nome: a.nome, itens: a.opcoes.map((op) => ({ label: op.label, delta: Number(op.preco) || 0 })) }));

  const unidade = bruto.unit_type === "square_meter" ? "m²" : "un";
  const menor = faixas.length ? faixas.reduce((a, b) => (b.valor < a.valor ? b : a)) : null;
  const minimo = bruto.min_sale_qty_enabled && Number(bruto.min_sale_qty) > 1 ? Number(bruto.min_sale_qty) : null;
  const preco: PrecoDoCatalogo = bruto.price_on_request
    ? { tipo: "consulta", unidade }
    : {
        tipo: "normal",
        valor: menor ? menor.valor : Number(bruto.price) || 0,
        unidade,
        aPartirDe: faixas.length > 1 || opcoes.some((a) => a.itens.some((i) => i.delta > 0)),
        quantidadeRef: menor ? (menor.min > 1 ? menor.min : null) : minimo,
      };

  const nome = String(bruto.name || "").trim();
  const url = contexto.urlDoProduto(bruto.id);
  const mensagem = `Olá! Vi no catálogo e quero saber mais sobre: ${nome}\n${url}`;
  return {
    id: bruto.id,
    categoriaId: contexto.categoriaId,
    nome,
    descricao: textoPuro(bruto.description, 170),
    url,
    linkWhatsapp: contexto.whatsapp ? `https://wa.me/${contexto.whatsapp.numero}?text=${encodeURIComponent(mensagem)}` : url,
    fotosOriginais: fotos,
    fotoCartao: null,
    fotoGrande: null,
    fotoCapa: null,
    fotoMini: null,
    fotosExtras: [],
    recorte: false,
    preco,
    faixas,
    economia: faixas.length > 1 ? Math.round(((faixas[0].valor - faixas[faixas.length - 1].valor) / faixas[0].valor) * 100) : null,
    minimo,
    cores,
    nomeDasCores: atributoDeCor?.nome || null,
    opcoes,
  };
}

/* --------------------------------------------------------- categorias */

export const ID_DOS_OUTROS = "outros";

/* A categoria de topo de cada categoria (o catálogo agrupa pelas de cima). */
export function raizesDasCategorias(categorias: LinhaDaCategoria[]) {
  const porId = new Map(categorias.map((c) => [c.id, c]));
  return (id: string | null | undefined) => {
    let atual = id ? porId.get(id) : undefined;
    for (let i = 0; i < 6 && atual?.parent_id && porId.get(atual.parent_id); i += 1) atual = porId.get(atual.parent_id);
    return atual || null;
  };
}

/* As categorias de topo em que a loja tem produto, na ordem da loja, e
   "Outros produtos" no fim para quem não tem categoria visível. */
export function agruparPorCategoria(produtos: ProdutoDoCatalogo[], categorias: LinhaDaCategoria[]): CategoriaDoCatalogo[] {
  const porId = new Map(categorias.map((c) => [c.id, c]));
  const grupos: CategoriaDoCatalogo[] = [];
  for (const cat of categorias) {
    if (cat.parent_id && porId.get(cat.parent_id)) continue;
    const doGrupo = produtos.filter((p) => p.categoriaId === cat.id);
    if (doGrupo.length) grupos.push({ id: cat.id, nome: String(cat.name || "").trim() || "Produtos", produtos: doGrupo, menorPreco: null });
  }
  const soltos = produtos.filter((p) => !grupos.some((g) => g.id === p.categoriaId));
  if (soltos.length) grupos.push({ id: ID_DOS_OUTROS, nome: "Outros produtos", produtos: soltos, menorPreco: null });
  for (const g of grupos) {
    const valores = g.produtos
      .map((p) => p.preco)
      .filter((preco): preco is Extract<PrecoDoCatalogo, { tipo: "normal" }> => preco.tipo === "normal" && preco.valor > 0)
      .map((preco) => preco.valor);
    g.menorPreco = valores.length ? Math.min(...valores) : null;
  }
  return grupos;
}

/* Capa: um produto com foto de cada categoria, em rodízio. */
export function destaquesDaCapa(grupos: CategoriaDoCatalogo[]) {
  const destaques: ProdutoDoCatalogo[] = [];
  for (let volta = 0; destaques.length < 8 && volta < 10; volta += 1) {
    for (const g of grupos) {
      const comFoto = g.produtos.filter((p) => p.fotoCapa);
      if (comFoto[volta] && destaques.length < 8) destaques.push(comFoto[volta]);
    }
  }
  const semFoto = grupos.flatMap((g) => g.produtos).filter((p) => !p.fotoCapa);
  while (destaques.length < 8 && semFoto.length) destaques.push(semFoto.shift() as ProdutoDoCatalogo);
  return destaques;
}
