"use client";

import { zipar } from "@/lib/banner-editor/zip";
import { coresForaDoCmyk } from "@/lib/banner-editor/cmyk";
import { fatiarCarrossel, numeracaoDosPosts } from "@/lib/banner-editor/documento";
import { useEffect, useRef, useState } from "react";
import { Check, Clapperboard, Download, FileImage, FileText, Image as IconeDeImagem, Loader2 } from "lucide-react";
import { gravarVideo, videoComSuporte } from "@/lib/banner-editor/video";
import { ESTILOS_DA_PAGINA, animarPagina, audiosDoProjeto, comAudios, temAnimacao, temposDoProjeto, type EstiloDaPagina } from "@/lib/banner-editor/cena";
import { segundos } from "@/lib/banner-editor/animacao";
import { baixarArte } from "@/lib/banner-editor/artes";
import { documentoDasPaginas, type DocumentoDoBanner } from "@/lib/banner-editor/documento";

/*
  O "Baixar" do editor de artes (como o do Canva): o tipo de arquivo, a
  qualidade (pixels a mais para impressão) e, no PNG, o fundo transparente.
  O arquivo é gerado no servidor com o mesmo HTML do palco e vem direto para
  o computador. Ficam lembradas as escolhas da última vez.

  Com várias páginas: todas, só a aberta ou as escolhidas (1, 3 e 8; ou de 2
  a 5). O PDF sai num arquivo só (uma folha por página); PNG e JPG saem um
  arquivo por página, com o número da página.

  MP4: a página aberta vira um vídeo animado (as peças entram uma depois da
  outra), feito no navegador com as camadas fotografadas no servidor.
*/

type Formato = "png" | "jpg" | "pdf" | "mp4";
type Escolhas = { formato: Formato; escala: number; qualidade: number; transparente: boolean; grafica: boolean; zip: boolean; animacao: EstiloDaPagina; duracao: number };

const PADRAO: Escolhas = { formato: "png", escala: 2, qualidade: 90, transparente: false, grafica: true, zip: true, animacao: "suave", duracao: 6 };
const DURACOES = [5, 8, 12];

/** As fotos da página aberta que podem sair borradas (na impressão, abaixo de 150 ppp; na tela, menores que o espaço). */
export function fotosBorradas(doc: DocumentoDoBanner | null) {
  if (!doc || typeof document === "undefined") return 0;
  let quantas = 0;
  for (const p of doc.pecas) {
    if (p.tipo !== "imagem" || p.oculta || p.moldura) continue;
    const img = document.querySelector<HTMLImageElement>(`[data-palco] [data-peca="${CSS.escape(p.id)}"] img`);
    if (!img?.naturalWidth) continue;
    const s = p.ajuste === "cobrir" ? Math.max(p.w / img.naturalWidth, p.h / img.naturalHeight) * (p.enquadre?.zoom || 1) : Math.min(p.w / img.naturalWidth, p.h / img.naturalHeight);
    const pontos = 1 / s;
    if (doc.impressao ? pontos * doc.impressao.dpi < 150 : pontos < 0.9) quantas += 1;
  }
  return quantas;
}
const CHAVE = "ktalogu:artes:baixar";

/** "1, 3, 8", "2-5" ou "2 a 5" viram os números das páginas (de 1 a `total`, em ordem, sem repetir). */
export function paginasDoTexto(texto: string, total: number): number[] {
  const juntas = texto.toLowerCase().replace(/(\d)\s*(?:-|–|a|até)\s*(?=\d)/g, "$1-");
  const numeros = new Set<number>();
  for (const parte of juntas.split(/[^\d-]+/)) {
    const faixa = /^(\d+)-(\d+)$/.exec(parte);
    const [de, ate] = faixa ? [Number(faixa[1]), Number(faixa[2])] : /^\d+$/.test(parte) ? [Number(parte), Number(parte)] : [0, -1];
    for (let n = Math.max(1, Math.min(de, ate)); n <= Math.min(total, Math.max(de, ate)); n++) numeros.add(n);
  }
  return [...numeros].sort((a, b) => a - b);
}

/** O contrário: [1, 2, 3, 5] vira "1-3, 5". */
export function textoDasPaginas(numeros: number[]): string {
  const partes: string[] = [];
  for (let i = 0; i < numeros.length; i++) {
    let j = i;
    while (j + 1 < numeros.length && numeros[j + 1] === numeros[j] + 1) j++;
    partes.push(j - i >= 2 ? `${numeros[i]}-${numeros[j]}` : numeros.slice(i, j + 1).join(", "));
    i = j;
  }
  return partes.join(", ");
}

function lembradas(): Escolhas {
  try {
    const bruto = JSON.parse(window.localStorage.getItem(CHAVE) || "null") as Partial<Escolhas> | null;
    const juntas = { ...PADRAO, ...(bruto || {}) };
    return ESTILOS_DA_PAGINA.some((e) => e.chave === juntas.animacao) ? juntas : { ...juntas, animacao: PADRAO.animacao };
  } catch {
    return PADRAO;
  }
}

const FORMATOS: Array<{ valor: Formato; nome: string; detalhe: string; Icone: typeof FileImage }> = [
  { valor: "png", nome: "PNG", detalhe: "Nítido, aceita fundo transparente", Icone: IconeDeImagem },
  { valor: "jpg", nome: "JPG", detalhe: "Arquivo leve, para redes e WhatsApp", Icone: FileImage },
  { valor: "pdf", nome: "PDF", detalhe: "Para imprimir e mandar (leve, em alta resolução)", Icone: FileText },
  { valor: "mp4", nome: "Vídeo MP4", detalhe: "Animado, para reels, status e story", Icone: Clapperboard },
];

const QUALIDADES = [
  { valor: 1, nome: "Normal", detalhe: "1×" },
  { valor: 2, nome: "Alta", detalhe: "2×" },
  { valor: 3, nome: "Máxima", detalhe: "3×" },
];

/* A animação rápida do Baixar, sem mexer na arte: o estilo escolhido e a duração (alongada se as peças precisam de mais). */
function animadaNaHora(pagina: DocumentoDoBanner, estilo: EstiloDaPagina, duracao: number): DocumentoDoBanner {
  const animada = animarPagina(pagina, estilo);
  const ultima = Math.max(0, ...animada.pecas.map((p) => (p.animacao ? p.animacao.inicio + p.animacao.duracao : 0)));
  return { ...animada, animacao: { fundo: animada.animacao?.fundo ?? "aproximar", duracao: Math.max(duracao, Math.ceil(ultima + 1)) } };
}

export function BotaoDeBaixar({
  documento,
  paginas,
  paginaAtual = 0,
  nome,
  aoAvisar,
  aoAjustarCores,
  aoAnimar,
}: {
  documento: () => DocumentoDoBanner | null;
  /* Todas as páginas do projeto (a aberta já atualizada). */
  paginas?: () => DocumentoDoBanner[];
  paginaAtual?: number;
  nome: string;
  aoAvisar: (texto: string, tom?: "bom" | "ruim") => void;
  /* Troca as cores fora do CMYK pelas sugeridas (todas as páginas). */
  aoAjustarCores?: (mapa: Record<string, string>) => void;
  /* Abre o painel "Animar" do editor. */
  aoAnimar?: () => void;
}) {
  const [aberto, setAberto] = useState(false);
  /* Quais páginas: todas, só a aberta ou as escolhidas (no vídeo, só as duas primeiras). */
  const [modo, setModo] = useState<"todas" | "atual" | "escolher">("todas");
  const [escolhidas, setEscolhidas] = useState<number[]>([]);
  const [textoEscolhido, setTextoEscolhido] = useState("");
  /* Espelhado (transfer de sublimação): não fica lembrado, para o próximo post não sair virado. */
  const [espelhar, setEspelhar] = useState(false);
  const [escolhas, setEscolhas] = useState<Escolhas>(PADRAO);
  const [gerando, setGerando] = useState(false);
  /* A gravação do vídeo: a fase e quanto já foi. */
  const [andamento, setAndamento] = useState<{ fase: string; fracao: number } | null>(null);
  const caixa = useRef<HTMLDivElement | null>(null);

  useEffect(() => setEscolhas(lembradas()), []);
  useEffect(() => {
    if (!aberto) return;
    const fora = (e: MouseEvent) => {
      if (!caixa.current?.contains(e.target as Node)) setAberto(false);
    };
    document.addEventListener("mousedown", fora);
    return () => document.removeEventListener("mousedown", fora);
  }, [aberto]);

  const mudar = (campos: Partial<Escolhas>) => {
    const novas = { ...escolhas, ...campos };
    setEscolhas(novas);
    try {
      window.localStorage.setItem(CHAVE, JSON.stringify(novas));
    } catch {
      /* sem armazenamento, só não lembra */
    }
  };

  const doc = aberto ? documento() : null;
  const borradas = aberto ? fotosBorradas(doc) : 0;
  const pixels = doc ? `${doc.largura * (escolhas.formato === "pdf" ? 1 : escolhas.escala)} × ${doc.altura * (escolhas.formato === "pdf" ? 1 : escolhas.escala)} px` : "";

  /* O carrossel contínuo sai fatiado: cada post é uma página para baixar. */
  const quantas = aberto && paginas ? paginas().flatMap(fatiarCarrossel).length : 1;
  /* O vídeo não tem "escolher": vale todas as cenas ou só a aberta. */
  const todas = modo === "todas" || (modo === "escolher" && escolhas.formato === "mp4");
  const pelaEscolha = modo === "escolher" && escolhas.formato !== "mp4" && quantas > 1;
  const escolherPaginas = (numeros: number[]) => {
    setEscolhidas(numeros);
    setTextoEscolhido(textoDasPaginas(numeros));
  };
  /* No PDF (impressão), as cores que a tinta da gráfica não alcança. */
  const foraDoCmyk = aberto && escolhas.formato === "pdf" ? coresForaDoCmyk(paginas ? paginas() : doc ? [doc] : []) : [];

  /* As cenas do vídeo (todas em sequência ou só a aberta) e se já têm animação ou vídeo montados. */
  const cenasDoVideo = (): DocumentoDoBanner[] => {
    const bruto = paginas ? paginas() : doc ? [doc] : [];
    const numeros = numeracaoDosPosts(bruto);
    const comNumero = bruto.map((p, i) => ({ ...p, numeracao: numeros[i] }));
    if (todas) return comNumero;
    /* Só uma cena: a trilha de áudio vai junto, recortada no tempo dela. */
    const desde = temposDoProjeto(comNumero).inicios[paginaAtual] ?? 0;
    const ate = desde + (temposDoProjeto(comNumero.slice(paginaAtual, paginaAtual + 1)).total || 0);
    const audios = audiosDoProjeto(comNumero).flatMap((a) => {
      const comeca = Math.max(a.inicio, desde);
      const acaba = Math.min(a.inicio + a.dura, ate);
      return acaba - comeca > 0.05 ? [{ ...a, inicio: comeca - desde, corte: a.corte + (comeca - a.inicio), dura: acaba - comeca }] : [];
    });
    return comAudios(comNumero.slice(paginaAtual, paginaAtual + 1), audios);
  };
  const montada = (lista: DocumentoDoBanner[]) => lista.some((p) => temAnimacao(p) || p.pecas.some((x) => x.tipo === "imagem" && x.video));
  const noVideo = aberto && escolhas.formato === "mp4" ? cenasDoVideo() : [];
  const jaAnimada = montada(noVideo);
  const quantasCenas = aberto && paginas ? paginas().length : 1;

  /* O vídeo, gravado aqui no navegador. */
  const baixarVideo = async () => {
    const atual = documento();
    if (!atual || gerando) return;
    setGerando(true);
    try {
      const lista = cenasDoVideo();
      /* Com animação (ou vídeo) montada, sai como está na linha do tempo; sem nada, entra a animação rápida escolhida aqui (só no vídeo). */
      const prontas = montada(lista) ? lista : lista.map((p) => animadaNaHora(p, escolhas.animacao, escolhas.duracao));
      const arquivo = await gravarVideo(prontas, { aoAndar: (fase, fracao) => setAndamento({ fase, fracao }) });
      const endereco = URL.createObjectURL(arquivo);
      const link = document.createElement("a");
      link.href = endereco;
      link.download = `${nome.replace(/[^\p{L}\p{N} _-]/gu, "").trim() || "arte"}.mp4`;
      document.body.appendChild(link);
      link.click();
      link.remove();
      window.setTimeout(() => URL.revokeObjectURL(endereco), 60_000);
      setAberto(false);
      aoAvisar(`Vídeo de ${segundos(temposDoProjeto(prontas).total)} baixado. Confira na pasta de downloads.`, "bom");
    } catch (erro) {
      aoAvisar(erro instanceof Error && erro.message !== "Failed to fetch" ? erro.message : "Sem conexão com o painel. Confira a internet e tente de novo.", "ruim");
    } finally {
      setGerando(false);
      setAndamento(null);
    }
  };

  const baixar = async () => {
    if (escolhas.formato === "mp4") return baixarVideo();
    const atual = documento();
    if (!atual || gerando) return;
    const { animacao: _animacao, duracao: _duracao, ...paraImagem } = { ...escolhas, formato: escolhas.formato };
    void _animacao;
    void _duracao;
    /* Cada página leva o número dela entre os posts (o contador "03/06" sai certo mesmo baixando um por vez). */
    const bruto = paginas ? paginas() : [atual];
    const numeros = numeracaoDosPosts(bruto);
    const projeto = bruto.map((p, i) => ({ ...p, numeracao: numeros[i] }));
    const lista = projeto.flatMap(fatiarCarrossel);
    /* O número de cada página no projeto (o arquivo leva o número de verdade: "Arte 03", "Arte 08"). */
    const numerosDaLista = lista.map((_, i) => i + 1);
    const daAberta = fatiarCarrossel(projeto[paginaAtual] ?? atual);
    const inicioDaAberta = projeto.slice(0, paginaAtual).flatMap(fatiarCarrossel).length;
    const [paginasQueSaem, numerosQueSaem] =
      lista.length > 1 && todas
        ? [lista, numerosDaLista]
        : pelaEscolha
          ? [escolhidas.map((n) => lista[n - 1]).filter(Boolean), escolhidas.filter((n) => lista[n - 1])]
          : [daAberta, daAberta.map((_, i) => inicioDaAberta + i + 1)];
    if (!paginasQueSaem.length) {
      aoAvisar("Escolha pelo menos uma página para baixar.", "ruim");
      return;
    }
    setGerando(true);
    try {
      let escala = escolhas.escala;
      if (escolhas.formato === "pdf" || paginasQueSaem.length === 1) {
        ({ escala } = await baixarArte({ documento: documentoDasPaginas(paginasQueSaem), largura: paginasQueSaem[0].largura, altura: paginasQueSaem[0].altura, nome: paginasQueSaem.length === 1 && lista.length > 1 ? `${nome} ${String(numerosQueSaem[0]).padStart(2, "0")}` : nome, ...paraImagem, grafica: escolhas.formato === "pdf" && escolhas.grafica, espelhar }));
      } else {
        /* Uma imagem por página, numeradas; uma de cada vez (o servidor faz uma arte por vez). No .zip, todas num arquivo só. */
        const juntas: Array<{ nome: string; dados: Uint8Array }> = [];
        for (const [i, pagina] of paginasQueSaem.entries()) {
          const feita = await baixarArte({ documento: pagina, largura: pagina.largura, altura: pagina.altura, nome: `${nome} ${String(numerosQueSaem[i]).padStart(2, "0")}`, ...paraImagem, espelhar }, escolhas.zip);
          escala = feita.escala;
          if (escolhas.zip) juntas.push({ nome: feita.nome, dados: new Uint8Array(await feita.arquivo.arrayBuffer()) });
        }
        if (escolhas.zip) {
          const endereco = URL.createObjectURL(zipar(juntas));
          const link = document.createElement("a");
          link.href = endereco;
          link.download = `${nome.replace(/[^\p{L}\p{N} _-]/gu, "").trim() || "arte"}.zip`;
          document.body.appendChild(link);
          link.click();
          link.remove();
          window.setTimeout(() => URL.revokeObjectURL(endereco), 30_000);
        }
      }
      setAberto(false);
      const pronto = paginasQueSaem.length > 1 ? (escolhas.formato === "pdf" ? `PDF com ${paginasQueSaem.length} páginas baixado.` : escolhas.zip ? `.zip com ${paginasQueSaem.length} imagens baixado.` : `${paginasQueSaem.length} imagens baixadas, uma por página.`) : "Arte baixada.";
      if (espelhar) {
        aoAvisar(`${pronto} Saiu espelhada, pronta para o papel de sublimação.`, "bom");
        return;
      }
      aoAvisar(escala < escolhas.escala && escolhas.formato !== "pdf" ? `${pronto} Saiu em ${escala}× (a arte é grande; ${escolhas.escala}× passaria do limite).` : `${pronto} Confira na pasta de downloads.`, "bom");
    } catch (erro) {
      aoAvisar(erro instanceof Error && erro.message !== "Failed to fetch" ? erro.message : "Sem conexão com o painel. Confira a internet e tente de novo.", "ruim");
    } finally {
      setGerando(false);
    }
  };

  const opcao = (ativa: boolean) => `flex w-full items-center gap-3 rounded-[10px] px-3 py-2.5 text-left transition ${ativa ? "bg-[#F1ECFF] ring-2 ring-[#8B5CF6]" : "hover:bg-[#F6F4FB]"}`;

  return (
    <div ref={caixa} className="relative">
      <button
        type="button"
        onClick={() => setAberto((v) => !v)}
        className="flex h-10 items-center gap-2 rounded-[10px] bg-white/15 px-4 text-[13.5px] font-bold text-white ring-1 ring-white/30 transition hover:bg-white/25"
        data-botao-do-topo
      >
        <Download size={16} /> Baixar
      </button>
      {aberto ? (
        <div className="absolute right-0 top-[calc(100%+10px)] z-[60] max-h-[calc(100vh-96px)] w-[340px] overflow-y-auto rounded-[16px] bg-white p-4 text-[#1F1B2E] shadow-[0_18px_50px_rgba(20,11,43,0.28)] ring-1 ring-black/5" data-janela-de-baixar data-janela-do-topo>
          {(escolhas.formato === "mp4" ? quantasCenas : quantas) > 1 ? (
            <>
              <p className="mb-2 text-[12px] font-bold uppercase tracking-[0.12em] text-[#8A849E]">Páginas</p>
              <div className="mb-4 flex rounded-[10px] bg-[#F1EFF6] p-1">
                {[
                  { valor: "todas" as const, rotulo: escolhas.formato === "mp4" ? `As ${quantasCenas} cenas` : `Todas (${quantas})`, ativo: todas },
                  { valor: "atual" as const, rotulo: escolhas.formato === "mp4" ? `Só a cena ${paginaAtual + 1}` : `Só a ${paginaAtual + 1}`, ativo: modo === "atual" },
                  ...(escolhas.formato === "mp4" ? [] : [{ valor: "escolher" as const, rotulo: "Escolher", ativo: pelaEscolha }]),
                ].map((o) => (
                  <button
                    key={o.valor}
                    type="button"
                    onClick={() => {
                      setModo(o.valor);
                      if (o.valor === "escolher" && !escolhidas.length) escolherPaginas([paginaAtual + 1]);
                    }}
                    className={`flex-1 rounded-[8px] py-2 text-[12.5px] font-bold transition ${o.ativo ? "bg-white text-[#5B21B6] shadow-[0_2px_8px_rgba(45,30,105,0.12)]" : "text-[#6B6584]"}`}
                    data-paginas-para-baixar={o.valor}
                  >
                    {o.rotulo}
                  </button>
                ))}
              </div>
              {pelaEscolha ? (
                <div className="-mt-2 mb-4" data-escolher-paginas>
                  <div className="grid grid-cols-6 gap-1.5">
                    {Array.from({ length: quantas }, (_, i) => i + 1).map((n) => {
                      const ligada = escolhidas.includes(n);
                      return (
                        <button
                          key={n}
                          type="button"
                          aria-pressed={ligada}
                          onClick={() => escolherPaginas(ligada ? escolhidas.filter((x) => x !== n) : [...escolhidas, n].sort((a, b) => a - b))}
                          className={`h-9 rounded-[9px] text-[12.5px] font-bold tabular-nums transition ${ligada ? "bg-[#7C3AED] text-white" : "bg-[#F1EFF6] text-[#4B4760] hover:bg-[#E9E4F8]"}`}
                          data-pagina-para-baixar={n}
                        >
                          {n}
                        </button>
                      );
                    })}
                  </div>
                  <input
                    value={textoEscolhido}
                    onChange={(e) => {
                      setTextoEscolhido(e.target.value);
                      setEscolhidas(paginasDoTexto(e.target.value, quantas));
                    }}
                    placeholder="Ex.: 1, 3, 8 ou 2-5"
                    className="mt-2 h-9 w-full rounded-[9px] bg-[#F6F4FB] px-3 text-[12.5px] outline-none ring-1 ring-black/5 focus:ring-2 focus:ring-[#8B5CF6]"
                    aria-label="Páginas para baixar"
                    data-texto-das-paginas
                  />
                  <div className="mt-1.5 flex items-center justify-between text-[11px] text-[#8A849E]">
                    <span>{escolhidas.length ? `${escolhidas.length} de ${quantas} páginas` : "Nenhuma página escolhida"}</span>
                    <span className="flex gap-2">
                      <button type="button" onClick={() => escolherPaginas(Array.from({ length: quantas }, (_, i) => i + 1))} className="font-bold text-[#6D28D9] hover:underline">
                        Todas
                      </button>
                      <button type="button" onClick={() => escolherPaginas([])} className="font-bold text-[#6D28D9] hover:underline">
                        Nenhuma
                      </button>
                    </span>
                  </div>
                </div>
              ) : null}
              {(todas || (pelaEscolha && escolhidas.length > 1)) && escolhas.formato !== "pdf" ? (
                <label className="-mt-2 mb-4 flex items-center gap-2 text-[12px] font-medium text-[#4B4760]">
                  <input type="checkbox" checked={escolhas.zip} onChange={(e) => mudar({ zip: e.target.checked })} className="h-4 w-4 accent-[#7C3AED]" data-zip />
                  Tudo num arquivo .zip (o carrossel inteiro de uma vez)
                </label>
              ) : null}
            </>
          ) : null}
          {foraDoCmyk.length ? (
            <div className="mb-4 rounded-[12px] bg-[#FFF7E6] p-3 text-[#7C4A03]" data-aviso-cmyk>
              <p className="text-[12px] font-bold">{foraDoCmyk.length === 1 ? "1 cor pode sair diferente" : `${foraDoCmyk.length} cores podem sair diferentes`} na gráfica (CMYK)</p>
              <p className="mt-0.5 text-[11.5px] leading-snug">A tinta não alcança essas cores da tela: impressas, saem mais apagadas. Ao lado, a mais próxima que imprime.</p>
              <div className="mt-2 flex flex-wrap gap-1.5">
                {foraDoCmyk.slice(0, 8).map((c) => (
                  <span key={c.cor} className="flex items-center gap-1 rounded-full bg-white px-1.5 py-1 text-[10.5px] font-bold tabular-nums ring-1 ring-black/5" title={`${c.cor} → ${c.sugestao}`}>
                    <span className="h-4 w-4 rounded-full ring-1 ring-black/10" style={{ background: c.cor }} />→<span className="h-4 w-4 rounded-full ring-1 ring-black/10" style={{ background: c.sugestao }} />
                  </span>
                ))}
              </div>
              {aoAjustarCores ? (
                <button type="button" onClick={() => aoAjustarCores(Object.fromEntries(foraDoCmyk.map((c) => [c.cor, c.sugestao])))} className="mt-2.5 h-8 w-full rounded-[8px] bg-[#7C4A03] text-[12px] font-bold text-white hover:bg-[#5C3602]" data-trocar-cores-cmyk>
                  Trocar pelas cores que imprimem
                </button>
              ) : null}
            </div>
          ) : null}
          <p className="mb-2 text-[12px] font-bold uppercase tracking-[0.12em] text-[#8A849E]">Tipo de arquivo</p>
          <div className="space-y-1">
            {FORMATOS.map(({ valor, nome: rotulo, detalhe, Icone }) => (
              <button key={valor} type="button" onClick={() => mudar({ formato: valor })} className={opcao(escolhas.formato === valor)}>
                <Icone size={18} className={escolhas.formato === valor ? "text-[#6D28D9]" : "text-[#8A849E]"} />
                <span className="min-w-0 flex-1">
                  <span className="block text-[13px] font-bold">{rotulo}</span>
                  <span className="block text-[11.5px] text-[#8A849E]">{detalhe}</span>
                </span>
                {escolhas.formato === valor ? <Check size={16} className="text-[#6D28D9]" /> : null}
              </button>
            ))}
          </div>

          {escolhas.formato === "mp4" ? (
            <div data-opcoes-do-video>
              {jaAnimada ? (
                <div className="mt-4 rounded-[12px] bg-[#F4F0FF] px-3.5 py-3" data-video-com-a-animacao>
                  <p className="text-[12.5px] font-bold text-[#4C1D95]">Como está na linha do tempo</p>
                  <p className="mt-0.5 text-[11.5px] leading-snug text-[#6B6584]">
                    {segundos(temposDoProjeto(noVideo).total)}
                    {noVideo.length > 1 ? `, ${noVideo.length} cenas com as transições` : ""}, cada peça com o efeito e o tempo que você montou.
                  </p>
                  {aoAnimar ? (
                    <button
                      type="button"
                      onClick={() => {
                        setAberto(false);
                        aoAnimar();
                      }}
                      className="mt-2 text-[12px] font-bold text-[#6D28D9] hover:underline"
                    >
                      Abrir a animação
                    </button>
                  ) : null}
                </div>
              ) : (
                <>
                  <p className="mb-2 mt-4 text-[12px] font-bold uppercase tracking-[0.12em] text-[#8A849E]">Animação rápida</p>
                  <div className="grid grid-cols-3 gap-1.5">
                    {ESTILOS_DA_PAGINA.map((a) => (
                      <button key={a.chave} type="button" onClick={() => mudar({ animacao: a.chave })} className={`rounded-[10px] py-2 text-[12.5px] font-bold transition ${escolhas.animacao === a.chave ? "bg-[#F1ECFF] text-[#5B21B6] ring-2 ring-[#8B5CF6]" : "bg-[#F6F4FB] text-[#4B4760] hover:bg-[#EEEAF8]"}`} data-animacao={a.chave}>
                        {a.nome}
                      </button>
                    ))}
                  </div>
                  <p className="mb-2 mt-4 text-[12px] font-bold uppercase tracking-[0.12em] text-[#8A849E]">Duração</p>
                  <div className="flex rounded-[10px] bg-[#F1EFF6] p-1">
                    {DURACOES.map((d) => (
                      <button key={d} type="button" onClick={() => mudar({ duracao: d })} className={`flex-1 rounded-[8px] py-1.5 text-[12.5px] font-bold transition ${escolhas.duracao === d ? "bg-white text-[#5B21B6] shadow-[0_2px_8px_rgba(45,30,105,0.12)]" : "text-[#6B6584]"}`} data-duracao={d}>
                        {d} s
                      </button>
                    ))}
                  </div>
                  {aoAnimar ? (
                    <button
                      type="button"
                      onClick={() => {
                        setAberto(false);
                        aoAnimar();
                      }}
                      className="mt-2 text-[12px] font-bold text-[#6D28D9] hover:underline"
                    >
                      Montar a animação peça por peça
                    </button>
                  ) : null}
                </>
              )}
              <p className="mt-1.5 text-[11.5px] leading-snug text-[#8A849E]">Sai em MP4{audiosDoProjeto(noVideo).length ? ", com a trilha de áudio" : ""}{noVideo.some((p) => p.pecas.some((x) => x.tipo === "imagem" && x.video && !x.video.mudo)) ? `${audiosDoProjeto(noVideo).length ? " e" : ","} com o som dos vídeos` : ""}, pronto para o Instagram e o WhatsApp.</p>
              {!videoComSuporte() ? <p className="mt-2 rounded-[10px] bg-[#FFF7E6] px-3 py-2 text-[11.5px] font-medium text-[#8A5300]">Este navegador não grava vídeo. Use o Chrome ou o Edge atualizado.</p> : null}
            </div>
          ) : escolhas.formato !== "pdf" ? (
            <>
              <p className="mb-2 mt-4 text-[12px] font-bold uppercase tracking-[0.12em] text-[#8A849E]">Qualidade</p>
              <div className="flex rounded-[10px] bg-[#F1EFF6] p-1">
                {QUALIDADES.map((q) => (
                  <button
                    key={q.valor}
                    type="button"
                    onClick={() => mudar({ escala: q.valor })}
                    className={`flex flex-1 flex-col items-center rounded-[8px] py-1.5 text-[12.5px] font-bold transition ${escolhas.escala === q.valor ? "bg-white text-[#5B21B6] shadow-[0_2px_8px_rgba(45,30,105,0.12)]" : "text-[#6B6584]"}`}
                  >
                    {q.nome}
                    <span className="text-[10.5px] font-semibold opacity-70">{q.detalhe}</span>
                  </button>
                ))}
              </div>
              <p className="mt-1.5 text-[11.5px] text-[#8A849E]">Sai com {pixels}.</p>
            </>
          ) : (
            <>
              <p className="mt-3 rounded-[10px] bg-[#F6F4FB] px-3 py-2 text-[11.5px] leading-snug text-[#6B6584]">
                {quantas > 1 && todas ? `Um arquivo com ${quantas} folhas` : pelaEscolha && escolhidas.length > 1 ? `Um arquivo com ${escolhidas.length} folhas` : "Uma folha"} no tamanho exato da arte, com as imagens em alta. Bom para gráfica e impressora.
              </p>
              <label className="mt-3 flex cursor-pointer items-center justify-between gap-3 rounded-[10px] bg-[#F6F4FB] px-3 py-2.5">
                <span>
                  <span className="block text-[12.5px] font-bold">Para gráfica</span>
                  <span className="block text-[11.5px] text-[#8A849E]">Sangria de 3 mm e marcas de corte{doc?.impressao ? ` · ${doc.impressao.dpi} ppp` : ""}</span>
                </span>
                <input type="checkbox" checked={escolhas.grafica} onChange={(e) => mudar({ grafica: e.target.checked })} className="h-4 w-4 accent-[#7C3AED]" aria-label="PDF para gráfica" />
              </label>
            </>
          )}

          {escolhas.formato === "jpg" ? (
            <div className="mt-4">
              <div className="mb-1 flex items-center justify-between text-[12px] font-semibold">
                Compressão do JPG
                <span className="tabular-nums text-[#8A849E]">{escolhas.qualidade}%</span>
              </div>
              <input type="range" min={50} max={100} value={escolhas.qualidade} onChange={(e) => mudar({ qualidade: Number(e.target.value) })} className="w-full accent-[#7C3AED]" />
            </div>
          ) : null}

          {escolhas.formato === "png" ? (
            <label className="mt-4 flex cursor-pointer items-center justify-between gap-3 rounded-[10px] bg-[#F6F4FB] px-3 py-2.5">
              <span>
                <span className="block text-[12.5px] font-bold">Fundo transparente</span>
                <span className="block text-[11.5px] text-[#8A849E]">Tira a camada &quot;Fundo&quot; da arte</span>
              </span>
              <input type="checkbox" checked={escolhas.transparente} onChange={(e) => mudar({ transparente: e.target.checked })} className="h-4 w-4 accent-[#7C3AED]" />
            </label>
          ) : null}

          {doc?.impressao ? (
            <label className="mt-3 flex cursor-pointer items-center justify-between gap-3 rounded-[10px] bg-[#F6F4FB] px-3 py-2.5">
              <span>
                <span className="block text-[12.5px] font-bold">Espelhado (sublimação)</span>
                <span className="block text-[11.5px] text-[#8A849E]">Sai virado no papel e fica certo na peça</span>
              </span>
              <input type="checkbox" checked={espelhar} onChange={(e) => setEspelhar(e.target.checked)} className="h-4 w-4 accent-[#7C3AED]" aria-label="Baixar espelhado" data-espelhar />
            </label>
          ) : null}

          {borradas ? (
            <p className="mt-3 rounded-[10px] bg-[#FFF7E6] px-3 py-2 text-[11.5px] font-medium leading-snug text-[#8A5300]">
              {borradas === 1
                ? `Uma foto desta página ${doc?.impressao ? "tem pouca resolução para esse tamanho impresso" : "é menor que o espaço que ocupa"} e pode sair borrada.`
                : `${borradas} fotos desta página ${doc?.impressao ? "têm pouca resolução para esse tamanho impresso" : "são menores que o espaço que ocupam"} e podem sair borradas.`}{" "}
              Use uma foto maior.
            </p>
          ) : null}
          <button
            type="button"
            onClick={baixar}
            disabled={gerando}
            className="mt-4 flex h-11 w-full items-center justify-center gap-2 rounded-[10px] bg-[#7C3AED] text-[13.5px] font-bold text-white transition hover:bg-[#6D28D9] disabled:opacity-70"
          >
            {gerando ? <Loader2 size={16} className="animate-spin" /> : <Download size={16} />}
            {gerando ? (andamento ? `${andamento.fase}${andamento.fracao > 0 && andamento.fracao < 1 ? ` ${Math.round(andamento.fracao * 100)}%` : ""}` : "Preparando o arquivo…") : escolhas.formato === "mp4" ? "Baixar vídeo MP4" : `Baixar ${escolhas.formato.toUpperCase()}`}
          </button>
        </div>
      ) : null}
    </div>
  );
}
