import { animacaoNova, type AnimacaoDaPeca, type EfeitoDaAnimacao } from "./animacao";
import type { ElementoPronto } from "./cupons-e-selos";
import { escalarPeca, novoId, solida, type Peca, type PecaDeForma, type PecaDeIcone, type PecaDeImagem, type PecaDeTexto, type PecaDeTextura, type PecaDeTraco, type Pintura, type Sombra } from "./documento";
import { FOTO_DA_MOLDURA, forma as formaPronta, texto as textoPronto, type Medida } from "./pecas-novas";

/*
 * Elementos prontos PARA VÍDEO (out/2026): o que os reels usam o tempo todo,
 * já animado e com a coreografia montada (o cursor anda e clica, o
 * interruptor liga, a notificação desce, o confete cai, a contagem troca).
 * Quem usa não desenha nada: põe, troca o texto ou a foto (as telas têm
 * moldura) e arrasta os clipes na linha do tempo. Desenhados numa prancha e
 * escalados para a arte; as peças que se mexem juntas vêm agrupadas, as que
 * têm o tempo delas vêm soltas (todas entram escolhidas, para mover juntas).
 */

const P: Medida = { largura: 1000, altura: 1000 };
const nada: Pintura = { tipo: "nenhuma", cor: "#FFFFFF", cor2: "#FFFFFF", angulo: 0 };
const linear = (cor: string, cor2: string, angulo = 135): Pintura => ({ tipo: "linear", cor, cor2, angulo });
const sombra = (y = 18, desfoque = 40, opacidade = 0.22, cor = "#000000"): Sombra => ({ cor, x: 0, y, desfoque, opacidade });

/* ----------------------------------------------------------- peças curtas */

type CamposDoTexto = Partial<PecaDeTexto> & { cor?: string };
function t(texto: string, x: number, y: number, w: number, h: number, campos: CamposDoTexto = {}): PecaDeTexto {
  const { cor, ...resto } = campos;
  return { ...textoPronto(P, { texto, tamanho: h * 0.72, linha: 1.1, fonte: "montserrat", peso: 800, ...(cor ? { pintura: solida(cor) } : {}), ...resto }, w, h), x, y, nome: texto.split("\n")[0].slice(0, 30) };
}
function f(tipo: PecaDeForma["forma"], x: number, y: number, w: number, h: number, cor: string | Pintura, campos: Partial<PecaDeForma> = {}): PecaDeForma {
  return { ...formaPronta(P, tipo, w, h, "#000000", { raio: 0, ...campos }), pintura: typeof cor === "string" ? solida(cor) : cor, x, y, ...(campos.pintura ? { pintura: campos.pintura } : {}) };
}
function ic(chave: string, x: number, y: number, lado: number, cor: string, campos: Partial<PecaDeIcone> = {}): PecaDeIcone {
  return { id: novoId("ic"), tipo: "icone", nome: "Ícone", x, y, w: lado, h: lado, rot: 0, opacidade: 1, icone: chave, pintura: solida(cor), espessura: 2, preenchido: false, sombra: null, ...campos };
}
/* Moldura vazia (a pessoa solta a foto dela em cima, ou clica em Substituir). */
function tela(x: number, y: number, w: number, h: number, campos: Partial<PecaDeImagem> = {}): PecaDeImagem {
  return { id: novoId("i"), tipo: "imagem", nome: "Moldura", x, y, w, h, rot: 0, opacidade: 1, src: FOTO_DA_MOLDURA, papel: "foto", ajuste: "cobrir", raio: 0, circulo: false, borda: null, sombra: null, filtros: { brilho: 100, contraste: 100, saturacao: 100, desfoque: 0 }, moldura: true, ...campos };
}
/* Traço livre pelos pontos (px da prancha). */
function tr(nome: string, pontos: Array<[number, number]>, cor: string, espessura: number, campos: Partial<PecaDeTraco> = {}): PecaDeTraco {
  const xs = pontos.map((p) => p[0]);
  const ys = pontos.map((p) => p[1]);
  const x = Math.min(...xs);
  const y = Math.min(...ys);
  const w = Math.max(1, Math.max(...xs) - x);
  const h = Math.max(1, Math.max(...ys) - y);
  return { id: novoId("tr"), tipo: "traco", nome, x, y, w, h, rot: 0, opacidade: 1, pontos: pontos.map(([px, py]) => ({ x: (px - x) / w, y: (py - y) / h })), fechado: false, suave: true, cor, espessura, tracejado: "solido", inicio: "nada", fim: "nada", preenchimento: nada, sombra: null, ...campos };
}
/* Mancha orgânica: 7 nós em volta do centro (a `semente` muda o desenho). */
function mancha(cx: number, cy: number, r: number, cor: string, semente: number): PecaDeTraco {
  const pontos = Array.from({ length: 7 }, (_, i): [number, number] => {
    const ang = (i / 7) * Math.PI * 2 + semente;
    const rr = r * (0.62 + 0.38 * ((Math.sin(semente * 7.3 + i * 2.17) + 1) / 2));
    return [cx + rr * Math.cos(ang), cy + rr * Math.sin(ang)];
  });
  return tr("Mancha", pontos, cor, 1, { fechado: true, preenchimento: solida(cor) });
}

/* --------------------------------------------------------- a animação */

function anima<T extends Peca>(pecas: T | T[], entrada: EfeitoDaAnimacao | null, inicio: number, extra: Partial<AnimacaoDaPeca> = {}): T[] {
  const lista = Array.isArray(pecas) ? pecas : [pecas];
  const a = animacaoNova(entrada, { inicio, ...extra });
  return lista.map((p) => ({ ...p, animacao: a }));
}
/* As peças que se mexem juntas (um clipe só na linha do tempo). */
function junto<T extends Peca>(pecas: T[]): T[] {
  const grupo = novoId("g");
  return pecas.map((p) => ({ ...p, grupo }));
}
/* O cursor chega, anda até o ponto e clica (o clique cai logo depois de chegar). */
function cursor(x: number, y: number, lado: number, cor: string, chega: number, dx: number, dy: number, anda: number, icone = "cursor") {
  return anima(ic(icone, x, y, lado, cor, { preenchido: icone === "cursor", espessura: icone === "cursor" ? 1.4 : 2, sombra: sombra(6, 14, 0.4) }), "pop", chega, { duracao: 0.35, mover: { dx, dy, inicio: anda, duracao: 0.6 }, enfase: "clicar", ritmo: Math.max(0.5, anda + 0.62 - (chega + 0.35)) });
}

/** Escala a prancha (W × H) para ocupar `fracao` do lado menor da arte, no meio; as distâncias do "Mover até" escalam junto. */
function montar(m: Medida, W: number, H: number, fracao: number, pecas: Peca[]): Peca[] {
  const k = (Math.min(m.largura, m.altura) * fracao) / Math.max(W, H);
  const ox = (m.largura - W * k) / 2;
  const oy = (m.altura - H * k) / 2;
  return pecas.map((p) => {
    const e = escalarPeca(p, k);
    const a = p.animacao;
    return { ...e, x: ox + p.x * k, y: oy + p.y * k, ...(a?.mover ? { animacao: { ...a, mover: { ...a.mover, dx: a.mover.dx * k, dy: a.mover.dy * k } } } : {}) } as Peca;
  });
}

/* =========================================================== interface */

export const TELAS_DE_VIDEO: ElementoPronto[] = [
  {
    chave: "v-celular",
    nome: "Celular com a sua tela",
    busca: "celular telefone smartphone mockup tela app iphone",
    criar: (m) =>
      montar(m, 520, 1000, 0.62, [
        ...anima(
          junto([
            f("retangulo", 0, 0, 520, 1000, "#0E0E10", { raio: 78, borda: { cor: "#3A3A40", largura: 6 }, sombra: sombra(30, 60, 0.35) }),
            tela(22, 22, 476, 956, { raio: 58 }),
            f("retangulo", 195, 44, 130, 34, "#0E0E10", { raio: 17 }),
          ]),
          "subir",
          0.15,
          { duracao: 0.7, enfase: "flutuar", ritmo: 3.2 },
        ),
      ]),
  },
  {
    chave: "v-navegador",
    nome: "Janela do site",
    busca: "navegador site janela browser mockup computador pagina loja",
    criar: (m) =>
      montar(m, 1000, 680, 0.86, [
        ...anima(
          junto([
            f("retangulo", 0, 0, 1000, 680, "#FFFFFF", { raio: 26, sombra: sombra(28, 60, 0.25) }),
            f("retangulo", 0, 0, 1000, 76, "#F1F0F5", { raio: 26 }),
            f("retangulo", 0, 50, 1000, 26, "#F1F0F5"),
            f("circulo", 30, 27, 22, 22, "#FF5F57"),
            f("circulo", 62, 27, 22, 22, "#FEBC2E"),
            f("circulo", 94, 27, 22, 22, "#28C840"),
            f("retangulo", 150, 18, 640, 40, "#FFFFFF", { raio: 20 }),
            t("suamarca.com.br", 175, 22, 590, 32, { peso: 600, tamanho: 22, cor: "#6B6880", alinhamento: "esquerda" }),
            tela(14, 90, 972, 576, { raio: 14 }),
          ]),
          "chicote",
          0.15,
          { direcao: "esquerda", duracao: 0.6 },
        ),
      ]),
  },
  {
    chave: "v-notificacao",
    nome: "Notificação descendo",
    busca: "notificacao push aviso pedido venda alerta celular",
    criar: (m) =>
      montar(m, 900, 210, 0.8, [
        ...anima(
          junto([
            f("retangulo", 0, 0, 900, 210, "#FFFFFF", { raio: 44, sombra: sombra(20, 50, 0.22) }),
            f("retangulo", 32, 35, 140, 140, linear("#8B5CF6", "#5B21B6"), { raio: 34 }),
            ic("sino", 67, 70, 70, "#FFFFFF", { espessura: 2.2 }),
            t("Novo pedido recebido", 200, 42, 560, 56, { tamanho: 44, cor: "#16131F", alinhamento: "esquerda" }),
            t("Maria comprou 2 itens · R$ 189,90", 200, 108, 660, 50, { peso: 500, tamanho: 34, cor: "#5E5A6E", alinhamento: "esquerda" }),
            t("agora", 760, 46, 110, 40, { peso: 600, tamanho: 28, cor: "#9A96AA", alinhamento: "direita" }),
          ]),
          "deslizar",
          0.2,
          { direcao: "baixo", duracao: 0.55, enfase: "tremer", ritmo: 2.4 },
        ),
      ]),
  },
  {
    chave: "v-comentario",
    nome: "Comentário com curtida",
    busca: "comentario depoimento cliente avaliacao instagram curtida",
    criar: (m) =>
      montar(m, 900, 230, 0.8, [
        ...anima(
          junto([
            f("retangulo", 0, 0, 900, 230, "#FFFFFF", { raio: 40, sombra: sombra(18, 46, 0.2) }),
            tela(34, 45, 140, 140, { circulo: true }),
            t("@cliente.feliz", 205, 52, 520, 50, { tamanho: 36, cor: "#16131F", alinhamento: "esquerda" }),
            t("Amei! Chegou rapidinho e perfeito", 205, 112, 600, 60, { peso: 500, tamanho: 34, cor: "#3F3B4E", alinhamento: "esquerda" }),
          ]),
          "subir",
          0.2,
          { duracao: 0.55 },
        ),
        ...anima(ic("coracao", 790, 82, 70, "#F43F5E", { preenchido: true }), "pop", 0.85, { duracao: 0.4, enfase: "pulsar", ritmo: 1.1 }),
      ]),
  },
  {
    chave: "v-conversa",
    nome: "Conversa no direct",
    busca: "mensagem direct whatsapp conversa chat balao cliente",
    criar: (m) =>
      montar(m, 900, 420, 0.82, [
        ...anima(junto([f("retangulo", 0, 0, 640, 140, "#EDEBF3", { raio: 50 }), t("Oi! Ainda tem no tamanho M?", 30, 38, 580, 64, { peso: 600, tamanho: 36, cor: "#16131F" })]), "pop", 0.2, { duracao: 0.4 }),
        ...anima(junto([f("retangulo", 260, 200, 640, 140, linear("#22C55E", "#15803D", 160), { raio: 50 }), t("Tem sim! Já separei pra você", 290, 238, 580, 64, { peso: 600, tamanho: 36, cor: "#FFFFFF" })]), "pop", 1.0, { duracao: 0.4 }),
        ...anima(t("Visto agora", 640, 356, 260, 44, { peso: 600, tamanho: 26, cor: "#8A869A", alinhamento: "direita" }), "surgir", 1.4),
      ]),
  },
  {
    chave: "v-curtidas",
    nome: "Curtidas subindo",
    busca: "curtida coracao like amei engajamento seguidores",
    criar: (m) =>
      montar(m, 900, 700, 0.7, [
        ...anima(ic("coracao", 300, 160, 300, "#F43F5E", { preenchido: true, sombra: sombra(16, 34, 0.25, "#9F1239") }), "elastico", 0.15, { duracao: 0.7, enfase: "pulsar", ritmo: 1.2 }),
        ...anima(t("+1,2 mil curtidas", 50, 500, 800, 110, { peso: 900, tamanho: 76, cor: "#16131F" }), "subir", 0.55),
        ...[0, 1, 2, 3].flatMap((i) =>
          anima(ic("coracao", [210, 620, 330, 540][i], 330, [70, 90, 56, 64][i], ["#FB7185", "#F43F5E", "#FDA4AF", "#E11D48"][i], { preenchido: true }), "pop", 0.6 + i * 0.22, {
            duracao: 0.3,
            mover: { dx: [-60, 50, -20, 30][i], dy: -330, inicio: 0.75 + i * 0.22, duracao: 1.3 },
            fim: 1.9 + i * 0.22,
            saida: "surgir",
            duracaoDaSaida: 0.3,
          }),
        ),
      ]),
  },
  {
    chave: "v-botao-comprar",
    nome: "Botão com clique",
    busca: "botao comprar clique cursor cta saiba mais link",
    criar: (m) =>
      montar(m, 760, 420, 0.78, [
        ...anima(
          junto([
            f("retangulo", 0, 0, 680, 160, linear("#22C55E", "#15803D", 160), { raio: 80, sombra: sombra(20, 40, 0.3, "#14532D") }),
            ic("carrinho", 70, 46, 68, "#FFFFFF", { espessura: 2.4 }),
            t("COMPRAR AGORA", 150, 42, 500, 76, { peso: 900, tamanho: 46, cor: "#FFFFFF", espaco: 0.02 }),
          ]),
          "pop",
          0.15,
          { duracao: 0.45, enfase: "pulsar", ritmo: 1.3 },
        ),
        ...cursor(620, 300, 120, "#FFFFFF", 0.55, -170, -190, 0.95),
      ]),
  },
  {
    chave: "v-interruptor",
    nome: "Interruptor ligando",
    busca: "interruptor toggle ligar ativar botao switch",
    criar: (m) =>
      montar(m, 900, 200, 0.7, [
        f("retangulo", 0, 0, 360, 200, "#D4D2DD", { raio: 100, nome: "Desligado" }),
        ...anima(f("retangulo", 0, 0, 360, 200, linear("#22C55E", "#16A34A", 90), { raio: 100, nome: "Ligado" }), "surgir", 0.95, { duracao: 0.3 }),
        ...anima(f("circulo", 18, 18, 164, 164, "#FFFFFF", { sombra: sombra(8, 18, 0.25), nome: "Botão" }), null, 0, { mover: { dx: 160, dy: 0, inicio: 0.85, duracao: 0.4 } }),
        ...anima(t("Notificações", 410, 55, 490, 90, { tamanho: 62, cor: "#16131F", alinhamento: "esquerda" }), "deslizar", 0.2, { direcao: "direita" }),
      ]),
  },
  {
    chave: "v-progresso",
    nome: "Barra enchendo",
    busca: "barra progresso carregando porcentagem meta enchendo",
    criar: (m) =>
      montar(m, 900, 220, 0.8, [
        ...anima(t("Pedidos do mês", 0, 0, 600, 70, { tamanho: 50, cor: "#16131F", alinhamento: "esquerda" }), "subir", 0.1),
        ...anima(t("100%", 700, 0, 200, 70, { peso: 900, tamanho: 54, cor: "#7C3AED", alinhamento: "direita" }), "pop", 1.85, { duracao: 0.35 }),
        f("retangulo", 0, 110, 900, 70, "#ECEAF3", { raio: 35 }),
        ...anima(f("retangulo", 0, 110, 900, 70, linear("#A78BFA", "#6D28D9", 90), { raio: 35 }), "revelar", 0.3, { direcao: "direita", duracao: 1.6 }),
      ]),
  },
  {
    chave: "v-estrelas",
    nome: "Cinco estrelas",
    busca: "estrelas avaliacao nota 5 cinco review depoimento",
    criar: (m) =>
      montar(m, 920, 330, 0.8, [
        ...[0, 1, 2, 3, 4].flatMap((i) => anima(ic("estrela", i * 190, 0, 160, "#FBBF24", { preenchido: true, sombra: sombra(8, 16, 0.25, "#92400E") }), "pop", 0.15 + i * 0.13, { duracao: 0.35 })),
        ...anima(t("5,0 · 1.240 avaliações", 60, 210, 800, 90, { peso: 700, tamanho: 54, cor: "#16131F" }), "subir", 0.95),
      ]),
  },
  {
    chave: "v-busca",
    nome: "Busca digitando",
    busca: "busca pesquisa google campo digitando procurar",
    criar: (m) =>
      montar(m, 900, 140, 0.82, [
        ...anima(junto([f("retangulo", 0, 0, 900, 140, "#FFFFFF", { raio: 70, borda: { cor: "#E2E0EA", largura: 3 }, sombra: sombra(14, 40, 0.16) }), ic("busca", 44, 38, 64, "#7A7690", { espessura: 2.4 })]), "aproximar", 0.1, { duracao: 0.45 }),
        ...anima(t("camiseta personalizada", 140, 36, 700, 68, { peso: 600, tamanho: 46, cor: "#16131F", alinhamento: "esquerda" }), "maquina", 0.55, { duracao: 1.2 }),
      ]),
  },
  {
    chave: "v-preco",
    nome: "Preço que cai",
    busca: "preco promocao desconto de por riscado oferta valor",
    criar: (m) =>
      montar(m, 800, 420, 0.75, [
        ...anima(t("De R$ 99,90", 100, 0, 600, 100, { peso: 700, tamanho: 70, cor: "#8A869A" }), "subir", 0.15),
        ...anima(f("retangulo", 110, 42, 580, 16, "#EF4444", { raio: 8, rot: -6 }), "revelar", 0.6, { direcao: "direita", duracao: 0.35 }),
        ...anima(t("POR R$ 49,90", 0, 150, 800, 200, { fonte: "anton", peso: 400, tamanho: 104, cor: "#16131F", fundo: { forma: "pilula", pintura: solida("#C6F432"), borda: null, raio: 100, pontas: 16, profundidade: 0.2 } }), "carimbo", 1.0, { duracao: 0.4, enfase: "pulsar", ritmo: 1.4 }),
      ]),
  },
];

/* ============================================================ destaques */

export const DESTAQUES_DE_VIDEO: ElementoPronto[] = [
  {
    chave: "v-cursor",
    nome: "Cursor que clica",
    busca: "cursor mouse seta clique clicar apontar",
    criar: (m) =>
      montar(m, 600, 500, 0.5, [
        ...anima(f("circulo", 60, 20, 160, 160, nada, { borda: { cor: "#C6F432", largura: 10 }, nome: "Onda do clique" }), "aproximar", 1.25, { duracao: 0.3, fim: 1.55, saida: "surgir", duracaoDaSaida: 0.35 }),
        ...cursor(430, 330, 130, "#FFFFFF", 0.15, -320, -260, 0.55),
      ]),
  },
  {
    chave: "v-mao",
    nome: "Mão tocando",
    busca: "mao dedo toque tocar clique apontar",
    criar: (m) => montar(m, 300, 300, 0.32, anima(ic("mao-clique", 0, 0, 300, "#FFFFFF", { espessura: 1.8, sombra: sombra(6, 14, 0.4) }), "pop", 0.2, { duracao: 0.35, enfase: "clicar", ritmo: 1 })),
  },
  {
    chave: "v-selecao",
    nome: "Caixa de seleção",
    busca: "selecao caixa tracejada alcas figma editar moldura destaque",
    criar: (m) => {
      const [W, H] = [800, 420];
      const alca = (x: number, y: number) => f("retangulo", x - 14, y - 14, 28, 28, "#FFFFFF", { borda: { cor: "#7C3AED", largura: 5 } });
      return montar(m, W, H + 90, 0.8, [
        ...anima(tr("Seleção", [[0, 0], [W, 0], [W, H], [0, H]], "#7C3AED", 5, { fechado: true, suave: false, tracejado: "tracejado" }), "revelar", 0.15, { direcao: "direita", duracao: 0.45 }),
        ...anima(junto([alca(0, 0), alca(W, 0), alca(0, H), alca(W, H)]), "pop", 0.55, { duracao: 0.3 }),
        ...anima(t("1080 × 1080", W / 2 - 150, H + 22, 300, 60, { peso: 700, tamanho: 34, cor: "#FFFFFF", fundo: { forma: "pilula", pintura: solida("#7C3AED"), borda: null, raio: 30, pontas: 16, profundidade: 0.2 } }), "pop", 0.75, { duracao: 0.3 }),
      ]);
    },
  },
  {
    chave: "v-circulo-rabiscado",
    nome: "Círculo à mão",
    busca: "circulo rabisco caneta destaque marcar riscar mao",
    criar: (m) => {
      const pontos = Array.from({ length: 15 }, (_, i): [number, number] => {
        const a = -Math.PI * 0.62 + (i / 13) * Math.PI * 2.12;
        const r = 1 + 0.05 * Math.sin(i * 1.7);
        return [450 + 430 * r * Math.cos(a), 250 + 220 * r * Math.sin(a)];
      });
      return montar(m, 900, 500, 0.75, anima(tr("Círculo à mão", pontos, "#EF4444", 12), "circulo", 0.2, { duracao: 0.6 }));
    },
  },
  {
    chave: "v-seta-rabiscada",
    nome: "Seta desenhada",
    busca: "seta rabisco desenhada apontar caneta olha aqui",
    criar: (m) =>
      montar(m, 600, 400, 0.55, [
        ...anima(
          junto([tr("Seta", [[20, 360], [120, 220], [300, 150], [520, 90]], "#16131F", 14), tr("Ponta", [[430, 40], [540, 85], [470, 180]], "#16131F", 14, { suave: false })]),
          "revelar",
          0.2,
          { direcao: "direita", duracao: 0.55, enfase: "flutuar", ritmo: 1.8 },
        ),
      ]),
  },
  {
    chave: "v-sublinhado",
    nome: "Sublinhado pincel",
    busca: "sublinhado pincel risco onda destaque linha",
    criar: (m) => montar(m, 900, 120, 0.8, anima(tr("Sublinhado", [[0, 80], [150, 40], [300, 76], [450, 38], [600, 74], [750, 36], [900, 70]], "#7C3AED", 18), "revelar", 0.2, { direcao: "direita", duracao: 0.5 })),
  },
  {
    chave: "v-marca-texto",
    nome: "Marca-texto",
    busca: "marca texto destaque faixa caneta neon amarelo",
    criar: (m) => montar(m, 900, 150, 0.8, anima(f("retangulo", 0, 0, 900, 150, "#C6F432", { raio: 10, opacidade: 0.9, mistura: "multiplicar", rot: -1.5 }), "revelar", 0.2, { direcao: "direita", duracao: 0.4 })),
  },
  {
    chave: "v-brilhos",
    nome: "Brilhos piscando",
    busca: "brilho estrela faisca sparkle magica destaque",
    criar: (m) =>
      montar(
        m,
        500,
        420,
        0.45,
        [
          [0, 120, 260, "#FBBF24"],
          [280, 0, 170, "#FDE68A"],
          [330, 250, 130, "#FBBF24"],
        ].flatMap(([x, y, lado, cor], i) => anima(ic("estrela-4", x as number, y as number, lado as number, cor as string, { preenchido: true }), "pop", 0.15 + i * 0.18, { duracao: 0.35, enfase: i === 1 ? "girar" : "pulsar", ritmo: 1 + i * 0.35 })),
      ),
  },
  {
    chave: "v-manchas",
    nome: "Manchas que dançam",
    busca: "mancha forma organica blob bolha fundo decoracao",
    criar: (m) =>
      montar(m, 900, 700, 0.85, [
        ...anima(mancha(180, 520, 180, "#16131F", 1.1), "pop", 0.1, { enfase: "balancar", ritmo: 3 }),
        ...anima(mancha(720, 180, 150, "#16131F", 2.6), "pop", 0.22, { enfase: "flutuar", ritmo: 2.4 }),
        ...anima(mancha(640, 560, 90, "#C6F432", 4.2), "pop", 0.34, { enfase: "flutuar", ritmo: 2 }),
      ]),
  },
  {
    chave: "v-confete",
    nome: "Confete caindo",
    busca: "confete festa comemoracao parabens celebracao chuva",
    criar: (m) => {
      const cores = ["#F43F5E", "#FBBF24", "#22C55E", "#3B82F6", "#A855F7", "#F97316"];
      const pecas = Array.from({ length: 16 }, (_, i) => {
        const x = 40 + ((i * 397) % 920);
        const y = 20 + ((i * 131) % 160);
        const tipo = (["retangulo", "circulo", "triangulo"] as const)[i % 3];
        const [w, h] = tipo === "retangulo" ? [26, 46] : [32, 32];
        const comeco = 0.1 + (i % 6) * 0.07;
        const cai = 1.6 + (i % 4) * 0.25;
        return anima(f(tipo, x, y, w, h, cores[i % cores.length], { raio: tipo === "retangulo" ? 4 : 0, rot: (i * 47) % 180 }), "pop", comeco, {
          duracao: 0.25,
          mover: { dx: ((i % 5) - 2) * 60, dy: 760, inicio: comeco + 0.15, duracao: cai },
          enfase: "girar",
          ritmo: 0.8 + (i % 4) * 0.3,
          fim: comeco + 0.15 + cai,
          saida: "surgir",
          duracaoDaSaida: 0.3,
        });
      });
      return montar(m, 1000, 1000, 1, pecas.flat());
    },
  },
  {
    chave: "v-impacto",
    nome: "Raios de impacto",
    busca: "impacto raios explosao destaque atencao uau boom",
    criar: (m) => {
      const raios = Array.from({ length: 12 }, (_, i) => {
        const a = (i / 12) * Math.PI * 2;
        const [cx, cy] = [400 + 330 * Math.cos(a), 400 + 330 * Math.sin(a)];
        return f("retangulo", cx - 60, cy - 9, 120, 18, "#16131F", { raio: 9, rot: (a * 180) / Math.PI });
      });
      return montar(m, 800, 800, 0.7, anima(junto(raios), "aproximar", 0.15, { duracao: 0.35, enfase: "pulsar", ritmo: 0.9 }));
    },
  },
  {
    chave: "v-numero-que-sobe",
    nome: "Número que sobe",
    busca: "numero contador sobe contagem vendas resultado economia valor",
    criar: (m) =>
      montar(m, 900, 330, 0.85, [
        ...anima(t("+R$ 1.300", 0, 0, 900, 220, { fonte: "anton", peso: 400, tamanho: 200, linha: 1, cor: "#16131F" }), "carimbo", 0.1, { duracao: 0.35, contador: { de: 0, inicio: 0.15, duracao: 1.6, curva: "freia" } }),
        ...anima(t("economizados por ano", 0, 230, 900, 90, { peso: 700, tamanho: 56, cor: "#5B21B6" }), "subir", 0.9),
      ]),
  },
  {
    chave: "v-cartao-3d",
    nome: "Cartão que vira em 3D",
    busca: "cartao 3d virar flip carta perspectiva girar",
    criar: (m) =>
      montar(m, 700, 900, 0.62, [
        ...anima(
          junto([
            f("retangulo", 0, 0, 700, 900, linear("#7C3AED", "#3B0764", 160), { raio: 48, sombra: sombra(30, 70, 0.35) }),
            tela(40, 40, 620, 560, { raio: 30 }),
            t("NOVIDADE", 40, 640, 620, 110, { fonte: "anton", peso: 400, tamanho: 96, cor: "#FFFFFF" }),
            t("toque para ver", 40, 760, 620, 70, { fonte: "caveat", peso: 700, tamanho: 60, cor: "#C6F432" }),
          ]),
          "virar",
          0.15,
          { duracao: 0.9, enfase: "balancar3d", ritmo: 3 },
        ),
      ]),
  },
  {
    chave: "v-contagem",
    nome: "Contagem 3, 2, 1",
    busca: "contagem regressiva 3 2 1 numeros comeca lancamento",
    criar: (m) =>
      montar(m, 500, 500, 0.55, [
        ...anima(f("circulo", 0, 0, 500, 500, nada, { borda: { cor: "#C6F432", largura: 18 } }), "aproximar", 0.1, { duracao: 0.4, enfase: "pulsar", ritmo: 0.7 }),
        ...["3", "2", "1"].flatMap((n, i) => anima(t(n, 50, 60, 400, 380, { fonte: "anton", peso: 400, tamanho: 330, linha: 1, cor: "#FFFFFF" }), "carimbo", 0.2 + i * 0.7, { duracao: 0.25, fim: 0.75 + i * 0.7, saida: "surgir", duracaoDaSaida: 0.12 })),
      ]),
  },
];

/* ============================================================ partículas */

/* A tela inteira com partículas que se mexem no vídeo (a textura animada, particulas.ts). */
function particulas(m: Medida, estilo: PecaDeTextura["estilo"], cor: string, quantidade: number, extra: Partial<PecaDeTextura> = {}): Peca[] {
  return [{ id: novoId("tex"), tipo: "textura", nome: "Partículas", x: 0, y: 0, w: m.largura, h: m.altura, rot: 0, opacidade: 1, estilo, cor, quantidade, tamanho: Math.round(Math.min(m.largura, m.altura) * 0.018), centroX: 50, centroY: 50, giro: 0, ...extra }];
}
export const PARTICULAS_DE_VIDEO: ElementoPronto[] = [
  { chave: "v-p-confete", nome: "Chuva de confete", busca: "confete festa particulas comemoracao chuva", criar: (m) => particulas(m, "confete", "#F43F5E", 90) },
  { chave: "v-p-fogos", nome: "Fogos de artifício", busca: "fogos artificio explosao festa ano novo particulas", criar: (m) => particulas(m, "fogos", "#FBBF24", 120) },
  { chave: "v-p-brilhos", nome: "Brilhos piscando", busca: "brilhos estrelas magia glitter particulas", criar: (m) => particulas(m, "brilhos", "#FDE68A", 50) },
  { chave: "v-p-neve", nome: "Neve caindo", busca: "neve natal inverno frio particulas", criar: (m) => particulas(m, "neve", "#FFFFFF", 140) },
  { chave: "v-p-bolhas", nome: "Bolhas subindo", busca: "bolhas sabao agua particulas", criar: (m) => particulas(m, "bolhas", "#FFFFFF", 30, { tamanho: Math.round(Math.min(m.largura, m.altura) * 0.035) }) },
  { chave: "v-p-coracoes", nome: "Corações subindo", busca: "coracoes amor namorados maes particulas", criar: (m) => particulas(m, "coracoes", "#F43F5E", 28, { tamanho: Math.round(Math.min(m.largura, m.altura) * 0.03) }) },
  { chave: "v-p-faiscas", nome: "Faíscas", busca: "faiscas fogo energia particulas impacto", criar: (m) => particulas(m, "faiscas", "#FDBA74", 80, { centroY: 85 }) },
];

/* =================================================== títulos e legendas */

const caixa = (cor: string, raio = 14) => ({ forma: "retangulo" as const, pintura: solida(cor), borda: null, raio, pontas: 16, profundidade: 0.2 });

export const LEGENDAS_DE_VIDEO: ElementoPronto[] = [
  {
    chave: "v-legenda-palavras",
    nome: "Legenda palavra por palavra",
    busca: "legenda palavra por palavra fala reels tiktok capcut caption",
    criar: (m) => montar(m, 900, 260, 0.85, anima(t("SUA LEGENDA ENTRA\nPALAVRA POR PALAVRA", 0, 0, 900, 260, { fonte: "anton", peso: 400, tamanho: 104, linha: 1.15, cor: "#FFFFFF", fundo: caixa("#16131F") }), "chicote", 0.15, { porPalavra: true, duracao: 1.3 })),
  },
  {
    chave: "v-legenda-destaque",
    nome: "Título com palavra marcada",
    busca: "titulo destaque marca texto palavra chave reels",
    criar: (m) =>
      montar(m, 900, 330, 0.85, [
        ...anima(t("O SEGREDO PARA", 0, 0, 900, 130, { fonte: "anton", peso: 400, tamanho: 110, cor: "#16131F" }), "chicote", 0.1, { porPalavra: true, duracao: 0.6 }),
        ...anima({ ...t("VENDER MAIS", 0, 150, 900, 170, { fonte: "anton", peso: 400, tamanho: 150, cor: "#16131F" }), destaque: { pintura: solida("#C6F432"), respiro: 0.14, raio: 6 } }, "revelar", 0.75, { direcao: "direita", duracao: 0.42 }),
      ]),
  },
  {
    chave: "v-nome-e-cargo",
    nome: "Nome na tela (lower third)",
    busca: "nome cargo apresentacao lower third entrevista legenda pessoa",
    criar: (m) =>
      montar(m, 760, 170, 0.75, [
        ...anima(f("retangulo", 0, 0, 22, 170, "#7C3AED", { raio: 6 }), "revelar", 0.1, { direcao: "baixo", duracao: 0.3 }),
        ...anima(t("Maria Souza", 40, 0, 560, 96, { tamanho: 58, cor: "#16131F", alinhamento: "esquerda", fundo: caixa("#FFFFFF", 10) }), "revelar", 0.3, { direcao: "direita", duracao: 0.4 }),
        ...anima(t("Fundadora · Ateliê Aurora", 40, 104, 470, 62, { peso: 600, tamanho: 32, cor: "#FFFFFF", alinhamento: "esquerda", fundo: caixa("#7C3AED", 10) }), "revelar", 0.5, { direcao: "direita", duracao: 0.4 }),
      ]),
  },
  {
    chave: "v-ao-vivo",
    nome: "Selo ao vivo",
    busca: "ao vivo live transmissao gravando rec selo",
    criar: (m) =>
      montar(m, 420, 130, 0.42, [
        ...anima(junto([f("retangulo", 0, 0, 420, 130, linear("#EF4444", "#B91C1C", 160), { raio: 65 }), t("AO VIVO", 105, 26, 300, 78, { peso: 900, tamanho: 52, cor: "#FFFFFF", espaco: 0.04 })]), "pop", 0.15, { duracao: 0.4 }),
        ...anima(f("circulo", 40, 40, 50, 50, "#FFFFFF"), "pop", 0.35, { duracao: 0.3, enfase: "piscar", ritmo: 1 }),
      ]),
  },
  {
    chave: "v-enquete",
    nome: "Enquete com votos",
    busca: "enquete pergunta votacao opcoes sim nao pesquisa",
    criar: (m) =>
      montar(m, 860, 560, 0.8, [
        ...anima(junto([f("retangulo", 0, 0, 860, 560, "#FFFFFF", { raio: 46, sombra: sombra(24, 60, 0.18) }), t("Qual cor você prefere?", 50, 50, 760, 80, { tamanho: 52, cor: "#16131F" })]), "subir", 0.1),
        ...[
          ["Lilás", 0.64, "#8B5CF6"],
          ["Verde", 0.36, "#22C55E"],
        ].flatMap(([nome, parte, cor], i) => {
          const y = 190 + i * 170;
          return [
            ...anima(f("retangulo", 50, y, 760, 120, "#F1F0F6", { raio: 60 }), "surgir", 0.35 + i * 0.1),
            ...anima(f("retangulo", 50, y, 760 * (parte as number), 120, cor as string, { raio: 60, opacidade: 0.9 }), "revelar", 0.6 + i * 0.15, { direcao: "direita", duracao: 0.9 }),
            ...anima(t(`${nome}  ${Math.round((parte as number) * 100)}%`, 90, y + 26, 680, 70, { tamanho: 44, cor: "#16131F", alinhamento: "esquerda" }), "surgir", 0.6 + i * 0.15),
          ];
        }),
      ]),
  },
  {
    chave: "v-titulo-eco",
    nome: "Título com eco",
    busca: "titulo eco contorno vazado promocao grande impacto",
    criar: (m) =>
      montar(m, 920, 260, 0.88, [
        ...anima(t("PROMOÇÃO", 16, 16, 900, 240, { fonte: "anton", peso: 400, tamanho: 200, pintura: nada, contorno: { cor: "#7C3AED", largura: 4 } }), "surgir", 0.45, { duracao: 0.4 }),
        ...anima(t("PROMOÇÃO", 0, 0, 900, 240, { fonte: "anton", peso: 400, tamanho: 200, cor: "#16131F" }), "chicote", 0.1, { duracao: 0.45 }),
      ]),
  },
];

/** As peças de um elemento encaixadas na caixa (cabem inteiras, no meio dela); as distâncias do "Mover até" escalam junto. */
export function encaixar(pecas: Peca[], caixa: { x: number; y: number; w: number; h: number }): Peca[] {
  const x = Math.min(...pecas.map((p) => p.x));
  const y = Math.min(...pecas.map((p) => p.y));
  const w = Math.max(...pecas.map((p) => p.x + p.w)) - x;
  const h = Math.max(...pecas.map((p) => p.y + p.h)) - y;
  const k = Math.min(caixa.w / w, caixa.h / h);
  const ox = caixa.x + (caixa.w - w * k) / 2;
  const oy = caixa.y + (caixa.h - h * k) / 2;
  return pecas.map((p) => {
    const e = escalarPeca(p, k);
    const a = p.animacao;
    return { ...e, x: ox + (p.x - x) * k, y: oy + (p.y - y) * k, ...(a?.mover ? { animacao: { ...a, mover: { ...a.mover, dx: a.mover.dx * k, dy: a.mover.dy * k } } } : {}) } as Peca;
  });
}

/** O elemento pronto pela chave (para os modelos usarem). */
export const elementoDeVideo = (chave: string) => [...TELAS_DE_VIDEO, ...DESTAQUES_DE_VIDEO, ...LEGENDAS_DE_VIDEO, ...PARTICULAS_DE_VIDEO].find((e) => e.chave === chave)!;
export { mancha as manchaDeVideo };
