/*
 * O desenho de cada peça, guardado pela própria peça (as peças nunca são
 * alteradas no lugar: mudou, é outro objeto). Assim o React recebe o MESMO
 * objeto `{ __html }` quando nada mudou e não regrava o HTML. Sem isto, cada
 * desenho novo do palco reescrevia todas as peças: pesado, e o nó clicado
 * sumia entre o apertar e o soltar (o duplo clique se perdia).
 */
import { caixaDaPeca, camadaDoFundo, conteudoDaPeca, exibicaoDaPeca, type ContagemDaPagina, type FundoDoBanner, type Peca } from "@/lib/banner-editor/documento";
import { versaoDosVetores } from "@/lib/banner-editor/vetores";

/* O SVG com cor trocada chega depois: a peça com vetor refaz o desenho quando chega texto novo (`versao`). */
const versaoDa = (p: Peca) => (p.tipo === "imagem" && p.vetor ? versaoDosVetores() : 0);
const daPeca = new WeakMap<Peca, { __html: string; versao: number }>();
const doFundo = new WeakMap<FundoDoBanner, Map<string, { __html: string }>>();

export function htmlDaPeca(p: Peca) {
  const versao = versaoDa(p);
  let guardado = daPeca.get(p);
  if (!guardado || guardado.versao !== versao) {
    guardado = { __html: conteudoDaPeca(p), versao };
    daPeca.set(p, guardado);
  }
  return guardado;
}

/*
 * Como a peça aparece (com a casca do "colocar dentro de" e o recheio do texto):
 * guardado pela peça e pelas que mexem nela (o recipiente ou o recheio), para
 * só refazer quando uma delas mudar.
 */
const exibida = new WeakMap<Peca, { ligadas: Peca[]; conta: string; versao: number; estilo: Record<string, string>; html: { __html: string } } | { ligadas: Peca[]; conta: string; versao: number; nada: true }>();
export function exibicaoGuardada(p: Peca, pecas: Peca[], contagem?: ContagemDaPagina | null) {
  const ligadas = pecas.filter((q) => q.id === p.dentroDe || q.dentroDe === p.id);
  /* O contador ("01/05") muda com a página: entra na chave só da peça que tem o contador. */
  const temContador = p.tipo === "texto" && /\{(pagina|total)\}/.test(p.texto + (p.html || ""));
  const conta = temContador && contagem ? `${contagem.pagina}/${contagem.total}` : "";
  const guardada = exibida.get(p);
  const versao = versaoDa(p);
  if (guardada && guardada.versao === versao && guardada.conta === conta && guardada.ligadas.length === ligadas.length && guardada.ligadas.every((q, i) => q === ligadas[i])) return "nada" in guardada ? null : guardada;
  /* Sem recipiente, recheio nem contador (o comum): a caixa de sempre e o desenho já guardado. */
  const ex = ligadas.length || conta ? exibicaoDaPeca(p, pecas, undefined, contagem) : { estilo: caixaDaPeca(p) as Record<string, string>, html: "" };
  const nova = ex ? { ligadas, conta, versao, estilo: ex.estilo, html: ligadas.length || conta ? { __html: ex.html } : htmlDaPeca(p) } : { ligadas, conta, versao, nada: true as const };
  exibida.set(p, nova);
  return "nada" in nova ? null : nova;
}

export function htmlDoFundo(fundo: FundoDoBanner, largura: number, altura: number) {
  let porTamanho = doFundo.get(fundo);
  if (!porTamanho) {
    porTamanho = new Map();
    doFundo.set(fundo, porTamanho);
  }
  const chave = `${largura}x${altura}`;
  let guardado = porTamanho.get(chave);
  if (!guardado) {
    guardado = { __html: camadaDoFundo(fundo, largura, altura) };
    porTamanho.set(chave, guardado);
  }
  return guardado;
}
