"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { Loader2, Search } from "lucide-react";
import type { Peca } from "@/lib/banner-editor/documento";
import { DEPOSITO_DAS_FIGURINHAS, figurinha, icone } from "@/lib/banner-editor/pecas-novas";
import { arrastavel } from "./arrastar-do-painel";

/*
  As bibliotecas grandes do editor: o banco de imagens grátis (Openverse,
  só CC0 e domínio público: uso comercial sem crédito), os 1.544 ícones do
  Lucide (licença ISC) e as figurinhas coloridas (Fluent Emoji, da
  Microsoft, licença MIT), com a busca em português.
*/

type Medida = { largura: number; altura: number };
type Achada = { id: string; titulo: string; miniatura: string; largura: number; altura: number; fonte: string; licenca: string };

/* Os atalhos do banco (o nome em português; a busca vai em inglês, que é a língua do acervo). */
export type AtalhoDoBanco = { nome: string; q: string };
export const ATALHOS_DO_BANCO: AtalhoDoBanco[] = [
  { nome: "Aniversário", q: "birthday party" },
  { nome: "Festa infantil", q: "kids party balloons" },
  { nome: "Casamento", q: "wedding" },
  { nome: "Bebê", q: "baby" },
  { nome: "Profissões", q: "worker at work" },
  { nome: "Escritório", q: "office work" },
  { nome: "Saúde", q: "doctor nurse" },
  { nome: "Beleza", q: "beauty salon" },
  { nome: "Comida", q: "food" },
  { nome: "Café", q: "coffee" },
  { nome: "Doces", q: "dessert cake" },
  { nome: "Flores", q: "flowers" },
  { nome: "Natureza", q: "nature landscape" },
  { nome: "Pets", q: "dog cat pet" },
  { nome: "Esportes", q: "sport" },
  { nome: "Escola", q: "school" },
  { nome: "Natal", q: "christmas" },
  { nome: "Céu", q: "sky clouds" },
  { nome: "Texturas", q: "texture" },
];

export function BancoDeImagens({ aoEnviarImagem, atalhos = ATALHOS_DO_BANCO, inicial }: { aoEnviarImagem: (lista: File[]) => void; atalhos?: AtalhoDoBanco[]; inicial?: AtalhoDoBanco }) {
  const [busca, setBusca] = useState("");
  const [atalho, setAtalho] = useState<string | null>(null);
  const [lista, setLista] = useState<Achada[]>([]);
  const [pagina, setPagina] = useState(1);
  const [total, setTotal] = useState(0);
  const [buscando, setBuscando] = useState(false);
  const [trazendo, setTrazendo] = useState<string | null>(null);
  const [erro, setErro] = useState<string | null>(null);
  const ultima = useRef("");

  const procurar = async (q: string, p = 1) => {
    if (!q.trim()) return;
    setBuscando(true);
    setErro(null);
    try {
      const r = await fetch(`/api/artes/banco?q=${encodeURIComponent(q)}&pagina=${p}`);
      const dados = (await r.json()) as { lista?: Achada[]; total?: number; error?: string };
      if (!r.ok) throw new Error(dados.error || "Não deu para buscar agora.");
      ultima.current = q;
      setPagina(p);
      setTotal(dados.total || 0);
      setLista((l) => (p === 1 ? dados.lista || [] : [...l, ...(dados.lista || [])]));
    } catch (e) {
      setErro(e instanceof Error ? e.message : "Não deu para buscar agora.");
    } finally {
      setBuscando(false);
    }
  };

  /* Abre já com fotos (o atalho inicial), em vez de uma caixa vazia esperando a palavra. */
  const abriu = useRef(false);
  useEffect(() => {
    if (abriu.current || !inicial) return;
    abriu.current = true;
    setAtalho(inicial.nome);
    void procurar(inicial.q);
  }, [inicial]);

  const usar = async (a: Achada) => {
    setTrazendo(a.id);
    setErro(null);
    try {
      const r = await fetch("/api/artes/banco", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ id: a.id }) });
      if (!r.ok) throw new Error(((await r.json().catch(() => ({}))) as { error?: string }).error || "Não deu para trazer essa imagem.");
      const blob = await r.blob();
      aoEnviarImagem([new File([blob], `banco-${a.id}.${blob.type.split("/")[1] || "jpg"}`, { type: blob.type })]);
    } catch (e) {
      setErro(e instanceof Error ? e.message : "Não deu para trazer essa imagem.");
    } finally {
      setTrazendo(null);
    }
  };

  return (
    <div data-banco-de-imagens>
      <form
        className="mb-2 flex items-center gap-2 rounded-[10px] bg-[#F3F1F9] px-3"
        onSubmit={(e) => {
          e.preventDefault();
          setAtalho(null);
          void procurar(busca);
        }}
      >
        <Search size={15} className="shrink-0 text-[#8A849E]" />
        <input value={busca} onChange={(e) => setBusca(e.target.value)} placeholder="Ex.: natal, café, praia, textura…" className="h-10 min-w-0 flex-1 bg-transparent text-[13px] outline-none placeholder:text-[#A39DB8]" aria-label="Procurar no banco de imagens" />
        {buscando ? <Loader2 size={15} className="animate-spin text-[#7C3AED]" /> : null}
      </form>
      {atalhos.length ? (
        <div className="mb-2 flex flex-wrap gap-1" data-atalhos-do-banco>
          {atalhos.map((a) => (
            <button
              key={a.nome}
              type="button"
              data-atalho-do-banco={a.nome}
              onClick={() => {
                setAtalho(a.nome);
                setBusca("");
                void procurar(a.q);
              }}
              className={`h-7 rounded-full px-2.5 text-[11.5px] font-bold transition ${atalho === a.nome ? "bg-[#7C3AED] text-white" : "bg-[#F3F1F9] text-[#4B4760] hover:bg-[#EDE7FF]"}`}
            >
              {a.nome}
            </button>
          ))}
        </div>
      ) : null}
      <p className="mb-2 text-[11px] leading-snug text-[#8A849E]">Fotos de uso livre, comercial e sem crédito (CC0 e domínio público, pelo Openverse).</p>
      {erro ? <p className="mb-2 text-[12px] font-semibold text-[#BE123C]">{erro}</p> : null}
      {lista.length ? (
        <div className="grid grid-cols-3 gap-1.5">
          {lista.map((a) => (
            <button key={a.id} type="button" title={`${a.titulo || "Imagem"} · ${a.licenca} · ${a.fonte}`} onClick={() => void usar(a)} disabled={Boolean(trazendo)} className="relative aspect-square overflow-hidden rounded-[10px] bg-[#F3F1F9] ring-1 ring-black/5 transition hover:ring-2 hover:ring-[#8B5CF6]" data-imagem-do-banco={a.id}>
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img src={a.miniatura} alt={a.titulo} loading="lazy" className="h-full w-full object-cover" />
              {trazendo === a.id ? (
                <span className="absolute inset-0 flex items-center justify-center bg-white/60">
                  <Loader2 size={18} className="animate-spin text-[#7C3AED]" />
                </span>
              ) : null}
            </button>
          ))}
        </div>
      ) : ultima.current && !buscando ? (
        <p className="text-[12px] text-[#8A849E]">Nada encontrado. Tente outra palavra.</p>
      ) : null}
      {lista.length && lista.length < total ? (
        <button type="button" disabled={buscando} onClick={() => void procurar(ultima.current, pagina + 1)} className="mt-2 h-9 w-full rounded-[10px] bg-[#F3F1F9] text-[12.5px] font-semibold text-[#4B4760] hover:bg-[#EAE5F7] disabled:opacity-50">
          Mais fotos
        </button>
      ) : null}
    </div>
  );
}

/* A busca dos ícones é em inglês (o nome do Lucide): as palavras em português viram os termos. */
const TERMOS: Record<string, string[]> = {
  natal: ["tree", "snow", "gift", "candy", "bell", "star"], presente: ["gift"], neve: ["snow"], estrela: ["star"], coracao: ["heart"], "coração": ["heart"], amor: ["heart"], flor: ["flower"], flores: ["flower"], folha: ["leaf"],
  carrinho: ["cart"], compra: ["shopping", "cart", "bag"], compras: ["shopping", "cart", "bag"], sacola: ["bag"], loja: ["store", "shop"], dinheiro: ["money", "wallet", "coins", "dollar"], cartao: ["card"], "cartão": ["card"], pix: ["qr", "zap"], desconto: ["percent", "tag", "badge"], promocao: ["percent", "tag", "badge"], "promoção": ["percent", "tag", "badge"], etiqueta: ["tag"], selo: ["badge", "award"],
  entrega: ["truck", "package"], caminhao: ["truck"], "caminhão": ["truck"], caixa: ["box", "package"], pacote: ["package"], telefone: ["phone"], whatsapp: ["message", "phone"], mensagem: ["message", "mail"], email: ["mail"], "e-mail": ["mail"], casa: ["house", "home"], local: ["map", "pin"], mapa: ["map"], relogio: ["clock", "watch"], "relógio": ["clock", "watch"], calendario: ["calendar"], "calendário": ["calendar"],
  pessoa: ["user", "person"], pessoas: ["users"], usuario: ["user"], bebe: ["baby"], "bebê": ["baby"], crianca: ["baby", "smile"], sorriso: ["smile"], festa: ["party", "cake"], bolo: ["cake"], aniversario: ["cake", "party"], "aniversário": ["cake", "party"], musica: ["music"], "música": ["music"], camera: ["camera"], "câmera": ["camera"], foto: ["image", "camera"],
  comida: ["utensils", "pizza", "apple"], cafe: ["coffee"], "café": ["coffee"], bebida: ["wine", "beer", "cup"], fruta: ["apple", "citrus", "cherry"], sol: ["sun"], lua: ["moon"], chuva: ["cloud", "rain"], fogo: ["flame"], raio: ["zap"], brilho: ["sparkle"], coroa: ["crown"], trofeu: ["trophy"], "troféu": ["trophy"], medalha: ["medal", "award"],
  seta: ["arrow"], check: ["check"], certo: ["check"], mais: ["plus"], menos: ["minus"], fechar: ["x"], busca: ["search"], lupa: ["search"], configuracao: ["settings"], ferramenta: ["wrench", "hammer"], impressora: ["printer"], livro: ["book"], escola: ["school", "graduation"], saude: ["heart-pulse", "stethoscope", "pill"], "saúde": ["heart-pulse", "stethoscope", "pill"], academia: ["dumbbell"], carro: ["car"], aviao: ["plane"], "avião": ["plane"], pascoa: ["egg", "rabbit"], "páscoa": ["egg", "rabbit"], coelho: ["rabbit"], cachorro: ["dog"], gato: ["cat"], camiseta: ["shirt"], roupa: ["shirt"], sapato: ["footprints"], oculos: ["glasses"], "óculos": ["glasses"],
};

let todosOsIcones: Promise<Array<[string, string]>> | null = null;
const carregarIcones = () => (todosOsIcones ??= fetch("/editor/icones-lucide.json").then((r) => r.json() as Promise<Array<[string, string]>>));

export function BuscaDeIcones({ medida, aoPor }: { medida: Medida; aoPor: (p: Peca) => void }) {
  const [busca, setBusca] = useState("");
  const [todos, setTodos] = useState<Array<[string, string]> | null>(null);
  const [carregando, setCarregando] = useState(false);
  const abrir = () => {
    if (todos || carregando) return;
    setCarregando(true);
    carregarIcones()
      .then(setTodos)
      .catch(() => setTodos([]))
      .finally(() => setCarregando(false));
  };
  const q = busca.trim().toLowerCase();
  const termos = q ? [...(TERMOS[q] || []), ...q.split(/\s+/).flatMap((p) => TERMOS[p] || [p])] : [];
  const achados = todos && termos.length ? todos.filter(([nome]) => termos.some((t) => nome.includes(t))).slice(0, 60) : [];
  return (
    <div data-busca-de-icones>
      <div className="mb-2 flex items-center gap-2 rounded-[10px] bg-[#F3F1F9] px-3">
        <Search size={15} className="shrink-0 text-[#8A849E]" />
        <input value={busca} onFocus={abrir} onChange={(e) => setBusca(e.target.value)} placeholder="Procurar entre 1.544 ícones (ex.: natal, entrega)" className="h-10 min-w-0 flex-1 bg-transparent text-[13px] outline-none placeholder:text-[#A39DB8]" aria-label="Procurar ícones" />
        {carregando ? <Loader2 size={15} className="animate-spin text-[#7C3AED]" /> : null}
      </div>
      {achados.length ? (
        <div className="grid grid-cols-5 gap-1.5">
          {achados.map(([nome, desenho]) => (
            <button
              key={nome}
              type="button"
              title={nome}
              data-icone-lucide={nome}
              onClick={() => aoPor(icone(medida, `lucide-${nome}`, "#141414", { desenho, nome: nome.replace(/-/g, " ") }))}
              className="flex aspect-square items-center justify-center rounded-[10px] bg-[#F3F1F9] text-[#2B2640] ring-1 ring-black/5 transition hover:bg-[#EDE7FF] hover:ring-[#8B5CF6]"
            >
              <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" dangerouslySetInnerHTML={{ __html: desenho }} />
            </button>
          ))}
        </div>
      ) : q && todos ? (
        <p className="text-[12px] text-[#8A849E]">Nenhum ícone com essa palavra. Tente outra (também vale em inglês).</p>
      ) : null}
    </div>
  );
}

/* Uma seleção de ícones pelo nome do Lucide (profissões, negócios, festas), já prontos para clicar ou arrastar. */
export function IconesEscolhidos({ medida, aoPor, nomes }: { medida: Medida; aoPor: (p: Peca) => void; nomes: string[] }) {
  const [todos, setTodos] = useState<Map<string, string> | null>(null);
  useEffect(() => {
    carregarIcones()
      .then((l) => setTodos(new Map(l)))
      .catch(() => setTodos(new Map()));
  }, []);
  if (!todos) return <Loader2 size={16} className="animate-spin text-[#7C3AED]" />;
  const achados = nomes.flatMap((nome) => {
    const desenho = todos.get(nome);
    return desenho ? [[nome, desenho] as const] : [];
  });
  const criar = (nome: string, desenho: string) => icone(medida, `lucide-${nome}`, "#141414", { desenho, nome: nome.replace(/-/g, " ") });
  return (
    <div className="grid grid-cols-6 gap-1.5" data-icones-escolhidos>
      {achados.map(([nome, desenho]) => (
        <button
          key={nome}
          type="button"
          title={`${nome.replace(/-/g, " ")} · clique ou arraste para a arte`}
          data-icone-lucide={nome}
          onClick={() => aoPor(criar(nome, desenho))}
          {...arrastavel(() => criar(nome, desenho))}
          className="flex aspect-square items-center justify-center rounded-[10px] bg-[#F3F1F9] text-[#2B2640] ring-1 ring-black/5 transition hover:bg-[#EDE7FF] hover:ring-[#8B5CF6]"
        >
          <svg viewBox="0 0 24 24" width="21" height="21" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" dangerouslySetInnerHTML={{ __html: desenho }} />
        </button>
      ))}
    </div>
  );
}

/* ------------------------------------------------------------ figurinhas */

type Figurinha = { c: string; n: string; g: string; t: string; p: number };
type IndiceDasFigurinhas = { grupos: Record<string, string>; lista: Figurinha[] };

let indiceDasFigurinhas: Promise<IndiceDasFigurinhas> | null = null;
const carregarFigurinhas = () => (indiceDasFigurinhas ??= fetch("/editor/figurinhas.json").then((r) => r.json() as Promise<IndiceDasFigurinhas>));
const semAcento = (s: string) => s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();

/* Bichinhos, café, corações, carinhas, flores, festas e profissões: desenhos sem fundo, nítidos até na caneca. */
/* `grupos`: só esses (a categoria "Profissões" mostra só as de profissão); sem, todos. */
export function BibliotecaDeFigurinhas({ medida, aoPor, grupos }: { medida: Medida; aoPor: (p: Peca) => void; grupos?: string[] }) {
  const [indice, setIndice] = useState<IndiceDasFigurinhas | null>(null);
  const [falhou, setFalhou] = useState(false);
  const [grupo, setGrupo] = useState(grupos?.[0] ?? "bichos");
  const [busca, setBusca] = useState("");
  const [quantas, setQuantas] = useState(32);
  useEffect(() => {
    carregarFigurinhas()
      .then(setIndice)
      .catch(() => setFalhou(true));
  }, []);
  const q = semAcento(busca.trim());
  const achadas = useMemo(() => (indice ? indice.lista.filter((f) => (!grupos || grupos.includes(f.g)) && (q ? q.split(/\s+/).every((p) => semAcento(`${f.n} ${f.t}`).includes(p)) : f.g === grupo)) : []), [indice, q, grupo, grupos]);
  const gruposVistos = indice ? Object.entries(indice.grupos).filter(([chave]) => !grupos || grupos.includes(chave)) : [];
  const criar = (f: Figurinha) => figurinha(medida, f.c, f.n, f.p);
  if (falhou) return <p className="text-[12px] text-[#8A849E]">Não deu para abrir as figurinhas agora.</p>;
  return (
    <div data-figurinhas>
      <div className="mb-2 flex items-center gap-2 rounded-[10px] bg-[#F3F1F9] px-3">
        <Search size={15} className="shrink-0 text-[#8A849E]" />
        <input
          value={busca}
          onChange={(e) => {
            setBusca(e.target.value);
            setQuantas(32);
          }}
          placeholder="Procurar (ex.: gato, café, coração)"
          className="h-10 min-w-0 flex-1 bg-transparent text-[13px] outline-none placeholder:text-[#A39DB8]"
          aria-label="Procurar figurinhas"
        />
        {!indice ? <Loader2 size={15} className="animate-spin text-[#7C3AED]" /> : null}
      </div>
      {indice && !q && gruposVistos.length > 1 ? (
        <div className="mb-2 flex flex-wrap gap-1">
          {gruposVistos.map(([chave, nome]) => (
            <button
              key={chave}
              type="button"
              data-grupo-de-figurinhas={chave}
              onClick={() => {
                setGrupo(chave);
                setQuantas(32);
              }}
              className={`h-7 rounded-full px-2.5 text-[11.5px] font-bold transition ${grupo === chave ? "bg-[#7C3AED] text-white" : "bg-[#F3F1F9] text-[#4B4760] hover:bg-[#EDE7FF]"}`}
            >
              {nome}
            </button>
          ))}
        </div>
      ) : null}
      {achadas.length ? (
        <div className="grid grid-cols-4 gap-1.5">
          {achadas.slice(0, quantas).map((f) => (
            <button
              key={f.c}
              type="button"
              title={`${f.n} · clique ou arraste para a arte`}
              data-figurinha={f.c}
              onClick={() => aoPor(criar(f))}
              {...arrastavel(() => criar(f))}
              className="flex aspect-square items-center justify-center rounded-[10px] bg-[#F7F5FC] p-1.5 ring-1 ring-black/5 transition hover:bg-[#EDE7FF] hover:ring-[#8B5CF6]"
            >
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img src={`${DEPOSITO_DAS_FIGURINHAS}/mini/${f.c}.webp`} alt={f.n} loading="lazy" className="max-h-full max-w-full object-contain" />
            </button>
          ))}
        </div>
      ) : q && indice ? (
        <p className="text-[12px] text-[#8A849E]">Nenhuma figurinha com essa palavra.</p>
      ) : null}
      {achadas.length > quantas ? (
        <button type="button" onClick={() => setQuantas((n) => n + 48)} className="mt-2 h-9 w-full rounded-[10px] bg-[#F3F1F9] text-[12.5px] font-semibold text-[#4B4760] hover:bg-[#EAE5F7]">
          Mais figurinhas ({achadas.length - quantas})
        </button>
      ) : null}
      <p className="mt-2 text-[10.5px] leading-snug text-[#A39DB8]">Desenhos Fluent Emoji (Microsoft, licença MIT): uso comercial liberado.</p>
    </div>
  );
}
