import { ehFundoDaArte, type DocumentoDoBanner, type Peca } from "./documento";

/*
 * As camadas do vídeo animado (o servidor fotografa, o navegador anima): o
 * fundo (a cor da página, as camadas travadas do começo e a forma "Fundo") e
 * cada peça ou grupo por cima, na ordem da arte. O que está dentro de outra
 * peça (colocar dentro) vai junto da de fora. Até 30 camadas; as que passam
 * disso entram na última.
 */

export type TipoDaCamada = "fundo" | "texto" | "imagem" | "forma";
export type CamadaDoVideo = { ids: string[]; fundo: boolean; tipo: TipoDaCamada; caixa: { x: number; y: number; w: number; h: number } };

const LIMITE = 30;

/**
 * O tamanho do vídeo: o da arte, sem passar de 1920 no lado maior e 1080 no
 * menor, em números pares (o H.264 pede). `limite` encolhe o lado maior (a
 * prévia dos modelos animados, 360 a 1920).
 */
export function tamanhoDoVideo(largura: number, altura: number, limite?: number) {
  const maior = limite ? Math.max(360, Math.min(1920, limite)) : 1920;
  const f = Math.min(1, maior / Math.max(largura, altura), 1080 / Math.min(largura, altura));
  const par = (v: number) => Math.max(2, Math.round((v * f) / 2) * 2);
  return { largura: par(largura), altura: par(altura) };
}

function caixaDe(pecas: Peca[]) {
  const x = Math.min(...pecas.map((p) => p.x));
  const y = Math.min(...pecas.map((p) => p.y));
  return { x, y, w: Math.max(...pecas.map((p) => p.x + p.w)) - x, h: Math.max(...pecas.map((p) => p.y + p.h)) - y };
}

export function camadasDoVideo(pagina: DocumentoDoBanner): CamadaDoVideo[] {
  const visiveis = pagina.pecas.filter((p) => !p.oculta);
  /* O fundo: as do começo que são fundo (travadas cobrindo a arte, a forma "Fundo"). */
  let inicio = 0;
  while (inicio < visiveis.length) {
    const p = visiveis[inicio];
    const cobre = p.x <= 1 && p.y <= 1 && p.w >= pagina.largura - 1 && p.h >= pagina.altura - 1;
    if (!(ehFundoDaArte(p, pagina.largura, pagina.altura) || (p.bloqueada && cobre))) break;
    inicio += 1;
  }
  const fundo: CamadaDoVideo = { ids: visiveis.slice(0, inicio).map((p) => p.id), fundo: true, tipo: "fundo", caixa: { x: 0, y: 0, w: pagina.largura, h: pagina.altura } };
  const resto = visiveis.slice(inicio);
  const unidades: Peca[][] = [];
  const doGrupo = new Map<string, Peca[]>();
  for (const p of resto) {
    if (p.dentroDe && resto.some((q) => q.id === p.dentroDe)) continue;
    const filhos = resto.filter((q) => q.dentroDe === p.id);
    if (p.grupo) {
      const lista = doGrupo.get(p.grupo);
      if (lista) {
        lista.push(p, ...filhos);
        continue;
      }
      const nova = [p, ...filhos];
      doGrupo.set(p.grupo, nova);
      unidades.push(nova);
    } else unidades.push([p, ...filhos]);
  }
  /* Mais de 30: as últimas viram uma camada só. */
  const juntas = unidades.length > LIMITE ? [...unidades.slice(0, LIMITE - 1), unidades.slice(LIMITE - 1).flat()] : unidades;
  const camadas = juntas.map((pecas): CamadaDoVideo => {
    const tipo: TipoDaCamada = pecas.every((p) => p.tipo === "texto") ? "texto" : pecas.some((p) => p.tipo === "imagem") ? "imagem" : "forma";
    return { ids: pecas.map((p) => p.id), fundo: false, tipo, caixa: caixaDe(pecas) };
  });
  return [fundo, ...camadas];
}
