"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { Captions, Film, Loader2, Mic, Music2, Pause, Play, Plus, Search, Upload, Volume2, X } from "lucide-react";
import SONS from "@/lib/banner-editor/sons-da-biblioteca.json";
import { ESTILOS_DA_LEGENDA, JEITOS_DE_FALAR, MAXIMO_DA_NARRACAO, VOZES, type EstiloDaLegenda, type JeitoDeFalar, type VozDaNarracao } from "@/lib/banner-editor/narracao";

/*
 * A folha de sons, aberta em cima da linha do tempo: músicas e efeitos
 * sonoros que a loja pode usar em qualquer vídeo, inclusive vendendo. As de
 * fora são de DOMÍNIO PÚBLICO (CC0: Free Music Archive e Kenney, licença
 * conferida faixa por faixa por .cache/banner/sons-de-fora.mts); as da
 * Ktalogu foram compostas em código. E o envio do áudio da própria pessoa
 * (MP3, WAV, M4A, OGG). O ▶ ouve antes; "Usar" põe na trilha, na agulha.
 */

export type SomDoCatalogo = { chave: string; nome: string; tipo: "musica" | "efeito"; grupo: string; etiquetas: string; src: string; duracao: number; onda: number[]; fonte?: { autor: string; obra: string; licenca: string; link: string } };
const CATALOGO = SONS as SomDoCatalogo[];

export type AbaDosSons = "musica" | "efeito" | "enviar" | "narracao" | "legenda";
/* De onde a legenda automática tira a fala (um áudio da trilha ou um vídeo das cenas). */
export type FonteDaFala = { id: string; nome: string; tipo: "audio" | "video" };
export type PedidoDeNarracao = { texto: string; voz: VozDaNarracao; jeito: JeitoDeFalar; legenda: EstiloDaLegenda | null };

const tempo = (s: number) => `${Math.floor(s / 60)}:${String(Math.round(s % 60)).padStart(2, "0")}`;

/** A forma de onda em barrinhas (0 a 100 cada). */
export function Onda({ onda, cor, altura = 22, de = 0, ate = 1 }: { onda: number[]; cor: string; altura?: number; de?: number; ate?: number }) {
  const trecho = onda.slice(Math.floor(de * onda.length), Math.max(Math.floor(de * onda.length) + 1, Math.ceil(ate * onda.length)));
  return (
    <svg viewBox={`0 0 ${trecho.length} 100`} preserveAspectRatio="none" className="block w-full" style={{ height: altura }} aria-hidden>
      {trecho.map((v, i) => (
        <rect key={i} x={i + 0.2} width={0.6} y={50 - Math.max(6, v * 0.9) / 2} height={Math.max(6, v * 0.9)} rx={0.3} fill={cor} />
      ))}
    </svg>
  );
}

/* A narração: o texto, a voz, o jeito de falar e a legenda junto (opcional). */
function AbaDaNarracao({ trabalhando, aoNarrar }: { trabalhando: string | null; aoNarrar: (p: PedidoDeNarracao) => void }) {
  const [texto, setTexto] = useState("");
  const [voz, setVoz] = useState<VozDaNarracao>("nova");
  const [jeito, setJeito] = useState<JeitoDeFalar>("anuncio");
  const [legenda, setLegenda] = useState<EstiloDaLegenda | null>("palavras");
  const chip = (ativo: boolean) => `h-7 shrink-0 rounded-full px-3 text-[11.5px] font-semibold transition ${ativo ? "bg-[#1F1B2E] text-white" : "bg-[#F3F1F9] text-[#4B4760] hover:bg-[#EAE6F5]"}`;
  return (
    <div className="grid min-h-0 flex-1 grid-cols-[minmax(0,1fr)_330px] gap-4 p-3" data-aba-narracao>
      <label className="flex min-h-0 flex-col">
        <span className="mb-1 text-[11px] font-bold uppercase tracking-[0.12em] text-[#8A849E]">O que a voz fala</span>
        <textarea value={texto} onChange={(e) => setTexto(e.target.value.slice(0, MAXIMO_DA_NARRACAO))} placeholder="Ex.: Chegou a coleção nova! Camisetas, canecas e bonés com a sua estampa. Peça já pelo link da bio." className="min-h-0 flex-1 resize-none rounded-[12px] border border-[#E2DEEC] p-3 text-[13px] leading-snug text-[#1F1B2E] outline-none focus:border-[#7C3AED]" data-texto-da-narracao />
        <span className="mt-1 text-[10.5px] text-[#A39DB8]">{texto.length}/{MAXIMO_DA_NARRACAO} letras · a voz é gerada por IA</span>
      </label>
      <div className="min-w-0 space-y-2.5 overflow-y-auto">
        <div className="flex flex-wrap gap-1.5" data-vozes>
          {VOZES.map((v) => (
            <button key={v.chave} type="button" onClick={() => setVoz(v.chave)} className={chip(voz === v.chave)} title={v.detalhe} data-voz={v.chave}>
              {v.nome}
            </button>
          ))}
        </div>
        <div className="flex flex-wrap gap-1.5">
          {JEITOS_DE_FALAR.map((j) => (
            <button key={j.chave} type="button" onClick={() => setJeito(j.chave)} className={chip(jeito === j.chave)} data-jeito={j.chave}>
              {j.nome}
            </button>
          ))}
        </div>
        <div className="flex flex-wrap items-center gap-1.5">
          <span className="text-[11.5px] font-semibold text-[#6B6584]">Legenda:</span>
          {[null, ...ESTILOS_DA_LEGENDA.map((e) => e.chave)].map((e) => (
            <button key={e ?? "sem"} type="button" onClick={() => setLegenda(e)} className={chip(legenda === e)} data-legenda-junto={e ?? "sem"}>
              {e ? ESTILOS_DA_LEGENDA.find((x) => x.chave === e)!.nome : "Sem"}
            </button>
          ))}
        </div>
        <button type="button" disabled={!texto.trim() || Boolean(trabalhando)} onClick={() => aoNarrar({ texto, voz, jeito, legenda })} className="flex h-10 w-full items-center justify-center gap-2 rounded-[12px] bg-[#7C3AED] text-[13px] font-bold text-white transition hover:bg-[#6D28D9] disabled:opacity-50" data-gerar-narracao>
          {trabalhando ? <Loader2 size={15} className="animate-spin" /> : <Mic size={15} />} {trabalhando || "Gerar a narração"}
        </button>
      </div>
    </div>
  );
}

/* A legenda automática de uma fala que já está no projeto. */
function AbaDaLegenda({ fontes, trabalhando, aoLegendar }: { fontes: FonteDaFala[]; trabalhando: string | null; aoLegendar: (id: string, estilo: EstiloDaLegenda) => void }) {
  const [fonte, setFonte] = useState<string | null>(fontes[0]?.id ?? null);
  const [estilo, setEstilo] = useState<EstiloDaLegenda>("palavras");
  const chip = (ativo: boolean) => `h-8 shrink-0 rounded-full px-3 text-[12px] font-semibold transition ${ativo ? "bg-[#1F1B2E] text-white" : "bg-[#F3F1F9] text-[#4B4760] hover:bg-[#EAE6F5]"}`;
  if (!fontes.length) return <p className="flex flex-1 items-center justify-center px-6 text-center text-[13px] text-[#6B6584]">Ponha um vídeo com fala, envie um áudio ou gere uma narração: a legenda sai da fala, palavra por palavra, no tempo certo.</p>;
  return (
    <div className="flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3" data-aba-legenda>
      <div>
        <p className="mb-1.5 text-[11px] font-bold uppercase tracking-[0.12em] text-[#8A849E]">De onde vem a fala</p>
        <div className="flex flex-wrap gap-1.5">
          {fontes.map((f) => (
            <button key={f.id} type="button" onClick={() => setFonte(f.id)} className={`${chip(fonte === f.id)} flex items-center gap-1.5`} data-fonte-da-fala={f.id}>
              {f.tipo === "video" ? <Film size={13} /> : <Mic size={13} />}
              {f.nome}
            </button>
          ))}
        </div>
      </div>
      <div>
        <p className="mb-1.5 text-[11px] font-bold uppercase tracking-[0.12em] text-[#8A849E]">Jeito da legenda</p>
        <div className="flex flex-wrap gap-1.5">
          {ESTILOS_DA_LEGENDA.map((e) => (
            <button key={e.chave} type="button" onClick={() => setEstilo(e.chave)} className={chip(estilo === e.chave)} title={e.detalhe} data-estilo-da-legenda={e.chave}>
              {e.nome}
            </button>
          ))}
        </div>
      </div>
      <button type="button" disabled={!fonte || Boolean(trabalhando)} onClick={() => fonte && aoLegendar(fonte, estilo)} className="flex h-10 w-full max-w-[360px] items-center justify-center gap-2 rounded-[12px] bg-[#7C3AED] text-[13px] font-bold text-white transition hover:bg-[#6D28D9] disabled:opacity-50" data-gerar-legenda>
        {trabalhando ? <Loader2 size={15} className="animate-spin" /> : <Captions size={15} />} {trabalhando || "Gerar a legenda"}
      </button>
      <p className="text-[11px] text-[#8A849E]">A legenda entra nas cenas como texto: dá para corrigir uma palavra, mudar a cor e a fonte como qualquer texto. Gerar de novo troca a anterior.</p>
    </div>
  );
}

export function FolhaDeAudios({
  aba: abaInicial,
  enviando,
  aoUsar,
  aoEnviar,
  aoFechar,
  fontes = [],
  trabalhando = null,
  aoNarrar,
  aoLegendar,
}: {
  aba: AbaDosSons;
  enviando: boolean;
  aoUsar: (s: SomDoCatalogo) => void;
  aoEnviar: (arquivos: FileList | null) => void;
  aoFechar: () => void;
  fontes?: FonteDaFala[];
  /* O que está sendo feito agora (gerando a voz, ouvindo a fala…), ou null. */
  trabalhando?: string | null;
  aoNarrar?: (p: PedidoDeNarracao) => void;
  aoLegendar?: (id: string, estilo: EstiloDaLegenda) => void;
}) {
  const [aba, setAba] = useState<AbaDosSons>(abaInicial);
  const [busca, setBusca] = useState("");
  const [grupo, setGrupo] = useState<string | null>(null);
  const [ouvindo, setOuvindo] = useState<string | null>(null);
  const tocador = useRef<HTMLAudioElement | null>(null);
  const entrada = useRef<HTMLInputElement | null>(null);

  useEffect(
    () => () => {
      tocador.current?.pause();
    },
    [],
  );
  const ouvir = (s: SomDoCatalogo) => {
    if (!tocador.current) {
      tocador.current = new Audio();
      tocador.current.addEventListener("ended", () => setOuvindo(null));
    }
    const el = tocador.current;
    if (ouvindo === s.chave) {
      el.pause();
      setOuvindo(null);
      return;
    }
    el.src = s.src;
    el.currentTime = 0;
    void el.play().catch(() => setOuvindo(null));
    setOuvindo(s.chave);
  };

  const lista = useMemo(() => {
    const termo = busca
      .trim()
      .toLowerCase()
      .normalize("NFD")
      .replace(/[̀-ͯ]/g, "");
    return CATALOGO.filter((s) => s.tipo === aba && (!grupo || s.grupo === grupo) && (!termo || `${s.nome} ${s.grupo} ${s.etiquetas} ${s.fonte?.autor ?? ""}`.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").includes(termo)));
  }, [aba, busca, grupo]);
  /* Os gêneros da aba (na ordem em que aparecem). */
  const grupos = useMemo(() => [...new Set(CATALOGO.filter((s) => s.tipo === aba).map((s) => s.grupo))], [aba]);

  return (
    <div data-folha-de-audios className="pointer-events-auto flex h-[272px] w-full flex-col rounded-t-[18px] bg-white shadow-[0_-14px_40px_rgba(20,11,43,0.16)] ring-1 ring-black/5" onPointerDown={(e) => e.stopPropagation()}>
      <div className="flex h-11 shrink-0 items-center gap-1 border-b border-[#EFEDF5] px-3">
        <span className="mr-2 flex items-center gap-1.5 pl-1 text-[13.5px] font-bold text-[#1F1B2E]">
          <Music2 size={15} className="text-[#DB2777]" /> Sons
        </span>
        {(
          [
            ["musica", "Músicas"],
            ["efeito", "Efeitos sonoros"],
            ["enviar", "Enviar o seu"],
            ...(aoNarrar ? [["narracao", "Narração (voz)"]] : []),
            ...(aoLegendar ? [["legenda", "Legenda automática"]] : []),
          ] as Array<[AbaDosSons, string]>
        ).map(([chave, nome]) => (
          <button
            key={chave}
            type="button"
            onClick={() => {
              setAba(chave);
              setGrupo(null);
            }} className={`h-8 rounded-full px-3.5 text-[12.5px] font-semibold transition ${aba === chave ? "bg-[#1F1B2E] text-white" : "text-[#4B4760] hover:bg-[#F1EFF6]"}`} data-aba-dos-sons={chave}>
            {nome}
          </button>
        ))}
        {aba === "musica" || aba === "efeito" ? (
          <label className="ml-3 flex h-8 w-[240px] items-center gap-2 rounded-full bg-[#F3F1F9] px-3 text-[#8A849E]">
            <Search size={14} />
            <input value={busca} onChange={(e) => setBusca(e.target.value)} placeholder={aba === "musica" ? "Buscar: animada, calma, natal…" : "Buscar: swoosh, pop, sino…"} className="min-w-0 flex-1 bg-transparent text-[12.5px] text-[#2B2640] outline-none placeholder:text-[#A39DB8]" data-busca-de-sons />
          </label>
        ) : null}
        <span className="ml-auto hidden text-[11px] font-semibold text-[#8A849E] xl:block" title="As de fora são de domínio público (CC0); as da Ktalogu foram compostas por ela. Use à vontade, até em vídeo de venda.">
          Livres para uso comercial, sem crédito obrigatório
        </span>
        <button type="button" onClick={aoFechar} title="Fechar" className="ml-2 flex h-8 w-8 items-center justify-center rounded-full text-[#8A849E] transition hover:bg-[#F3F1F9] hover:text-[#1F1B2E]" data-fechar-sons>
          <X size={17} />
        </button>
      </div>

      {(aba === "musica" || aba === "efeito") && grupos.length > 1 ? (
        <div className="flex shrink-0 gap-1.5 overflow-x-auto px-3 pt-2.5 [scrollbar-width:none]" data-grupos-de-sons>
          {[null, ...grupos].map((g) => (
            <button key={g ?? "todos"} type="button" onClick={() => setGrupo(g)} className={`h-7 shrink-0 rounded-full px-3 text-[11.5px] font-semibold transition ${grupo === g ? "bg-[#DB2777] text-white" : "bg-[#F3F1F9] text-[#4B4760] hover:bg-[#EAE6F5]"}`} data-grupo-de-som={g ?? "todos"}>
              {g ?? `Todos (${CATALOGO.filter((s) => s.tipo === aba).length})`}
            </button>
          ))}
        </div>
      ) : null}
      {aba === "narracao" && aoNarrar ? (
        <AbaDaNarracao trabalhando={trabalhando} aoNarrar={aoNarrar} />
      ) : aba === "legenda" && aoLegendar ? (
        <AbaDaLegenda fontes={fontes} trabalhando={trabalhando} aoLegendar={aoLegendar} />
      ) : aba === "enviar" ? (
        <div className="flex flex-1 items-center justify-center p-4">
          <button
            type="button"
            onClick={() => entrada.current?.click()}
            onDragOver={(e) => e.preventDefault()}
            onDrop={(e) => {
              e.preventDefault();
              aoEnviar(e.dataTransfer.files);
            }}
            disabled={enviando}
            className="flex h-full w-full max-w-[640px] flex-col items-center justify-center gap-2 rounded-[16px] border-2 border-dashed border-[#D6D1E6] text-[#4B4760] transition hover:border-[#A78BFA] hover:bg-[#FAF8FF] disabled:opacity-60"
            data-enviar-audio
          >
            {enviando ? <Loader2 size={26} className="animate-spin text-[#7C3AED]" /> : <Upload size={26} className="text-[#7C3AED]" />}
            <span className="text-[14px] font-bold text-[#1F1B2E]">{enviando ? "Enviando o áudio…" : "Clique ou solte aqui o seu áudio"}</span>
            <span className="text-[12px] text-[#8A849E]">MP3, WAV, M4A ou OGG, até 50 MB. Entra na trilha de áudio, no ponto da agulha.</span>
            <span className="text-[11.5px] text-[#A39DB8]">Use só áudio que é seu ou que você tem direito de usar.</span>
          </button>
          <input ref={entrada} type="file" accept="audio/mpeg,audio/mp3,audio/wav,audio/x-wav,audio/mp4,audio/x-m4a,audio/aac,audio/ogg,audio/webm" className="hidden" onChange={(e) => aoEnviar(e.target.files)} data-entrada-de-audio />
        </div>
      ) : (
        <div className="grid min-h-0 flex-1 auto-rows-min grid-cols-1 gap-1.5 overflow-y-auto p-3 md:grid-cols-2 xl:grid-cols-3">
          {lista.length ? (
            lista.map((s) => (
              <div key={s.chave} className={`group flex items-center gap-2.5 rounded-[12px] px-2 py-1.5 ring-1 transition ${ouvindo === s.chave ? "bg-[#FDF2F8] ring-[#F9A8D4]" : "ring-[#EFEDF5] hover:bg-[#FAF9FC] hover:ring-[#E2DEEC]"}`} data-som={s.chave}>
                <button type="button" onClick={() => ouvir(s)} title={ouvindo === s.chave ? "Parar" : "Ouvir"} className={`flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-white transition ${s.tipo === "musica" ? "bg-[#DB2777] hover:bg-[#BE185D]" : "bg-[#F59E0B] hover:bg-[#D97706]"}`} data-ouvir={s.chave}>
                  {ouvindo === s.chave ? <Pause size={14} fill="currentColor" /> : <Play size={14} fill="currentColor" className="ml-0.5" />}
                </button>
                <span className="min-w-0 flex-1">
                  <span className="flex items-center gap-1.5">
                    <span className="truncate text-[12.5px] font-bold text-[#1F1B2E]">{s.nome}</span>
                    <span className="shrink-0 rounded-full bg-[#F3F1F9] px-1.5 py-[1px] text-[10px] font-semibold text-[#6B6584]">{s.grupo}</span>
                  </span>
                  {s.fonte ? (
                    <span className="block truncate text-[10.5px] text-[#8A849E]" title={`${s.fonte.obra} · ${s.fonte.licenca === "CC0 1.0" ? "domínio público (CC0 1.0)" : "composta pela Ktalogu"}`}>
                      {s.fonte.autor} · {s.fonte.licenca === "CC0 1.0" ? "domínio público" : "Ktalogu"}
                    </span>
                  ) : null}
                  <span className="flex items-center gap-2">
                    <span className="min-w-0 flex-1 opacity-70">
                      <Onda onda={s.onda} cor={s.tipo === "musica" ? "#DB2777" : "#F59E0B"} altura={14} />
                    </span>
                    <span className="shrink-0 text-[10.5px] font-semibold tabular-nums text-[#8A849E]">{tempo(s.duracao)}</span>
                  </span>
                </span>
                <button type="button" onClick={() => aoUsar(s)} title="Pôr na trilha de áudio (na agulha)" className="flex h-8 shrink-0 items-center gap-1 rounded-full bg-[#F1ECFF] px-3 text-[12px] font-bold text-[#5B21B6] transition hover:bg-[#E6DDFF]" data-usar-som={s.chave}>
                  <Plus size={13} /> Usar
                </button>
              </div>
            ))
          ) : (
            <p className="col-span-full flex items-center gap-2 px-2 py-6 text-[12.5px] text-[#8A849E]">
              <Volume2 size={15} /> Nada com “{busca}”. Tente outra palavra.
            </p>
          )}
        </div>
      )}
    </div>
  );
}
