"use client";

import { useEffect, useLayoutEffect, useRef, useState, type ReactNode } from "react";
import Link from "next/link";
import { ChevronDown, ChevronLeft, ChevronRight, User, X } from "lucide-react";
import type { ItemPronto } from "@/lib/navegacao-da-loja";
import type { BoutiqueCategoria } from "./BoutiqueShell";

/*
  O menu da Boutique: a faixa do computador (itens em caixa alta no centro do
  cabeçalho, com o megamenu que desce) e a gaveta do celular (270 px pela
  esquerda, submenus deslizando da direita com "‹ Voltar").

  Uma árvore só alimenta os dois desenhos. Ela nasce do menu que a loja
  publicou no editor (catalog_navegacao) quando existe; senão, das categorias
  — e, no menu próprio com "mostrar categorias", as categorias entram como
  mais um item. Assim nada que o lojista monta no painel fica sem lugar.
*/

export type NoDoMenu = {
  id: string;
  rotulo: string;
  href: string | null;
  externo?: boolean;
  novaAba?: boolean;
  destaque?: boolean;
  /* Ids que fazem o item contar como "onde a pessoa está". */
  ids?: string[];
  filhos: NoDoMenu[];
};

type Raiz = BoutiqueCategoria & { filhas: Array<BoutiqueCategoria & { netas: BoutiqueCategoria[] }> };

/** As categorias viram nós: raiz → filhas → netas. */
export function nosDasCategorias(arvore: Raiz[], linkDaCategoria: (categoria: BoutiqueCategoria) => string): NoDoMenu[] {
  return arvore.map((raiz) => ({
    id: `cat-${raiz.id}`,
    rotulo: raiz.name,
    href: linkDaCategoria(raiz),
    ids: [raiz.id, raiz.slug || "", ...raiz.filhas.flatMap((f) => [f.id, f.slug || "", ...f.netas.flatMap((n) => [n.id, n.slug || ""])])].filter(Boolean),
    filhos: raiz.filhas.map((filha) => ({
      id: `cat-${filha.id}`,
      rotulo: filha.name,
      href: linkDaCategoria(filha),
      filhos: filha.netas.map((neta) => ({ id: `cat-${neta.id}`, rotulo: neta.name, href: linkDaCategoria(neta), filhos: [] })),
    })),
  }));
}

/** O menu publicado no editor vira nós (um nível de filhos, como no painel). */
export function nosDoMenuProprio(itens: ItemPronto[]): NoDoMenu[] {
  return itens.map((item) => ({
    id: item.id,
    rotulo: item.rotulo,
    href: item.destino?.href ?? null,
    externo: item.destino?.externo,
    novaAba: item.destino?.novaAba,
    destaque: item.destaque,
    filhos: item.filhos.map((filho) => ({
      id: filho.id,
      rotulo: filho.rotulo,
      href: filho.destino.href,
      externo: filho.destino.externo,
      novaAba: filho.destino.novaAba,
      filhos: [],
    })),
  }));
}

function LinkDoMenu({
  no,
  className,
  style,
  onClick,
  marcas,
  children,
}: {
  no: Pick<NoDoMenu, "href" | "externo" | "novaAba">;
  className?: string;
  style?: React.CSSProperties;
  onClick?: () => void;
  /* Atributos data-* (aberto, ativo) que o CSS do tema lê. */
  marcas?: Record<string, string>;
  children: ReactNode;
}) {
  if (!no.href) {
    return (
      <span className={className} style={style} {...marcas}>
        {children}
      </span>
    );
  }
  const alvo = no.novaAba ? "_blank" : undefined;
  const rel = no.novaAba || no.externo ? "noopener noreferrer" : undefined;
  return no.externo ? (
    <a href={no.href} target={alvo} rel={rel} className={className} style={style} onClick={onClick} {...marcas}>
      {children}
    </a>
  ) : (
    <Link href={no.href} target={alvo} rel={rel} className={className} style={style} onClick={onClick} {...marcas}>
      {children}
    </Link>
  );
}

/* O destaque é vermelho (o "ESQUENTA BLACK" da referência). Dentro do painel
   e da gaveta com a cor de menu do lojista, o vermelho some no fundo colorido:
   lá o shell troca por --bq-destaque-no-painel (a cor do texto do menu) e o
   item segue destacado pelo negrito. */
const COR_DO_DESTAQUE = "var(--bq-destaque, var(--bq-selo))";
const DESTAQUE_NO_PAINEL = { "--bq-destaque": "var(--bq-destaque-no-painel, var(--bq-selo))" } as React.CSSProperties;

/* ------------------------------------------------------------------------
   Computador
   ------------------------------------------------------------------------ */

/** O painel que desce do item: colunas com título ou lista simples. */
function PainelDoItem({ no, aoEscolher, aDireita }: { no: NoDoMenu; aoEscolher: () => void; aDireita: boolean }) {
  const comNetos = no.filhos.filter((f) => f.filhos.length > 0);
  const soltos = no.filhos.filter((f) => f.filhos.length === 0);
  const colunas = comNetos.length > 0;

  const subitem = (filho: NoDoMenu) => (
    <LinkDoMenu
      key={filho.id}
      no={filho}
      onClick={aoEscolher}
      className="group/sub flex items-center gap-1.5 py-[2px] text-[13px] uppercase leading-[1.4] tracking-[0.025em] opacity-75 transition-opacity hover:opacity-100"
    >
      <ChevronRight className="h-[11px] w-[11px] shrink-0 opacity-55" strokeWidth={1.6} />
      <span className="truncate">{filho.rotulo}</span>
    </LinkDoMenu>
  );

  return (
    <div
      className={`bq-painel-menu absolute top-full z-50 ${aDireita ? "right-0" : "left-0"}`}
      style={{ color: "var(--bq-menu-fg, #262626)", ...DESTAQUE_NO_PAINEL }}
    >
      {colunas ? (
        <div className="grid w-max max-w-[min(900px,90vw)] gap-x-11 gap-y-4 px-[30px] pb-7 pt-[26px]" style={{ gridTemplateColumns: `repeat(${Math.min(comNetos.length + (soltos.length ? 1 : 0), 4)}, minmax(150px, 210px))` }}>
          {comNetos.map((filho) => (
            <div key={filho.id} className="min-w-0">
              <LinkDoMenu
                no={filho}
                onClick={aoEscolher}
                className="mb-2.5 block text-[13px] font-semibold uppercase leading-[1.3] tracking-[0.04em]"
              >
                {filho.rotulo}
              </LinkDoMenu>
              <div className="flex flex-col">
                {filho.filhos.map(subitem)}
                {filho.href ? subitem({ id: `${filho.id}-tudo`, rotulo: "Ver tudo", href: filho.href, filhos: [] }) : null}
              </div>
            </div>
          ))}
          {soltos.length || no.href ? (
            <div className="flex min-w-0 flex-col gap-2.5">
              {soltos.map((filho) => (
                <LinkDoMenu
                  key={filho.id}
                  no={filho}
                  onClick={aoEscolher}
                  className="block text-[13px] font-semibold uppercase leading-[1.3] tracking-[0.04em] opacity-90 transition-opacity hover:opacity-100"
                  style={filho.destaque ? { color: COR_DO_DESTAQUE, fontWeight: 700 } : undefined}
                >
                  {filho.rotulo}
                </LinkDoMenu>
              ))}
              {no.href ? (
                <LinkDoMenu no={no} onClick={aoEscolher} className="mt-1 block text-[13px] font-bold uppercase tracking-[0.06em]">
                  Ver tudo
                </LinkDoMenu>
              ) : null}
            </div>
          ) : null}
        </div>
      ) : (
        <div className="grid w-max max-w-[min(520px,90vw)] grid-cols-2 gap-x-8 gap-y-1 p-5" style={{ boxShadow: "var(--bq-shadow-balao)" }}>
          {no.filhos.map((filho) => (
            <LinkDoMenu
              key={filho.id}
              no={filho}
              onClick={aoEscolher}
              className="flex min-w-[180px] items-center gap-1.5 py-1 text-[13px] uppercase tracking-[0.025em] opacity-80 transition-opacity hover:opacity-100"
              style={filho.destaque ? { color: COR_DO_DESTAQUE, fontWeight: 700 } : undefined}
            >
              <ChevronRight className="h-[11px] w-[11px] shrink-0 opacity-55" strokeWidth={1.6} />
              {filho.rotulo}
            </LinkDoMenu>
          ))}
          {no.href ? (
            <LinkDoMenu no={no} onClick={aoEscolher} className="flex items-center gap-1.5 py-1 text-[13px] font-bold uppercase tracking-[0.04em]">
              <ChevronRight className="h-[11px] w-[11px] shrink-0 opacity-55" strokeWidth={1.6} />
              Ver tudo
            </LinkDoMenu>
          ) : null}
        </div>
      )}
    </div>
  );
}

/** A faixa de itens no centro do cabeçalho do computador. */
export function BoutiqueMenuDoComputador({
  nos,
  ativo,
}: {
  nos: NoDoMenu[];
  /* Diz se o item é onde a pessoa está (rota ou categoria do produto). */
  ativo: (no: NoDoMenu) => boolean;
}) {
  const [aberto, setAberto] = useState<string | null>(null);
  const fechar = useRef<number | null>(null);
  const caixa = useRef<HTMLUListElement | null>(null);

  /* Cabem uns seis itens em caixa alta; o resto vai para "Mais". Numa tela
     mais estreita (1024 a 1280 px) ou com nomes longos, nem seis cabem: a
     faixa vazava por cima da logo. Então, enquanto a lista não couber na
     coluna do meio, um item a menos passa para o "Mais" (no mínimo dois
     ficam à vista). Mudou a largura da coluna, a conta recomeça. */
  const LIMITE_MAXIMO = 6;
  const [limite, setLimite] = useState(LIMITE_MAXIMO);
  const visiveis =
    nos.length > limite
      ? [...nos.slice(0, limite - 1), { id: "__mais__", rotulo: "Mais", href: null, filhos: nos.slice(limite - 1) } as NoDoMenu]
      : nos;

  /* Medido no quadro seguinte, ainda antes da pintura. */
  useLayoutEffect(() => {
    const quadro = window.requestAnimationFrame(() => {
      const lista = caixa.current;
      const casa = lista?.parentElement;
      if (!lista || !casa || !casa.clientWidth) return;
      if (lista.scrollWidth > casa.clientWidth + 1) setLimite((atual) => Math.max(2, atual - 1));
    });
    return () => window.cancelAnimationFrame(quadro);
  }, [limite, nos]);

  useEffect(() => {
    const casa = caixa.current?.parentElement;
    if (!casa || typeof ResizeObserver === "undefined") return;
    let largura = casa.clientWidth;
    const observador = new ResizeObserver(() => {
      const nova = casa.clientWidth;
      if (Math.abs(nova - largura) < 2) return;
      largura = nova;
      setLimite(LIMITE_MAXIMO);
    });
    observador.observe(casa);
    return () => observador.disconnect();
  }, []);

  useEffect(() => {
    if (!aberto) return;
    const esc = (evento: KeyboardEvent) => {
      if (evento.key === "Escape") setAberto(null);
    };
    const fora = (evento: MouseEvent) => {
      if (!caixa.current?.contains(evento.target as Node)) setAberto(null);
    };
    document.addEventListener("keydown", esc);
    document.addEventListener("mousedown", fora);
    return () => {
      document.removeEventListener("keydown", esc);
      document.removeEventListener("mousedown", fora);
    };
  }, [aberto]);

  const abrir = (id: string | null) => {
    if (fechar.current) window.clearTimeout(fechar.current);
    setAberto(id);
  };
  /* Um respiro antes de fechar: o mouse cruza o vão entre o item e o painel. */
  const fecharDepois = () => {
    if (fechar.current) window.clearTimeout(fechar.current);
    fechar.current = window.setTimeout(() => setAberto(null), 140);
  };

  return (
    <ul ref={caixa} className="flex h-full min-w-0 items-stretch justify-center" onMouseLeave={fecharDepois}>
      {visiveis.map((no, indice) => {
        const temFilhos = no.filhos.length > 0;
        const estaAberto = aberto === no.id;
        const classe =
          "bq-item-menu relative flex h-full items-center gap-1 whitespace-nowrap px-1.5 text-[12px] font-bold uppercase tracking-[1px] xl:px-2 xl:text-[14px]";
        /* Os itens ficam sobre a barra do cabeçalho: a cor é a do texto do
           cabeçalho (herdada). A cor do menu vale no painel e na gaveta, que
           têm fundo próprio. Nunca cor fixa: com fundo escuro o menu sumia. */
        const estilo = {
          fontFamily: "var(--bq-fonte-menu)",
          ...(no.destaque ? { color: COR_DO_DESTAQUE } : {}),
        };
        const marcas: Record<string, string> = {
          ...(estaAberto ? { "data-aberto": "" } : {}),
          ...(ativo(no) ? { "data-ativo": "" } : {}),
        };
        return (
          <li
            key={no.id}
            className="relative flex h-full items-stretch"
            onMouseEnter={() => abrir(temFilhos ? no.id : null)}
          >
            {temFilhos && !no.href ? (
              <button
                type="button"
                className={classe}
                style={estilo}
                aria-expanded={estaAberto}
                onClick={() => abrir(estaAberto ? null : no.id)}
                {...marcas}
              >
                {no.rotulo}
                <ChevronDown className={`h-3.5 w-3.5 shrink-0 opacity-60 transition-transform ${estaAberto ? "rotate-180" : ""}`} strokeWidth={1.6} />
              </button>
            ) : (
              <LinkDoMenu no={no} className={classe} style={estilo} onClick={() => setAberto(null)} marcas={marcas}>
                {no.rotulo}
                {temFilhos ? (
                  <ChevronDown className={`h-3.5 w-3.5 shrink-0 opacity-60 transition-transform ${estaAberto ? "rotate-180" : ""}`} strokeWidth={1.6} />
                ) : null}
              </LinkDoMenu>
            )}
            {temFilhos && estaAberto ? (
              <PainelDoItem no={no} aoEscolher={() => setAberto(null)} aDireita={indice >= Math.ceil(visiveis.length / 2) + 1} />
            ) : null}
          </li>
        );
      })}
    </ul>
  );
}

/* ------------------------------------------------------------------------
   Celular
   ------------------------------------------------------------------------ */

export function BoutiqueGaveta({
  aberta,
  aoFechar,
  nos,
  slug,
  clienteLogado,
}: {
  aberta: boolean;
  aoFechar: () => void;
  nos: NoDoMenu[];
  slug: string;
  clienteLogado?: boolean;
}) {
  /* O caminho dos submenus abertos: cada nível é um painel por cima. */
  const [pilha, setPilha] = useState<NoDoMenu[]>([]);

  /* Fechou a gaveta: volta para o começo na próxima vez. */
  useEffect(() => {
    if (aberta) return;
    const relogio = window.setTimeout(() => setPilha([]), 500);
    return () => window.clearTimeout(relogio);
  }, [aberta]);

  const escolher = () => aoFechar();

  const linha = (no: NoDoMenu, negrito = false) =>
    no.filhos.length ? (
      <button
        key={no.id}
        type="button"
        onClick={() => setPilha((antes) => [...antes, no])}
        className="flex h-12 w-full items-center justify-between px-2 text-left text-[14px] uppercase"
        style={no.destaque ? { color: COR_DO_DESTAQUE, fontWeight: 700 } : undefined}
      >
        <span className={`truncate ${negrito ? "font-bold" : ""}`}>{no.rotulo}</span>
        <ChevronRight className="h-4 w-4 shrink-0" style={{ color: "#c1c1c1" }} strokeWidth={1.5} />
      </button>
    ) : (
      <LinkDoMenu
        key={no.id}
        no={no}
        onClick={escolher}
        className={`flex h-12 w-full items-center px-2 text-[14px] uppercase ${negrito ? "font-bold" : ""}`}
        style={no.destaque ? { color: COR_DO_DESTAQUE, fontWeight: 700 } : undefined}
      >
        <span className="truncate">{no.rotulo}</span>
      </LinkDoMenu>
    );

  return (
    <div
      className={`fixed inset-0 z-[60] lg:hidden ${aberta ? "visible" : "invisible"}`}
      style={{ transition: `visibility 0s linear ${aberta ? "0s" : "0.5s"}` }}
      aria-hidden={!aberta}
    >
      <div
        className="absolute inset-0 bg-black/40 transition-opacity duration-500"
        style={{ opacity: aberta ? 1 : 0 }}
        onClick={aoFechar}
      />
      <button
        type="button"
        onClick={aoFechar}
        aria-label="Fechar menu"
        tabIndex={aberta ? 0 : -1}
        className="absolute left-[270px] top-0 flex h-[34px] w-[34px] items-center justify-center bg-white text-black transition-opacity duration-500"
        style={{ opacity: aberta ? 1 : 0 }}
      >
        <X className="h-7 w-7" strokeWidth={1.4} />
      </button>

      <nav
        className="absolute inset-y-0 left-0 flex w-[270px] flex-col overflow-hidden"
        style={{
          backgroundColor: "var(--bq-menu-bg, #ffffff)",
          color: "var(--bq-menu-fg, #252525)",
          ...DESTAQUE_NO_PAINEL,
          transform: aberta ? "translateX(0)" : "translateX(-100%)",
          transition: "transform 0.5s var(--bq-curva)",
        }}
        aria-label="Menu"
      >
        <div className="flex min-h-[66px] shrink-0 flex-col items-center justify-center bg-black px-3 text-center text-white">
          <p className="flex items-center gap-1.5 text-[14px] font-bold">
            <User className="h-4 w-4" fill="currentColor" strokeWidth={1.5} />
            {clienteLogado ? "Olá!" : "Olá, visitante!"}
          </p>
          {clienteLogado ? (
            <Link href={`/${slug}/cliente`} onClick={escolher} className="text-[14px] underline underline-offset-2">
              Minha conta
            </Link>
          ) : (
            <p className="text-[14px]">
              <Link href={`/${slug}/cliente/login`} onClick={escolher} className="underline underline-offset-2">
                Entre
              </Link>{" "}
              ou{" "}
              <Link href={`/${slug}/cadastro-cliente`} onClick={escolher} className="underline underline-offset-2">
                cadastre-se
              </Link>{" "}
              aqui
            </p>
          )}
        </div>

        <div className="relative flex-1 overflow-hidden">
          <div className="absolute inset-0 overflow-y-auto">{nos.map((no) => linha(no))}</div>

          {pilha.map((no, nivel) => (
            <div
              key={`${no.id}-${nivel}`}
              className="bq-gaveta-painel absolute inset-0 overflow-y-auto"
              style={{ backgroundColor: "var(--bq-menu-bg, #ffffff)" }}
            >
              <p className="flex h-12 items-center px-2 text-[14px] uppercase">{no.rotulo}:</p>
              <button
                type="button"
                onClick={() => setPilha((antes) => antes.slice(0, -1))}
                className="flex h-12 w-full items-center gap-2 px-2 text-left text-[14px]"
                style={{ backgroundColor: "#f2f2f2", color: "#252525" }}
              >
                <ChevronLeft className="h-4 w-4" style={{ color: "#c1c1c1" }} strokeWidth={1.5} />
                Voltar
              </button>
              {no.filhos.map((filho) => linha(filho))}
              {no.href ? linha({ id: `${no.id}-tudo`, rotulo: "Ver tudo", href: no.href, externo: no.externo, filhos: [] }, true) : null}
            </div>
          ))}
        </div>
      </nav>
    </div>
  );
}
