"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { Loader2, Search } from "lucide-react";
import type { Peca } from "@/lib/banner-editor/documento";
import { ANGULOS_3D, CORES_3D, buscarNaBiblioteca, carregarBiblioteca, ehIcone3d, miniDoItem, pecaDaBiblioteca, variantePadrao, type IndiceDaBiblioteca, type ItemDaBiblioteca } from "@/lib/banner-editor/biblioteca";
import { arrastavel } from "./arrastar-do-painel";

/*
 * A biblioteca de recortes (PNG sem fundo) e de ícones 3D no painel:
 * grupos em fichas, a busca (genérica ou pelo nome), a grade e, no ícone 3D,
 * a janelinha em cima dele com os ângulos e as cores para escolher qual entra.
 * Arrastar para a arte põe a variação padrão (colorido, na diagonal).
 */

type Medida = { largura: number; altura: number };
const POR_VEZ = 48;

/* A miniatura que não veio (o depósito às vezes recusa uma rajada) tenta de novo uma vez, um pouco depois. */
function tentarDeNovo(e: React.SyntheticEvent<HTMLImageElement>) {
  const img = e.currentTarget;
  if (img.dataset.tentou) return;
  img.dataset.tentou = "1";
  window.setTimeout(() => {
    img.src = `${img.src.split("?")[0]}?r=1`;
  }, 1500);
}

function useBiblioteca() {
  const [indice, setIndice] = useState<IndiceDaBiblioteca | null>(null);
  const [falhou, setFalhou] = useState(false);
  useEffect(() => {
    let vivo = true;
    carregarBiblioteca()
      .then((i) => vivo && setIndice(i))
      .catch(() => vivo && setFalhou(true));
    return () => {
      vivo = false;
    };
  }, []);
  return { indice, falhou };
}

/* A janelinha das variações do ícone 3D, presa em cima do quadradinho clicado (fora do painel, para não ser cortada). */
function EscolhaDaVariacao({ item, ancora, aoEscolher, aoFechar }: { item: ItemDaBiblioteca; ancora: DOMRect; aoEscolher: (variante: string) => void; aoFechar: () => void }) {
  const caixa = useRef<HTMLDivElement | null>(null);
  useEffect(() => {
    const fora = (e: PointerEvent) => {
      if (!caixa.current?.contains(e.target as Node)) aoFechar();
    };
    const tecla = (e: KeyboardEvent) => e.key === "Escape" && aoFechar();
    window.addEventListener("pointerdown", fora, true);
    window.addEventListener("keydown", tecla);
    window.addEventListener("resize", aoFechar);
    return () => {
      window.removeEventListener("pointerdown", fora, true);
      window.removeEventListener("keydown", tecla);
      window.removeEventListener("resize", aoFechar);
    };
  }, [aoFechar]);
  const angulos = ANGULOS_3D.filter((a) => item.v?.some((v) => v.startsWith(`${a.chave}_`)));
  const cores = CORES_3D.filter((c) => item.v?.some((v) => v.endsWith(`_${c.chave}`)));
  /* Só as imagens (sem nome de ângulo nem de cor: a miniatura já mostra). A conta inclui o espaço de dentro (12 de cada lado) e o vão entre os quadradinhos. */
  const LADO = 60;
  const VAO = 6;
  const largura = 24 + cores.length * LADO + (cores.length - 1) * VAO;
  const altura = 24 + angulos.length * LADO + (angulos.length - 1) * VAO;
  /* Em cima do quadradinho; sem espaço, embaixo. Sempre dentro da janela. */
  const cima = ancora.top - altura - 8 > 8;
  const top = cima ? ancora.top - altura - 8 : Math.min(window.innerHeight - altura - 8, ancora.bottom + 8);
  const left = Math.max(8, Math.min(window.innerWidth - largura - 8, ancora.left + ancora.width / 2 - largura / 2));
  return createPortal(
    <div ref={caixa} role="dialog" aria-label={`Escolher a variação de ${item.n}`} className="fixed z-[200] box-border rounded-[14px] bg-white p-3 shadow-[0_18px_50px_rgba(20,11,43,0.28)] ring-1 ring-black/5" style={{ top, left, width: largura }} data-variacoes-3d={item.c}>
      <div className="grid" style={{ gridTemplateColumns: `repeat(${cores.length}, ${LADO}px)`, gap: VAO }}>
        {angulos.flatMap((a) =>
          cores.map((c) => {
            const v = `${a.chave}_${c.chave}`;
            return item.v?.includes(v) ? (
              <button key={v} type="button" onClick={() => aoEscolher(v)} title={`${a.nome} · ${c.nome}`} className="flex items-center justify-center rounded-[10px] bg-[#F6F4FB] p-1 ring-1 ring-black/5 transition hover:bg-[#EDE7FF] hover:ring-[#8B5CF6]" style={{ width: LADO, height: LADO }} data-variacao={v}>
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img src={miniDoItem(item, v)} alt={`${a.nome} · ${c.nome}`} onError={tentarDeNovo} className="max-h-full max-w-full object-contain" />
              </button>
            ) : (
              <span key={v} style={{ width: LADO, height: LADO }} />
            );
          }),
        )}
      </div>
    </div>,
    document.body,
  );
}

/**
 * A grade da biblioteca. `grupos`: só esses (sem, todos); `termo`: a busca
 * vem de fora (a barra de cima de Elementos) e a própria some (sem achado,
 * nada aparece); `inicial`: o grupo aberto de começo; `limite`: só uma
 * amostra (com "Ver todos"); `titulo`: o título da seção.
 */
export function BibliotecaDeImagens({ medida, aoPor, grupos, termo, inicial, limite, aoVerTodos, titulo }: { medida: Medida; aoPor: (p: Peca) => void; grupos?: string[]; termo?: string; inicial?: string; limite?: number; aoVerTodos?: () => void; titulo?: string }) {
  const { indice, falhou } = useBiblioteca();
  const [busca, setBusca] = useState("");
  const [grupo, setGrupo] = useState<string | null>(inicial ?? null);
  const [quantos, setQuantos] = useState(limite ?? POR_VEZ);
  const [escolhendo, setEscolhendo] = useState<{ item: ItemDaBiblioteca; ancora: DOMRect } | null>(null);
  const deFora = termo !== undefined;
  const q = (deFora ? termo : busca).trim();
  const gruposVistos = useMemo(() => (indice ? Object.keys(indice.grupos).filter((g) => (!grupos || grupos.includes(g)) && indice.lista.some((i) => i.g === g)) : []), [indice, grupos]);
  const achados = useMemo(() => {
    if (!indice) return [];
    if (q) return buscarNaBiblioteca(indice, q, grupos);
    const g = grupo ?? (gruposVistos.length === 1 ? gruposVistos[0] : null);
    return indice.lista.filter((i) => (g ? i.g === g : !grupos || grupos.includes(i.g)));
  }, [indice, q, grupo, grupos, gruposVistos]);
  if (falhou) return <p className="text-[12px] text-[#8A849E]">Não deu para abrir a biblioteca agora.</p>;
  if (!indice) return <Loader2 size={16} className="animate-spin text-[#7C3AED]" />;
  if (deFora && !achados.length) return null;
  const por = (item: ItemDaBiblioteca, variante?: string) => aoPor(pecaDaBiblioteca(medida, item, variante));
  const clicar = (item: ItemDaBiblioteca, e: React.MouseEvent<HTMLButtonElement>) => {
    if (ehIcone3d(item) && (item.v?.length || 0) > 1) setEscolhendo({ item, ancora: e.currentTarget.getBoundingClientRect() });
    else por(item);
  };
  return (
    <div className={titulo ? "mb-6" : undefined} data-biblioteca-de-imagens>
      {titulo ? (
        <h3 className="mb-2.5 flex items-baseline justify-between text-[13px] font-bold text-[#1F1B2E]">
          {titulo} {q ? <span className="text-[11px] font-medium text-[#8A849E]">{achados.length}</span> : null}
        </h3>
      ) : null}
      {deFora ? null : (
        <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);
              setQuantos(limite ?? POR_VEZ);
            }}
            placeholder="Procurar (ex.: bolo, mulher de terno, fogo)"
            className="h-10 min-w-0 flex-1 bg-transparent text-[13px] outline-none placeholder:text-[#A39DB8]"
            aria-label="Procurar na biblioteca"
            data-busca-da-biblioteca
          />
        </div>
      )}
      {!q && !limite && gruposVistos.length > 1 ? (
        <div className="mb-2 flex flex-wrap gap-1">
          {[null, ...gruposVistos].map((g) => (
            <button
              key={g ?? "todos"}
              type="button"
              onClick={() => {
                setGrupo(g);
                setQuantos(POR_VEZ);
              }}
              className={`h-7 rounded-full px-2.5 text-[11.5px] font-bold transition ${grupo === g ? "bg-[#7C3AED] text-white" : "bg-[#F3F1F9] text-[#4B4760] hover:bg-[#EDE7FF]"}`}
              data-grupo-da-biblioteca={g ?? "todos"}
            >
              {g ? indice.grupos[g] : "Todos"}
            </button>
          ))}
        </div>
      ) : null}
      {achados.length ? (
        <div className="grid grid-cols-3 gap-1.5">
          {achados.slice(0, quantos).map((item) => (
            <button
              key={item.c}
              type="button"
              title={`${item.n}${ehIcone3d(item) && (item.v?.length || 0) > 1 ? " · clique para escolher o ângulo e a cor" : " · clique ou arraste para a arte"}`}
              onClick={(e) => clicar(item, e)}
              {...arrastavel(() => pecaDaBiblioteca(medida, item, variantePadrao(item)))}
              className="relative 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]"
              data-item-da-biblioteca={item.c}
            >
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img src={miniDoItem(item)} alt={item.n} loading="lazy" draggable={false} onError={tentarDeNovo} className="max-h-full max-w-full object-contain" />
              {ehIcone3d(item) && (item.v?.length || 0) > 1 ? <span className="absolute bottom-1 right-1 rounded-full bg-white/90 px-1.5 text-[9.5px] font-bold text-[#6D28D9] ring-1 ring-black/5">{item.v?.length}</span> : null}
            </button>
          ))}
        </div>
      ) : (
        <p className="text-[12px] text-[#8A849E]">Nada com essa palavra. Tente outra (ou uma mais geral, como “comida” ou “pessoa”).</p>
      )}
      {limite && aoVerTodos && achados.length > limite ? (
        <button type="button" onClick={aoVerTodos} className="mt-2 h-9 w-full rounded-[10px] bg-[#F3F1F9] text-[12.5px] font-semibold text-[#4B4760] hover:bg-[#EAE5F7]">
          Ver todos ({achados.length})
        </button>
      ) : achados.length > quantos ? (
        <button type="button" onClick={() => setQuantos((n) => n + POR_VEZ)} className="mt-2 h-9 w-full rounded-[10px] bg-[#F3F1F9] text-[12.5px] font-semibold text-[#4B4760] hover:bg-[#EAE5F7]">
          Mais ({achados.length - quantos})
        </button>
      ) : null}
      {escolhendo ? (
        <EscolhaDaVariacao
          item={escolhendo.item}
          ancora={escolhendo.ancora}
          aoFechar={() => setEscolhendo(null)}
          aoEscolher={(v) => {
            por(escolhendo.item, v);
            setEscolhendo(null);
          }}
        />
      ) : null}
    </div>
  );
}
