import type { Caixa } from "@/lib/banner-editor/animacao";
import type { UnidadeDaCena } from "@/lib/banner-editor/cena";
import type { DocumentoDoBanner, PecaDeTexto } from "@/lib/banner-editor/documento";
import { exibicaoGuardada } from "./desenho-guardado";

/*
 * Onde cada palavra do texto fica na página, para a entrada palavra por
 * palavra: o texto é desenhado escondido, com o mesmo HTML do palco e do
 * vídeo, e o navegador diz a caixa de cada palavra (a quebra de linha é a
 * dele, igual à da camada que o servidor fotografa). Guardado por peça.
 */

const MAXIMO_DE_PALAVRAS = 80;
const medidas = new WeakMap<PecaDeTexto, Caixa[] | null>();

function medir(pagina: DocumentoDoBanner, peca: PecaDeTexto): Caixa[] | null {
  const ex = exibicaoGuardada(peca, pagina.pecas);
  if (!ex) return null;
  const folha = document.createElement("div");
  folha.setAttribute("aria-hidden", "true");
  Object.assign(folha.style, { position: "fixed", left: "-200000px", top: "0", width: `${pagina.largura}px`, height: `${pagina.altura}px`, visibility: "hidden", pointerEvents: "none", contain: "layout" });
  const caixa = document.createElement("div");
  Object.assign(caixa.style, { position: "absolute", ...ex.estilo });
  caixa.innerHTML = ex.html.__html;
  folha.appendChild(caixa);
  document.body.appendChild(folha);
  try {
    const base = folha.getBoundingClientRect();
    const f = base.width / pagina.largura || 1;
    const caixas: Caixa[] = [];
    const andador = document.createTreeWalker(caixa, NodeFilter.SHOW_TEXT);
    for (let no = andador.nextNode(); no; no = andador.nextNode()) {
      const texto = no.textContent || "";
      for (const m of texto.matchAll(/\S+/g)) {
        const trecho = document.createRange();
        trecho.setStart(no, m.index);
        trecho.setEnd(no, m.index + m[0].length);
        /* A palavra quebrada em duas linhas vira duas caixas. */
        for (const r of trecho.getClientRects()) {
          if (r.width < 0.5 || r.height < 0.5) continue;
          caixas.push({ x: (r.left - base.left) / f, y: (r.top - base.top) / f, w: r.width / f, h: r.height / f });
        }
        if (caixas.length > MAXIMO_DE_PALAVRAS) return null;
      }
    }
    return caixas.length > 1 ? caixas : null;
  } finally {
    folha.remove();
  }
}

/** As unidades com as caixas das palavras nas que entram palavra por palavra (um texto sozinho). */
export function comPalavras(pagina: DocumentoDoBanner, unidades: UnidadeDaCena[]): UnidadeDaCena[] {
  if (typeof document === "undefined") return unidades;
  return unidades.map((u) => {
    if (!u.animacao?.porPalavra || u.ids.length !== 1) return u;
    const peca = pagina.pecas.find((p) => p.id === u.ids[0]);
    if (!peca || peca.tipo !== "texto") return u;
    if (!medidas.has(peca)) medidas.set(peca, medir(pagina, peca));
    const palavras = medidas.get(peca);
    return palavras ? { ...u, palavras } : u;
  });
}
