"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import {
  AlertTriangle,
  AlignCenter,
  AlignCenterHorizontal,
  AlignCenterVertical,
  AlignEndHorizontal,
  AlignEndVertical,
  AlignHorizontalSpaceAround,
  AlignLeft,
  AlignRight,
  AlignStartHorizontal,
  AlignStartVertical,
  AlignVerticalSpaceAround,
  Blend,
  ChevronDown,
  ChevronUp,
  Circle,
  CircleDashed,
  Slash,
  Waves,
  WandSparkles,
  SquareDashedBottom,
  Brush,
  Pin,
  Copy,
  Crop,
  Eraser,
  Loader2,
  Group,
  List,
  ListOrdered,
  ListChecks,
  Lock,
  QrCode,
  Scan,
  Sheet,
  Spline,
  ChartColumn,
  LockOpen,
  Minus,
  Move,
  Paintbrush,
  Plus,
  Shapes,
  SlidersHorizontal,
  Sparkles,
  Trash2,
  Ungroup,
  Replace,
  Omega,
  Palette,
  Grip,
} from "lucide-react";
import { cssDaPintura, fonteDaChave, type Peca } from "@/lib/banner-editor/documento";
import type { TipoDoNo } from "@/lib/banner-editor/curvas";
import type { OperacaoDeForma } from "@/lib/banner-editor/soldar-e-aparar";
import type { AjusteDaPeca } from "./paineis";
import { formatarTrecho, tamanhoDoTrecho, useTrechoEscolhido, type AcaoNoTrecho } from "./texto-rico";

/*
  A barra flutuante em cima da arte (como a do Canva): uma pílula branca com
  o que importa da peça escolhida. O que tem mais de um ajuste (fonte, cor,
  efeitos, posição, ajustes da foto, textura) abre o painel da esquerda;
  negrito, itálico, alinhamento, tamanho e travar mudam aqui. A transparência
  abre o painel dela (por igual ou em degradê, com as alças na peça).

  Escrevendo um texto com um trecho selecionado, negrito, itálico,
  sublinhado, riscado, tamanho, cor e fonte valem SÓ para o trecho. Sem
  trecho, valem para o texto inteiro. A barra não rouba o foco do texto
  (o clique nela não tira a seleção).

  Com várias peças escolhidas, a barra vira a do grupo: alinhar entre elas,
  distribuir o espaço, duplicar, travar e apagar todas.
*/

const BOTAO =
  "flex h-9 min-w-9 shrink-0 items-center justify-center gap-1.5 rounded-[8px] px-2 text-[13px] font-medium text-[#2B2640] transition hover:bg-[#F1EFF6] active:bg-[#E9E4F8]";
const ATIVO = "!bg-[#EDE7FF] !text-[#5B21B6]";

function Divisor() {
  return <span className="mx-1 h-6 w-px shrink-0 bg-[#E6E3EE]" />;
}

/*
 * A barra que não cabe rola de lado: a rodinha do mouse anda para os lados
 * e a borda esmaece onde tem mais botão (sem barra de rolagem à vista).
 */
function useBarraQueRola() {
  const el = useRef<HTMLDivElement | null>(null);
  const [mais, setMais] = useState({ esquerda: false, direita: false });
  const medir = useCallback(() => {
    const b = el.current;
    if (!b) return;
    const esquerda = b.scrollLeft > 2;
    const direita = b.scrollLeft + b.clientWidth < b.scrollWidth - 2;
    setMais((m) => (m.esquerda === esquerda && m.direita === direita ? m : { esquerda, direita }));
  }, []);
  const ref = useCallback(
    (no: HTMLDivElement | null) => {
      el.current = no;
      if (no) medir();
    },
    [medir],
  );
  useEffect(() => {
    const b = el.current;
    if (!b) return;
    medir();
    const roda = (e: WheelEvent) => {
      if (b.scrollWidth <= b.clientWidth + 2 || Math.abs(e.deltaX) > Math.abs(e.deltaY)) return;
      e.preventDefault();
      b.scrollLeft += e.deltaY;
    };
    const observador = new ResizeObserver(medir);
    observador.observe(b);
    b.addEventListener("wheel", roda, { passive: false });
    b.addEventListener("scroll", medir, { passive: true });
    return () => {
      observador.disconnect();
      b.removeEventListener("wheel", roda);
      b.removeEventListener("scroll", medir);
    };
  });
  const borda = (lado: boolean) => (lado ? "transparent 0, #000 28px" : "#000 0");
  const mascara = mais.esquerda || mais.direita ? `linear-gradient(to right, ${borda(mais.esquerda)}, #000 calc(100% - ${mais.direita ? 28 : 0}px), ${mais.direita ? "transparent 100%" : "#000 100%"})` : undefined;
  return { ref, estilo: mascara ? { WebkitMaskImage: mascara, maskImage: mascara } : undefined, medir };
}

/* O ícone da perspectiva: um quadro deitado com a grade (como o do Corel). */
function IconeDaPerspectiva({ size = 16 }: { size?: number }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M3 6 21 3v18L3 18Z" />
      <path d="M12 4.5v15" strokeWidth={1.4} />
      <path d="M3 12h18" strokeWidth={1.4} />
    </svg>
  );
}

/* O clique na barra não tira o foco do texto em escrita (o trecho continua escolhido). */
const naoRoubarFoco = (e: React.MouseEvent) => {
  const alvo = e.target as HTMLElement;
  if (alvo.closest("button") && !alvo.closest("input")) e.preventDefault();
};

/** A amostra de cor (com o degradê, se houver) que abre o painel de cor. */
function BotaoDeCor({ fundo, titulo, aoClicar, ativo, letra }: { fundo: string; titulo: string; aoClicar: () => void; ativo: boolean; letra?: boolean }) {
  return (
    <button type="button" title={titulo} onClick={aoClicar} className={`${BOTAO} ${ativo ? ATIVO : ""}`}>
      {letra ? (
        <span className="flex flex-col items-center leading-none">
          <span className="text-[15px] font-bold">A</span>
          <span className="mt-0.5 h-[4px] w-5 rounded-full ring-1 ring-black/10" style={{ background: fundo }} />
        </span>
      ) : (
        <span className="h-6 w-6 rounded-full ring-1 ring-black/15" style={{ background: fundo }} />
      )}
    </button>
  );
}

/**
 * Aviso de foto com pouca resolução para o tamanho dela: na impressão, menos
 * de 150 ppp; na tela, menor que o espaço que ocupa. Mede a foto de verdade
 * (o tamanho original dela, quando termina de carregar).
 */
function AvisoDeResolucao({ peca, dpi }: { peca: Extract<Peca, { tipo: "imagem" }>; dpi: number | null }) {
  const [natural, setNatural] = useState<{ w: number; h: number } | null>(null);
  useEffect(() => {
    const img = document.querySelector<HTMLImageElement>(`[data-palco] [data-peca="${CSS.escape(peca.id)}"] img`);
    if (!img) return;
    const ler = () => setNatural(img.naturalWidth ? { w: img.naturalWidth, h: img.naturalHeight } : null);
    if (img.complete) ler();
    img.addEventListener("load", ler);
    return () => img.removeEventListener("load", ler);
  }, [peca.id, peca.src]);
  if (!natural || peca.moldura) return null;
  const s = peca.ajuste === "cobrir" ? Math.max(peca.w / natural.w, peca.h / natural.h) * (peca.enquadre?.zoom || 1) : Math.min(peca.w / natural.w, peca.h / natural.h);
  const pontos = 1 / s;
  const ppp = dpi ? Math.round(pontos * dpi) : null;
  const baixa = ppp !== null ? ppp < 150 : pontos < 0.9;
  if (!baixa) return null;
  return (
    <span className="mx-1 flex shrink-0 items-center gap-1 rounded-full bg-[#FFF7E6] px-2.5 py-1 text-[11px] font-bold text-[#8A5300]" title={ppp !== null ? "Para imprimir bem, a foto precisa de 150 ppp ou mais no tamanho em que está. Diminua a foto ou use uma maior." : "A foto é menor que o espaço que ocupa: pode sair borrada. Use uma foto maior."}>
      <AlertTriangle size={13} /> {ppp !== null ? `Resolução baixa (${ppp} ppp)` : "Foto pequena"}
    </span>
  );
}

export type Alinhamento = "esquerda" | "centro-h" | "direita" | "topo" | "meio-v" | "base";

/* O desenho de cada operação (dois quadrados, o resultado cheio), no jeito do Corel. */
function IconeDaOperacao({ operacao }: { operacao: OperacaoDeForma }) {
  const a = "M3 3h11v11H3z";
  const b = "M10 10h11v11H10z";
  const cheio = "currentColor";
  return (
    <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round" aria-hidden="true">
      {operacao === "soldar" ? <path d="M3 3h11v7h7v11H10v-7H3z" fill={cheio} fillOpacity="0.35" /> : null}
      {operacao === "aparar" ? (
        <>
          <path d="M3 3h11v7h-4v4H3z" fill={cheio} fillOpacity="0.35" />
          <path d={b} strokeDasharray="2 2" />
        </>
      ) : null}
      {operacao === "intersecao" ? (
        <>
          <path d={a} strokeDasharray="2 2" />
          <path d={b} strokeDasharray="2 2" />
          <path d="M10 10h4v4h-4z" fill={cheio} />
        </>
      ) : null}
      {operacao === "frente-menos-tras" ? (
        <>
          <path d={a} strokeDasharray="2 2" />
          <path d="M14 10h7v11H10v-7h4z" fill={cheio} fillOpacity="0.35" />
        </>
      ) : null}
    </svg>
  );
}

const OPERACOES: Array<[OperacaoDeForma, string, string]> = [
  ["aparar", "Aparar", "Aparar: as de cima recortam a de baixo e saem (o cupom com as mordidas, o furo, o recorte)"],
  ["soldar", "Soldar", "Soldar: junta todas num desenho só, com o jeito da de baixo"],
  ["intersecao", "Interseção", "Interseção: fica só o pedaço em que todas se encostam"],
  ["frente-menos-tras", "Frente menos trás", "Frente menos trás: a de cima, sem o que as de baixo cobrem"],
];

export function BarraDoGrupo({
  quantas,
  travadas,
  agrupadas,
  aoColocarDentro,
  aoOperar,
  operando = false,
  aoAgrupar,
  aoAlinhar,
  aoDistribuir,
  aoDuplicar,
  aoTravar,
  aoApagar,
  aoAnimar,
  animando = false,
  aoTrocarFoto,
  aoPerspectiva,
  perspectivaLigada = false,
  aoTirarPerspectiva,
}: {
  quantas: number;
  travadas: boolean;
  /* As escolhidas já são um grupo (o botão desagrupa). */
  agrupadas: boolean;
  /* Duas peças em que uma serve de recipiente: "Colocar dentro" (máscara de recorte). */
  aoColocarDentro?: () => void;
  /* Só formas e desenhos fechados escolhidos: Soldar, Aparar, Interseção (como no Corel). */
  aoOperar?: (operacao: OperacaoDeForma) => void;
  operando?: boolean;
  aoAgrupar: () => void;
  aoAlinhar: (a: Alinhamento) => void;
  aoDistribuir: (eixo: "h" | "v") => void;
  aoDuplicar: () => void;
  aoTravar: () => void;
  aoApagar: () => void;
  /* O painel "Animar" (entrada, movimento e saída das escolhidas). */
  aoAnimar?: () => void;
  animando?: boolean;
  /* O grupo tem uma foto só (o celular, a janela do site, o cartão): trocar a foto dele. */
  aoTrocarFoto?: () => void;
  /* Perspectiva do grupo inteiro (os 4 cantos na arte entortam todas juntas); tirar volta todas ao reto. */
  aoPerspectiva?: () => void;
  perspectivaLigada?: boolean;
  aoTirarPerspectiva?: () => void;
}) {
  const rola = useBarraQueRola();
  const alinhar: Array<[Alinhamento, typeof AlignLeft, string]> = [
    ["esquerda", AlignStartVertical, "Alinhar à esquerda"],
    ["centro-h", AlignCenterVertical, "Centralizar na horizontal"],
    ["direita", AlignEndVertical, "Alinhar à direita"],
    ["topo", AlignStartHorizontal, "Alinhar no topo"],
    ["meio-v", AlignCenterHorizontal, "Centralizar na vertical"],
    ["base", AlignEndHorizontal, "Alinhar na base"],
  ];
  return (
    <div className="pointer-events-auto flex h-12 max-w-full rounded-[12px] bg-white shadow-[0_2px_6px_rgba(20,11,43,0.06),0_10px_30px_rgba(20,11,43,0.10)] ring-1 ring-black/5">
      <div ref={rola.ref} style={rola.estilo} className="no-scrollbar flex min-w-0 items-center gap-0.5 overflow-x-auto px-1.5">
        <span className="shrink-0 px-2 text-[12.5px] font-bold text-[#5B21B6]">{agrupadas ? "Grupo" : `${quantas} peças`}</span>
        {aoTrocarFoto ? (
          <button type="button" title="Trocar a foto do grupo (fica a moldura, o lugar e a animação)" className={`${BOTAO} font-bold text-[#5B21B6]`} onClick={aoTrocarFoto} data-substituir-foto>
            <Replace size={16} /> Trocar a foto
          </button>
        ) : null}
        {aoColocarDentro ? (
          <button type="button" title="Colocar dentro: a de cima aparece só dentro da outra (foto no texto, textura na forma, luz no produto)" className={BOTAO} onClick={aoColocarDentro}>
            <SquareDashedBottom size={16} /> Colocar dentro
          </button>
        ) : null}
        {aoOperar ? (
          <>
            <Divisor />
            {OPERACOES.map(([operacao, rotulo, titulo]) => (
              <button key={operacao} type="button" data-operacao={operacao} title={titulo} disabled={operando} className={`${BOTAO} disabled:opacity-40`} onClick={() => aoOperar(operacao)}>
                {operando ? null : <IconeDaOperacao operacao={operacao} />} {operacao === "aparar" ? rotulo : <span className="sr-only">{rotulo}</span>}
                {operando && operacao === "aparar" ? <Loader2 size={14} className="animate-spin" /> : null}
              </button>
            ))}
            <Divisor />
          </>
        ) : null}
        <button type="button" title={agrupadas ? "Desagrupar (Ctrl+Shift+G)" : "Agrupar (Ctrl+G): passam a andar juntas"} className={`${BOTAO} ${agrupadas ? ATIVO : ""}`} onClick={aoAgrupar}>
          {agrupadas ? <Ungroup size={16} /> : <Group size={16} />} {agrupadas ? "Desagrupar" : "Agrupar"}
        </button>
        {aoPerspectiva ? (
          <button type="button" title={perspectivaLigada ? "Pronto: sair da perspectiva" : "Perspectiva: puxe os 4 cantos e tudo entorta junto (para encaixar a arte numa caixa, parede, camiseta)"} className={`${BOTAO} ${perspectivaLigada ? ATIVO : ""}`} onClick={aoPerspectiva} data-perspectiva-do-grupo>
            <IconeDaPerspectiva /> {perspectivaLigada ? "Pronto" : "Perspectiva"}
          </button>
        ) : null}
        {aoTirarPerspectiva ? (
          <button type="button" title="Tirar a perspectiva: as peças voltam ao reto" className={BOTAO} onClick={aoTirarPerspectiva} data-tirar-perspectiva>
            Tirar perspectiva
          </button>
        ) : null}
        <Divisor />
        {alinhar.map(([valor, Icone, titulo]) => (
          <button key={valor} type="button" title={titulo} className={BOTAO} onClick={() => aoAlinhar(valor)}>
            <Icone size={17} />
          </button>
        ))}
        <Divisor />
        <button type="button" title="Distribuir na horizontal (mesmo espaço entre elas)" disabled={quantas < 3} className={`${BOTAO} disabled:opacity-30`} onClick={() => aoDistribuir("h")}>
          <AlignHorizontalSpaceAround size={17} />
        </button>
        <button type="button" title="Distribuir na vertical" disabled={quantas < 3} className={`${BOTAO} disabled:opacity-30`} onClick={() => aoDistribuir("v")}>
          <AlignVerticalSpaceAround size={17} />
        </button>
        <Divisor />
        {aoAnimar ? (
          <>
            <button type="button" title="Animar: como as peças entram, se mexem e saem no vídeo" className={`${BOTAO} ${animando ? ATIVO : ""}`} onClick={aoAnimar} data-animar>
              <Sparkles size={16} /> Animar
            </button>
            <Divisor />
          </>
        ) : null}
        <button type="button" title="Duplicar todas (Ctrl+D)" className={BOTAO} onClick={aoDuplicar}>
          <Copy size={16} />
        </button>
        <button type="button" title={travadas ? "Destravar todas" : "Travar todas"} className={`${BOTAO} ${travadas ? ATIVO : ""}`} onClick={aoTravar}>
          {travadas ? <Lock size={16} /> : <LockOpen size={16} />}
        </button>
        <button type="button" title="Apagar todas (Delete)" className={`${BOTAO} hover:!bg-[#FFE4E6] hover:!text-[#BE123C]`} onClick={aoApagar}>
          <Trash2 size={16} />
        </button>
      </div>
    </div>
  );
}

export function BarraDaPeca({
  peca,
  emEscrita,
  ajusteAberto,
  mudar,
  aoAbrir,
  pincel = false,
  aoPincel,
  aoEnquadrar,
  dpiDeImpressao = null,
  aoTirarFundo,
  aoBorracha,
  tirandoFundo = null,
  nosDoTraco = null,
  aoMexerNos,
  aoConverterEmCurvas,
  aoSeparar,
  aoTirarDeDentro,
  aoSubstituir,
  fotoDeDentro = false,
  fixa = false,
  aoFixar,
  aoAnimar,
  animando = false,
  animada = false,
  corDoVetor = null,
  aoCorDoVetor,
  coresDaFoto = null,
  corDaFoto = null,
  aoCorDaFoto,
  aoReticula,
  comReticula = false,
  aoPerspectiva,
  perspectivaLigada = false,
}: {
  peca: Peca | null;
  /* O texto escolhido está em escrita (vale o trecho, quando houver). */
  emEscrita: boolean;
  ajusteAberto: AjusteDaPeca | null;
  mudar: (campos: Partial<Peca>) => void;
  aoAbrir: (ajuste: AjusteDaPeca) => void;
  /* "Copiar estilo": liga o pincel com o estilo desta peça (o próximo clique pinta outra). */
  pincel?: boolean;
  aoPincel?: () => void;
  /* Foto: ajustar o enquadre arrastando (como o "Recortar" do Canva). */
  aoEnquadrar?: () => void;
  /* A página é de impressão nessa resolução (o aviso de foto borrada usa). */
  dpiDeImpressao?: number | null;
  /* Foto: tirar o fundo (no navegador); o texto é a etapa enquanto tira. */
  aoTirarFundo?: () => void;
  /* Elemento em SVG: a cor original aberta no painel e o clique numa bolinha (abre a troca daquela cor). */
  corDoVetor?: string | null;
  aoCorDoVetor?: (original: string) => void;
  /* Borracha: limpar restos da foto (apagar e restaurar com pincel). */
  aoBorracha?: () => void;
  tirandoFundo?: string | null;
  /* Ferramenta Forma ligada num desenho: quantos nós estão escolhidos (0 = os botões valem para todos). */
  nosDoTraco?: { escolhidos: number; fechado: boolean } | null;
  aoMexerNos?: (acao: TipoDoNo | "apagar" | "fechar") => void;
  /* Forma pronta que dá para virar curvas (Ctrl+Q). */
  aoConverterEmCurvas?: () => void;
  /* Desenho com pedaços soltos (do Aparar/Soldar): cada pedaço vira uma peça. */
  aoSeparar?: () => void;
  /* A peça está dentro de outra (máscara de recorte): tirar de dentro. */
  aoTirarDeDentro?: () => void;
  /* Trocar a foto (a escolhida, ou a de dentro da forma/texto: `fotoDeDentro`) mantendo lugar, moldura e animação. */
  aoSubstituir?: () => void;
  fotoDeDentro?: boolean;
  /* Fixar em todas as páginas (logo, rodapé, contador). */
  fixa?: boolean;
  aoFixar?: () => void;
  /* O painel "Animar"; `animada` = a peça já tem animação (o botão fica roxo). */
  aoAnimar?: () => void;
  animando?: boolean;
  animada?: boolean;
  /* Foto: as cores que compõem a imagem (`agora` já com a troca feita); o clique numa abre "Trocar cores" nela (null: o painel sem cor escolhida). */
  coresDaFoto?: Array<{ de: string; agora: string }> | null;
  corDaFoto?: string | null;
  aoCorDaFoto?: (cor: string | null) => void;
  /* Foto: o painel da retícula (halftone); `comReticula` = a foto já está em retícula. */
  aoReticula?: () => void;
  comReticula?: boolean;
  /* Perspectiva pelos 4 cantos (liga e desliga as alças dos cantos na arte). */
  aoPerspectiva?: () => void;
  perspectivaLigada?: boolean;
}) {
  const comTrecho = useTrechoEscolhido() && emEscrita;
  const rola = useBarraQueRola();

  if (!peca) {
    return (
      <div className="pointer-events-auto flex h-12 items-center gap-1 rounded-[12px] bg-white px-4 text-[12.5px] text-[#6B6584] shadow-[0_2px_6px_rgba(20,11,43,0.06),0_10px_30px_rgba(20,11,43,0.10)] ring-1 ring-black/5" data-dica-da-barra>
        Clique numa peça para editar · <b className="mx-1 font-semibold text-[#2B2640]">dois cliques</b> num texto para escrever · <b className="mx-1 font-semibold text-[#2B2640]">Shift</b> ou laço para várias
        {aoAnimar ? (
          <button type="button" onClick={aoAnimar} title="Animar a página: entrada das peças, duração e movimento do fundo" className={`ml-3 flex h-8 items-center gap-1.5 rounded-[8px] px-2.5 text-[12.5px] font-bold transition ${animando ? "bg-[#EDE7FF] text-[#6D28D9]" : "bg-[#F3F1F9] text-[#4B4760] hover:bg-[#EAE6F5] hover:text-[#1F1B2E]"}`} data-animar-pagina>
            <Sparkles size={14} /> Animar
          </button>
        ) : null}
      </div>
    );
  }

  const aberto = (a: AjusteDaPeca) => (ajusteAberto === a ? ATIVO : "");
  const ehFundo = peca.tipo === "forma" && peca.nome === "Fundo";
  /* No trecho quando houver; senão, na peça inteira. */
  const noTrechoOu = (acao: AcaoNoTrecho, inteiro: () => void, valor?: string | number) => {
    if (!(comTrecho && formatarTrecho(acao, valor))) inteiro();
  };

  return (
    <div onMouseDown={naoRoubarFoco} className="pointer-events-auto flex h-12 max-w-full rounded-[12px] bg-white shadow-[0_2px_6px_rgba(20,11,43,0.06),0_10px_30px_rgba(20,11,43,0.10)] ring-1 ring-black/5" data-barra-da-peca>
      <div ref={rola.ref} style={rola.estilo} className="no-scrollbar flex min-w-0 items-center gap-0.5 overflow-x-auto px-1.5">
        {peca.tipo === "texto" ? (
          <>
            {comTrecho ? <span className="mr-1 rounded-full bg-[#EDE7FF] px-2 py-1 text-[10.5px] font-bold text-[#5B21B6]">Trecho</span> : null}
            <button type="button" onClick={() => aoAbrir("fonte")} className={`${BOTAO} w-[148px] justify-between border border-[#E6E3EE] ${aberto("fonte")}`} title="Fonte">
              {/* A da lista ou a da marca (e as com glifos), que mostram o nome dado a elas. */}
              <span className="truncate" style={{ fontFamily: `'${fonteDaChave(peca.fonte).familia}'` }}>
                {(fonteDaChave(peca.fonte).nome || fonteDaChave(peca.fonte).familia).replace(" (com glifos)", "")}
              </span>
              <ChevronDown size={14} className="shrink-0 text-[#8A849E]" />
            </button>
            <div className="ml-1 flex h-9 shrink-0 items-center rounded-[8px] border border-[#E6E3EE]">
              <button
                type="button"
                className="flex h-full w-8 items-center justify-center text-[#4B4760] hover:bg-[#F1EFF6]"
                title="Diminuir"
                onClick={() => {
                  const base = (comTrecho && tamanhoDoTrecho()) || peca.tamanho;
                  noTrechoOu("tamanho", () => mudar({ tamanho: Math.max(6, Math.round(peca.tamanho - Math.max(1, peca.tamanho * 0.08))) }), Math.max(4, base - Math.max(1, base * 0.08)));
                }}
              >
                <Minus size={14} />
              </button>
              <span className="w-10 text-center text-[13px] font-semibold tabular-nums text-[#2B2640]">{Math.round(peca.tamanho)}</span>
              <button
                type="button"
                className="flex h-full w-8 items-center justify-center text-[#4B4760] hover:bg-[#F1EFF6]"
                title="Aumentar"
                onClick={() => {
                  const base = (comTrecho && tamanhoDoTrecho()) || peca.tamanho;
                  noTrechoOu("tamanho", () => mudar({ tamanho: Math.min(900, Math.round(peca.tamanho + Math.max(1, peca.tamanho * 0.08))) }), base + Math.max(1, base * 0.08));
                }}
              >
                <Plus size={14} />
              </button>
            </div>
            <BotaoDeCor letra fundo={peca.pintura.tipo === "nenhuma" ? "transparent" : cssDaPintura(peca.pintura)} titulo={comTrecho ? "Cor do trecho" : "Cor da letra"} aoClicar={() => aoAbrir("cor")} ativo={ajusteAberto === "cor"} />
            <button type="button" className={`${BOTAO} font-black ${!comTrecho && peca.peso >= 700 ? ATIVO : ""}`} title={comTrecho ? "Negrito no trecho (Ctrl+B)" : "Negrito"} onClick={() => noTrechoOu("negrito", () => mudar({ peso: peca.peso >= 700 ? 400 : 800 }))}>
              B
            </button>
            <button type="button" className={`${BOTAO} font-serif italic ${!comTrecho && peca.italico ? ATIVO : ""}`} title={comTrecho ? "Itálico no trecho (Ctrl+I)" : "Itálico"} onClick={() => noTrechoOu("italico", () => mudar({ italico: !peca.italico }))}>
              I
            </button>
            <button type="button" className={`${BOTAO} underline ${!comTrecho && peca.sublinhado ? ATIVO : ""}`} title={comTrecho ? "Sublinhado no trecho (Ctrl+U)" : "Sublinhado"} onClick={() => noTrechoOu("sublinhado", () => mudar({ sublinhado: !peca.sublinhado }))}>
              U
            </button>
            <button type="button" className={`${BOTAO} line-through ${!comTrecho && peca.riscado ? ATIVO : ""}`} title={comTrecho ? "Riscado no trecho" : "Riscado (preço antigo)"} onClick={() => noTrechoOu("riscado", () => mudar({ riscado: !peca.riscado }))}>
              S
            </button>
            <button type="button" className={`${BOTAO} text-[11.5px] font-bold ${peca.caixaAlta ? ATIVO : ""}`} title="Maiúsculas" onClick={() => mudar({ caixaAlta: !peca.caixaAlta })}>
              aA
            </button>
            <button type="button" className={`${BOTAO} ${aberto("glifos")}`} title="Glifos: caracteres especiais e letras alternativas da fonte" onClick={() => aoAbrir("glifos")} data-abrir-glifos>
              <Omega size={16} />
            </button>
            <button
              type="button"
              className={BOTAO}
              title="Alinhamento (clique para trocar)"
              onClick={() => mudar({ alinhamento: peca.alinhamento === "esquerda" ? "centro" : peca.alinhamento === "centro" ? "direita" : "esquerda" })}
            >
              {peca.alinhamento === "esquerda" ? <AlignLeft size={17} /> : peca.alinhamento === "centro" ? <AlignCenter size={17} /> : <AlignRight size={17} />}
            </button>
            <button
              type="button"
              className={`${BOTAO} ${peca.lista ? ATIVO : ""}`}
              title="Lista (clique para trocar: pontos, números, checks, sem)"
              onClick={() => mudar({ lista: !peca.lista ? "pontos" : peca.lista === "pontos" ? "numeros" : peca.lista === "numeros" ? "checks" : null } as Partial<Peca>)}
            >
              {peca.lista === "numeros" ? <ListOrdered size={17} /> : peca.lista === "checks" ? <ListChecks size={17} /> : <List size={17} />}
            </button>
            {peca.fundo ? <BotaoDeCor fundo={cssDaPintura(peca.fundo.pintura)} titulo="Cor do fundo do texto" aoClicar={() => aoAbrir("cor-do-fundo")} ativo={ajusteAberto === "cor-do-fundo"} /> : null}
            <Divisor />
            <button type="button" className={`${BOTAO} ${aberto("efeitos")}`} onClick={() => aoAbrir("efeitos")}>
              <Sparkles size={16} /> Efeitos
            </button>
          </>
        ) : null}

        {peca.tipo === "forma" ? (
          <>
            <BotaoDeCor fundo={peca.pintura.tipo === "nenhuma" ? "transparent" : cssDaPintura(peca.pintura)} titulo={ehFundo ? "Cor do fundo" : "Cor da forma"} aoClicar={() => aoAbrir("cor")} ativo={ajusteAberto === "cor"} />
            {ehFundo ? <span className="px-1.5 text-[12.5px] font-semibold text-[#2B2640]">Fundo</span> : null}
            <Divisor />
            <button type="button" className={`${BOTAO} ${aberto("efeitos")}`} onClick={() => aoAbrir("efeitos")}>
              <Shapes size={16} /> {ehFundo ? "Borda e sombra" : "Forma, borda e sombra"}
            </button>
            {aoConverterEmCurvas && !ehFundo ? (
              <button type="button" className={BOTAO} title="Converter em curvas (Ctrl+Q): a forma vira desenho com nós para mexer ponto a ponto" onClick={aoConverterEmCurvas}>
                <Spline size={16} /> Converter em curvas
              </button>
            ) : null}
          </>
        ) : null}

        {peca.tipo === "icone" ? (
          <>
            <BotaoDeCor fundo={cssDaPintura(peca.pintura)} titulo="Cor do ícone" aoClicar={() => aoAbrir("cor")} ativo={ajusteAberto === "cor"} />
            <Divisor />
            <button type="button" className={`${BOTAO} ${aberto("efeitos")}`} onClick={() => aoAbrir("efeitos")}>
              <Shapes size={16} /> Traço e sombra
            </button>
          </>
        ) : null}

        {peca.tipo === "textura" ? (
          <>
            <BotaoDeCor fundo={peca.cor} titulo="Cor da textura" aoClicar={() => aoAbrir("cor")} ativo={ajusteAberto === "cor"} />
            <Divisor />
            <button type="button" className={`${BOTAO} ${aberto("textura")}`} onClick={() => aoAbrir("textura")}>
              <SlidersHorizontal size={16} /> Textura
            </button>
          </>
        ) : null}

        {peca.tipo === "traco" ? (
          <>
            {peca.fechado ? (
              <BotaoDeCor fundo={peca.preenchimento.tipo === "nenhuma" ? "transparent" : cssDaPintura(peca.preenchimento)} titulo="Cor de dentro" aoClicar={() => aoAbrir("cor")} ativo={ajusteAberto === "cor"} />
            ) : (
              <BotaoDeCor fundo={peca.cor} titulo="Cor da linha" aoClicar={() => aoAbrir("cor")} ativo={ajusteAberto === "cor"} />
            )}
            <Divisor />
            <button type="button" className={`${BOTAO} ${aberto("efeitos")}`} onClick={() => aoAbrir("efeitos")}>
              <Spline size={16} /> {peca.fechado ? "Preenchimento e contorno" : "Linha e pontas"}
            </button>
            {aoSeparar ? (
              <button type="button" data-separar className={BOTAO} title="Separar: cada pedaço solto do desenho vira uma peça (os furos ficam no pedaço deles)" onClick={aoSeparar}>
                <Ungroup size={16} /> Separar
              </button>
            ) : null}
            {nosDoTraco && aoMexerNos ? (
              <>
                <Divisor />
                <span className="px-1.5 text-[11px] font-bold text-[#8A849E]">{nosDoTraco.escolhidos ? `${nosDoTraco.escolhidos} ${nosDoTraco.escolhidos === 1 ? "nó" : "nós"}` : "Todos os nós"}</span>
                <button type="button" className={BOTAO} title="Vira curva: o nó ganha alças" onClick={() => aoMexerNos("curva")}>
                  <Spline size={16} /> Curva
                </button>
                <button type="button" className={BOTAO} title="Vira reta: tira as alças (os trechos ficam retos)" onClick={() => aoMexerNos("reta")}>
                  <Slash size={15} /> Reta
                </button>
                <button type="button" className={BOTAO} title="Canto: cada alça mexe sozinha (faz bico)" onClick={() => aoMexerNos("canto")}>
                  <ChevronUp size={16} /> Canto
                </button>
                <button type="button" className={BOTAO} title="Suave: as duas alças ficam em linha (curva lisa)" onClick={() => aoMexerNos("suave")}>
                  <Waves size={16} /> Suave
                </button>
                <button type="button" className={BOTAO} title="Apagar os nós escolhidos (Delete)" disabled={!nosDoTraco.escolhidos} onClick={() => aoMexerNos("apagar")}>
                  <Trash2 size={15} />
                </button>
                <button type="button" className={BOTAO} title={nosDoTraco.fechado ? "Abrir: vira linha (sem o trecho de volta)" : "Fechar: liga o último nó ao primeiro (vira forma com cor)"} onClick={() => aoMexerNos("fechar")}>
                  {nosDoTraco.fechado ? <CircleDashed size={16} /> : <Circle size={16} />} {nosDoTraco.fechado ? "Abrir" : "Fechar"}
                </button>
              </>
            ) : null}
          </>
        ) : null}

        {peca.tipo === "qr" ? (
          <button type="button" className={`${BOTAO} ${aberto("efeitos")}`} onClick={() => aoAbrir("efeitos")}>
            <QrCode size={16} /> QR code
          </button>
        ) : null}

        {peca.tipo === "tabela" ? (
          <button type="button" className={`${BOTAO} ${aberto("efeitos")}`} onClick={() => aoAbrir("efeitos")}>
            <Sheet size={16} /> Editar tabela
          </button>
        ) : null}

        {peca.tipo === "grafico" ? (
          <button type="button" className={`${BOTAO} ${aberto("efeitos")}`} onClick={() => aoAbrir("efeitos")}>
            <ChartColumn size={16} /> Editar gráfico
          </button>
        ) : null}

        {aoSubstituir ? (
          <button type="button" className={`${BOTAO} font-bold text-[#5B21B6]`} title={fotoDeDentro ? "Substituir a foto de dentro (fica a forma, o lugar e a animação)" : "Substituir a foto: escolha outra e ela entra no mesmo lugar, tamanho e moldura"} onClick={aoSubstituir} data-substituir-foto>
            <Replace size={16} /> {fotoDeDentro ? "Trocar a foto" : "Substituir"}
          </button>
        ) : null}
        {peca.tipo === "imagem" ? (
          <>
            {peca.vetor && aoCorDoVetor ? (
              <>
                {peca.vetor.cores.slice(0, 8).map((original) => (
                  <BotaoDeCor key={original} fundo={peca.vetor?.trocas?.[original] ?? original} titulo="Trocar esta cor" aoClicar={() => aoCorDoVetor(original)} ativo={ajusteAberto === "vetor" && corDoVetor === original} />
                ))}
                {peca.vetor.cores.length > 8 ? (
                  <button type="button" className={BOTAO} title="Todas as cores deste elemento" onClick={() => aoCorDoVetor(peca.vetor!.cores[8])}>
                    +{peca.vetor.cores.length - 8}
                  </button>
                ) : null}
                <Divisor />
              </>
            ) : null}
            {coresDaFoto?.length && aoCorDaFoto ? (
              <>
                {coresDaFoto.slice(0, 6).map((c) => (
                  <BotaoDeCor key={c.de} fundo={c.agora} titulo={c.de === c.agora ? "Trocar esta cor" : `${c.de} → ${c.agora}`} aoClicar={() => aoCorDaFoto(c.de)} ativo={ajusteAberto === "cores-da-foto" && corDaFoto === c.de} />
                ))}
                <Divisor />
              </>
            ) : null}
            <button type="button" className={`${BOTAO} ${aberto("efeitos")}`} onClick={() => aoAbrir("efeitos")}>
              <Crop size={16} /> Recorte e moldura
            </button>
            {/* Ornamento em SVG não tem fundo nem pixel: tirar fundo, borracha, aviso de foto pequena e fundo verde ficam só nas fotos. */}
            {aoTirarFundo && !peca.vetor ? (
              <button type="button" className={`${BOTAO} ${tirandoFundo ? ATIVO : ""}`} title="Tirar o fundo da foto (roda no seu navegador)" disabled={Boolean(tirandoFundo)} onClick={aoTirarFundo}>
                {tirandoFundo ? <Loader2 size={16} className="animate-spin" /> : <Eraser size={16} />} {tirandoFundo || "Tirar fundo"}
              </button>
            ) : null}
            {aoBorracha && !peca.vetor ? (
              <button type="button" className={BOTAO} title="Borracha: limpar restos da foto com o pincel (apagar ou restaurar)" onClick={aoBorracha}>
                <Brush size={16} /> Borracha
              </button>
            ) : null}
            {peca.vetor ? null : <AvisoDeResolucao peca={peca} dpi={dpiDeImpressao} />}
            {aoEnquadrar && peca.ajuste === "cobrir" ? (
              <button type="button" className={BOTAO} title="Enquadrar: arraste a foto dentro da moldura (ou dois cliques nela)" onClick={aoEnquadrar}>
                <Scan size={16} /> Enquadrar
              </button>
            ) : null}
            <button type="button" className={`${BOTAO} ${aberto("ajustes")}`} onClick={() => aoAbrir("ajustes")}>
              <SlidersHorizontal size={16} /> Ajustes
            </button>
            {aoCorDaFoto ? (
              <button type="button" title="Trocar cores: as cores da imagem e o substituir cor com o conta-gotas" className={`${BOTAO} ${aberto("cores-da-foto")}`} onClick={() => aoCorDaFoto(null)} data-trocar-cores>
                <Palette size={16} /> Cores
              </button>
            ) : null}
            {aoReticula ? (
              <button type="button" title="Retícula (halftone): pontos, linhas e pontilhado, também para gravação a laser" className={`${BOTAO} ${aberto("reticula")} ${comReticula && ajusteAberto !== "reticula" ? "text-[#7C3AED]" : ""}`} onClick={aoReticula} data-reticula>
                <Grip size={16} /> Retícula
              </button>
            ) : null}
            {/* Fundo verde (chroma key): some a cor da tela, na foto e no vídeo. */}
            {peca.vetor ? null : (
              <button type="button" className={`${BOTAO} ${peca.chroma ? ATIVO : ""}`} title="Tirar o fundo verde (ou azul) de uma foto ou vídeo gravado na tela verde" onClick={() => mudar({ chroma: peca.chroma ? null : { cor: "verde", forca: 50 } } as Partial<Peca>)} data-chroma>
                <span className="h-3.5 w-3.5 rounded-[4px] bg-[#22C55E] ring-1 ring-black/10" /> Fundo verde
              </button>
            )}
            {peca.chroma ? (
              <span className="flex items-center gap-1.5 rounded-[10px] bg-[#F0FDF4] px-2 py-1" data-ajuste-do-chroma>
                {(["verde", "azul"] as const).map((cor) => (
                  <button key={cor} type="button" onClick={() => mudar({ chroma: { ...peca.chroma!, cor } } as Partial<Peca>)} className={`h-6 rounded-full px-2 text-[11px] font-bold ${peca.chroma!.cor === cor ? "bg-[#15803D] text-white" : "text-[#166534] hover:bg-white"}`}>
                    {cor === "verde" ? "Verde" : "Azul"}
                  </button>
                ))}
                <input type="range" min={0} max={100} value={peca.chroma.forca} onChange={(e) => mudar({ chroma: { ...peca.chroma!, forca: Number(e.target.value) } } as Partial<Peca>)} className="w-20 accent-[#15803D]" aria-label="Força do corte" title="Mais forte: corta mais verde (cuidado com a borda)" data-forca-do-chroma />
              </span>
            ) : null}
          </>
        ) : null}

        <Divisor />
        {aoFixar ? (
          <button type="button" title={fixa ? "Fixa em todas as páginas (clique para deixar só nesta)" : "Fixar em todas as páginas: logo, rodapé, contador (muda numa, muda em todas)"} className={`${BOTAO} ${fixa ? ATIVO : ""}`} onClick={aoFixar} data-fixar>
            <Pin size={16} />
          </button>
        ) : null}
        {aoTirarDeDentro ? (
          <button type="button" title="Tirar de dentro: a peça volta a aparecer inteira" className={BOTAO} onClick={aoTirarDeDentro}>
            <SquareDashedBottom size={16} /> Tirar de dentro
          </button>
        ) : null}
        {aoPincel ? (
          <button type="button" title="Copiar estilo: clique aqui e depois na peça que vai receber (Ctrl+Alt+C / Ctrl+Alt+V)" className={`${BOTAO} ${pincel ? ATIVO : ""}`} onClick={aoPincel}>
            <Paintbrush size={16} />
          </button>
        ) : null}
        {aoAnimar ? (
          <button type="button" title="Animar: como a peça entra, se mexe e sai no vídeo" className={`${BOTAO} ${animando ? ATIVO : ""} ${animada && !animando ? "text-[#7C3AED]" : ""}`} onClick={aoAnimar} data-animar>
            <Sparkles size={16} /> Animar
          </button>
        ) : null}
        <button type="button" title="Efeitos da camada: sombras, brilho, sombra por dentro e contorno, juntos" className={`${BOTAO} ${aberto("camada")}`} onClick={() => aoAbrir("camada")}>
          <WandSparkles size={16} />
        </button>
        {aoPerspectiva ? (
          <button type="button" title={perspectivaLigada ? "Pronto: sair da perspectiva" : "Perspectiva: puxe os 4 cantos na arte (como no Corel)"} className={`${BOTAO} ${perspectivaLigada ? ATIVO : ""}`} onClick={aoPerspectiva} data-perspectiva>
            <IconeDaPerspectiva />
          </button>
        ) : null}
        <button type="button" className={`${BOTAO} ${aberto("posicao")}`} onClick={() => aoAbrir("posicao")}>
          <Move size={16} /> Posição
        </button>
        <button type="button" title="Transparência (por igual ou em degradê, com alças na peça)" className={`${BOTAO} ${aberto("transparencia")} ${peca.transparencia || peca.opacidade < 1 ? "text-[#7C3AED]" : ""}`} onClick={() => aoAbrir("transparencia")}>
          <Blend size={17} />
        </button>
        <button type="button" className={`${BOTAO} ${peca.bloqueada ? ATIVO : ""}`} title={peca.bloqueada ? "Destravar" : "Travar no lugar"} onClick={() => mudar({ bloqueada: !peca.bloqueada })}>
          {peca.bloqueada ? <Lock size={16} /> : <LockOpen size={16} />}
        </button>
      </div>
    </div>
  );
}
