"use client";

import { PlayerDaGaleria, SeloDePlay } from "@/components/produto/VideoDoProduto";
import type { VideoDoProduto } from "@/lib/video-do-produto";
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { useRouter } from "next/navigation";
import ClientPortalFavoriteButton from "@/components/ClientPortalFavoriteButton";
import Link from "next/link";
import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Clock3, Package, Star } from "lucide-react";
import { BoutiqueCardDoProduto, type BoutiqueProduto as BoutiqueProdutoResumo } from "./BoutiqueCardDoProduto";
import type { ProductCombo, SelectedComboData } from "@/components/ProductCombosWidget";
import { useVisaoDaLoja } from "@/components/VisaoDaLojaContext";
import {
  BoutiqueCompra,
  type BoutiqueControleDaCompra,
  type BoutiqueCupomDaPagina,
  type BoutiqueProdutoDaPagina,
} from "./BoutiqueCompra";
import { BoutiqueCompreJunto } from "./BoutiqueCompreJunto";
import { BoutiqueCorteDeProducao } from "./BoutiqueCorteDeProducao";
import { BoutiqueGabarito } from "./BoutiqueGabarito";
import { gabaritosDoProduto } from "@/lib/gabaritos-do-produto";
import type { GrupoDeServicos, ServicoOpcional } from "@/lib/servicos-opcionais";

/*
  A página de produto da Boutique, no desenho da referência
  (.cache/tema-boutique/REFERENCIA.md, 7.1 e 7.2).

  Computador: trilha centralizada; à esquerda a galeria com as miniaturas em
  pé e DUAS fotos 2:3 lado a lado (anda de uma em uma, setas cinza no hover,
  zoom de 1,6× no próprio lugar com um clique); à direita, a coluna de compra
  de 450 px. Embaixo, em largura de container: "Compre junto", a descrição em
  acordeão, "Vídeos do produto", os relacionados em carrossel e as avaliações.

  Celular: a galeria vira um carrossel de largura total com bolinhas e a
  faixa de miniaturas deitada; "Compre junto", "Descrição do produto" e
  "Produtos Relacionados" viram acordeões; a barra de compra fixa (71 px) é
  do card de compra.

  O vídeo do produto é o primeiro item da galeria (miniatura com ▷) e toca no
  lugar da foto.
*/

export type BoutiqueImagem = { id?: string | null; image_url: string; is_primary?: boolean | null };

export type BoutiqueEspecificacao = { rotulo: string; valor: string };

type ItemDaGaleria = { tipo: "video" } | { tipo: "foto"; id: string; url: string };

/* ---------------------------------------------------------------- *
 *  Peças da página
 * ---------------------------------------------------------------- */

/* As estrelas amarelas da referência. */
function Estrelas({ nota, tamanho = 14 }: { nota: number; tamanho?: number }) {
  return (
    <span className="inline-flex items-center gap-0.5" style={{ color: "#f5c518" }} aria-hidden="true">
      {Array.from({ length: 5 }).map((_, i) => {
        const cheia = i + 1 <= Math.round(nota);
        return <Star key={i} size={tamanho} fill={cheia ? "currentColor" : "none"} strokeWidth={1.4} className={cheia ? "" : "text-[#d6d6d6]"} />;
      })}
    </span>
  );
}

/*
  Um bloco da parte de baixo da página. No computador: título centralizado
  18/700 com o risco preto de 30×2 embaixo. No celular: vira acordeão, com
  "–" e "+" à direita, como na referência. Um elemento só para os dois: o
  conteúdo não é montado duas vezes.
*/
function BlocoDoProduto({
  id,
  titulo,
  acordeaoNoCelular = true,
  children,
}: {
  id?: string;
  titulo: string;
  acordeaoNoCelular?: boolean;
  children: ReactNode;
}) {
  const [aberto, setAberto] = useState(true);
  return (
    <section id={id} className="bq-bloco">
      {acordeaoNoCelular ? (
        <button type="button" onClick={() => setAberto((a) => !a)} aria-expanded={aberto} className="bq-bloco-acordeao lg:hidden">
          <span>{titulo}</span>
          <span aria-hidden="true" className="text-[22px] font-light leading-none">
            {aberto ? "–" : "+"}
          </span>
        </button>
      ) : null}
      <h2 className={`bq-bloco-titulo ${acordeaoNoCelular ? "hidden lg:flex" : "flex"}`}>{titulo}</h2>
      <div className={acordeaoNoCelular && !aberto ? "hidden lg:block" : "block"}>{children}</div>
    </section>
  );
}

/* A foto com o zoom da referência: um clique aproxima 1,6× no próprio lugar
   (o ponto do clique fica parado), mexer o mouse passeia, sair desfaz. */
function FotoComZoom({ url, alt }: { url: string; alt: string }) {
  const [zoom, setZoom] = useState(false);
  const [origem, setOrigem] = useState("50% 50%");
  const ondeEsta = (evento: React.MouseEvent<HTMLDivElement>) => {
    const caixa = evento.currentTarget.getBoundingClientRect();
    const x = ((evento.clientX - caixa.left) / caixa.width) * 100;
    const y = ((evento.clientY - caixa.top) / caixa.height) * 100;
    return `${Math.min(100, Math.max(0, x)).toFixed(1)}% ${Math.min(100, Math.max(0, y)).toFixed(1)}%`;
  };
  return (
    <div
      className="relative h-full w-full overflow-hidden bg-white"
      style={{ cursor: zoom ? "zoom-out" : "zoom-in" }}
      onClick={(evento) => {
        setOrigem(ondeEsta(evento));
        setZoom((z) => !z);
      }}
      onMouseMove={(evento) => {
        if (zoom) setOrigem(ondeEsta(evento));
      }}
      onMouseLeave={() => setZoom(false)}
    >
      {/* eslint-disable-next-line @next/next/no-img-element */}
      <img
        src={url}
        alt={alt}
        draggable={false}
        className="h-full w-full select-none object-contain"
        style={{ transform: zoom ? "scale(1.6)" : "none", transformOrigin: origem, transition: "transform 0.3s ease" }}
      />
    </div>
  );
}

/* A miniatura de um item da galeria (foto ou vídeo). */
function Miniatura({ item, capa, ativa, aoEscolher, classe }: { item: ItemDaGaleria; capa: string | null; ativa: boolean; aoEscolher: () => void; classe: string }) {
  const url = item.tipo === "foto" ? item.url : capa;
  return (
    <button
      type="button"
      onClick={aoEscolher}
      aria-label={item.tipo === "video" ? "Vídeo do produto" : "Ver esta foto"}
      aria-current={ativa}
      className={`bq-miniatura relative shrink-0 overflow-hidden bg-white ${classe}`}
      {...(ativa ? { "data-ativa": "" } : {})}
    >
      {url ? (
        /* eslint-disable-next-line @next/next/no-img-element */
        <img src={url} alt="" className="h-full w-full object-cover" />
      ) : null}
      {item.tipo === "video" ? <SeloDePlay /> : null}
    </button>
  );
}

function Galeria({
  itens,
  indice,
  aoMudar,
  video,
  nome,
}: {
  itens: ItemDaGaleria[];
  indice: number;
  aoMudar: (novo: number) => void;
  video: VideoDoProduto | null;
  nome: string;
}) {
  const capa = useMemo(() => {
    const foto = itens.find((item) => item.tipo === "foto");
    return foto && foto.tipo === "foto" ? foto.url : null;
  }, [itens]);
  /* As duas galerias (computador e celular) existem na página, uma escondida
     pelo CSS. O player do vídeo só monta na que está à vista: montado nas
     duas, o vídeo que toca sozinho tocaria duas vezes. Antes de saber, a capa. */
  const [ehComputador, setEhComputador] = useState<boolean | null>(null);
  useEffect(() => {
    const consulta = window.matchMedia("(min-width: 1024px)");
    const ler = () => setEhComputador(consulta.matches);
    ler();
    consulta.addEventListener("change", ler);
    return () => consulta.removeEventListener("change", ler);
  }, []);
  const total = itens.length;
  /* A moldura segue a primeira foto: 2:3 como na referência quando a foto é
     de moda (em pé), quadrada quando a loja fotografa quadrado — sem faixas
     brancas enormes em cima e embaixo. Entre os dois, a proporção da foto. */
  const [proporcao, setProporcao] = useState(2 / 3);
  useEffect(() => {
    if (!capa) return;
    let ativo = true;
    const foto = new window.Image();
    foto.onload = () => {
      if (!ativo || !foto.naturalWidth || !foto.naturalHeight) return;
      setProporcao(Math.min(1, Math.max(2 / 3, foto.naturalWidth / foto.naturalHeight)));
    };
    foto.src = capa;
    return () => {
      ativo = false;
    };
  }, [capa]);
  const moldura = `${proporcao}`;
  /* No computador cabem duas: o trilho começa no item escolhido (o último
     par para no fim, sem buraco branco). */
  const inicio = total >= 2 ? Math.min(Math.max(indice, 0), total - 2) : 0;

  const listaDeMiniaturas = useRef<HTMLDivElement | null>(null);
  useEffect(() => {
    const ativa = listaDeMiniaturas.current?.querySelector<HTMLElement>("[data-ativa]");
    ativa?.scrollIntoView({ block: "nearest", inline: "nearest" });
  }, [indice]);

  /* O carrossel do celular: arrastar troca o item; tocar numa miniatura
     rola até ele. Enquanto o código rola, o arrasto não manda. */
  const trilho = useRef<HTMLDivElement | null>(null);
  const rolandoPorCodigo = useRef(false);
  useEffect(() => {
    const caixa = trilho.current;
    if (!caixa || !caixa.clientWidth) return;
    const alvo = indice * caixa.clientWidth;
    if (Math.abs(caixa.scrollLeft - alvo) < 4) return;
    rolandoPorCodigo.current = true;
    caixa.scrollTo({ left: alvo, behavior: "smooth" });
    const soltar = window.setTimeout(() => {
      rolandoPorCodigo.current = false;
    }, 450);
    return () => window.clearTimeout(soltar);
  }, [indice]);

  const conteudo = (item: ItemDaGaleria, chave: string, noComputador: boolean) =>
    item.tipo === "video" && video ? (
      <div key={chave} className="relative h-full w-full bg-black">
        {ehComputador === noComputador ? (
          <PlayerDaGaleria video={video} capa={capa} nome={nome} sozinho={video.opcoes.galeria.sozinho && !video.flutuante} />
        ) : capa ? (
          <>
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img src={capa} alt="" className="h-full w-full object-cover opacity-90" />
            <SeloDePlay />
          </>
        ) : null}
      </div>
    ) : item.tipo === "foto" ? (
      <FotoComZoom key={chave} url={item.url} alt={nome} />
    ) : null;

  if (!total) {
    return (
      <div className="flex w-full items-center justify-center bg-[#fafafa] text-[12px] uppercase tracking-[0.12em] text-[#666666]" style={{ aspectRatio: "2 / 3", maxHeight: 640 }}>
        Sem imagem
      </div>
    );
  }

  return (
    <>
      {/* ---- computador: miniaturas em pé + duas fotos lado a lado ---- */}
      <div className="hidden gap-[18px] lg:flex">
        <div className="flex w-[96px] shrink-0 flex-col items-center">
          <button type="button" aria-label="Anterior" onClick={() => aoMudar(Math.max(0, indice - 1))} disabled={indice <= 0} className="flex h-9 w-full items-center justify-center text-black disabled:opacity-30">
            <ChevronUp className="h-4 w-4" strokeWidth={1.6} />
          </button>
          <div ref={listaDeMiniaturas} className="bq-sem-barra flex max-h-[560px] w-full flex-col gap-3 overflow-y-auto py-1">
            {itens.map((item, i) => (
              <Miniatura
                key={item.tipo === "foto" ? item.id : "video"}
                item={item}
                capa={capa}
                ativa={i === indice}
                aoEscolher={() => aoMudar(i)}
                classe="h-[94px] w-[96px]"
              />
            ))}
          </div>
          <button type="button" aria-label="Próxima" onClick={() => aoMudar(Math.min(total - 1, indice + 1))} disabled={indice >= total - 1} className="flex h-9 w-full items-center justify-center text-black disabled:opacity-30">
            <ChevronDown className="h-4 w-4" strokeWidth={1.6} />
          </button>
        </div>

        <div className="bq-galeria group/galeria relative min-w-0 flex-1 overflow-hidden">
          <div
            className={`flex gap-[18px] ${total >= 2 ? "" : "justify-center"}`}
            style={{
              transform: `translateX(calc(${-inicio} * (50% + 9px)))`,
              transition: "transform 0.3s ease",
            }}
          >
            {itens.map((item) => (
              <div key={item.tipo === "foto" ? item.id : "video"} className="w-[calc(50%-9px)] shrink-0">
                <div className="w-full" style={{ aspectRatio: moldura }}>
                  {conteudo(item, `g-${item.tipo === "foto" ? item.id : "video"}`, true)}
                </div>
              </div>
            ))}
          </div>
          {total > 2 ? (
            <>
              <button type="button" aria-label="Foto anterior" onClick={() => aoMudar(Math.max(0, inicio - 1))} disabled={inicio <= 0} className="bq-seta-galeria left-0">
                <ChevronLeft className="h-5 w-5" strokeWidth={1.5} />
              </button>
              <button type="button" aria-label="Próxima foto" onClick={() => aoMudar(Math.min(total - 1, inicio + 2))} disabled={inicio >= total - 2} className="bq-seta-galeria right-0">
                <ChevronRight className="h-5 w-5" strokeWidth={1.5} />
              </button>
            </>
          ) : null}
        </div>
      </div>

      {/* ---- celular: carrossel de largura total, bolinhas, miniaturas deitadas ---- */}
      <div className="lg:hidden">
        <div className="relative">
          <div
            ref={trilho}
            className="bq-sem-barra flex snap-x snap-mandatory overflow-x-auto"
            onScroll={(evento) => {
              if (rolandoPorCodigo.current) return;
              const caixa = evento.currentTarget;
              if (!caixa.clientWidth) return;
              const novo = Math.round(caixa.scrollLeft / caixa.clientWidth);
              if (novo !== indice && novo >= 0 && novo < total) aoMudar(novo);
            }}
          >
            {itens.map((item, i) => (
              <div key={item.tipo === "foto" ? item.id : "video"} className="w-full shrink-0 snap-center" style={{ aspectRatio: moldura }}>
                {item.tipo === "foto" ? (
                  /* eslint-disable-next-line @next/next/no-img-element */
                  <img src={item.url} alt={nome} className="h-full w-full bg-white object-contain" loading={i === 0 ? "eager" : "lazy"} />
                ) : (
                  conteudo(item, `c-${i}`, false)
                )}
              </div>
            ))}
          </div>
          {total > 1 ? (
            <>
              <button type="button" aria-label="Foto anterior" onClick={() => aoMudar(Math.max(0, indice - 1))} className="bq-seta-celular left-0">
                <ChevronLeft className="h-5 w-5" strokeWidth={1.5} />
              </button>
              <button type="button" aria-label="Próxima foto" onClick={() => aoMudar(Math.min(total - 1, indice + 1))} className="bq-seta-celular right-0">
                <ChevronRight className="h-5 w-5" strokeWidth={1.5} />
              </button>
            </>
          ) : null}
        </div>
        {total > 1 ? (
          <div className="flex flex-wrap justify-center gap-[7px] py-3" aria-hidden="true">
            {itens.map((item, i) => (
              <span key={item.tipo === "foto" ? item.id : "video"} className="h-2 w-2 rounded-full" style={{ backgroundColor: i === indice ? "#000000" : "#d1d1d1" }} />
            ))}
          </div>
        ) : null}
        {total > 1 ? (
          <div className="flex items-center gap-1 px-[10px]">
            <button type="button" aria-label="Anterior" onClick={() => aoMudar(Math.max(0, indice - 1))} className="flex h-8 w-5 shrink-0 items-center justify-center text-[#99a3ad]">
              <ChevronLeft className="h-4 w-4" />
            </button>
            <div className="bq-sem-barra flex min-w-0 flex-1 gap-2 overflow-x-auto">
              {itens.map((item, i) => (
                <Miniatura
                  key={item.tipo === "foto" ? item.id : "video"}
                  item={item}
                  capa={capa}
                  ativa={i === indice}
                  aoEscolher={() => aoMudar(i)}
                  classe="h-[84px] w-[98px]"
                />
              ))}
            </div>
            <button type="button" aria-label="Próxima" onClick={() => aoMudar(Math.min(total - 1, indice + 1))} className="flex h-8 w-5 shrink-0 items-center justify-center text-[#99a3ad]">
              <ChevronRight className="h-4 w-4" />
            </button>
          </div>
        ) : null}
      </div>
    </>
  );
}

/* Os relacionados em carrossel: 4 por vez no computador (setas cinza fora da
   grade), 2 no celular, arrastando. */
function Relacionados({
  produtos,
  slug,
  clienteId,
  favoritos,
  corDaMarca,
}: {
  produtos: BoutiqueProdutoResumo[];
  slug: string;
  clienteId?: string | null;
  favoritos?: string[] | null;
  corDaMarca: string;
}) {
  const trilho = useRef<HTMLDivElement | null>(null);
  const [ponta, setPonta] = useState({ inicio: true, fim: false });
  const medir = useCallback(() => {
    const caixa = trilho.current;
    if (!caixa) return;
    setPonta({ inicio: caixa.scrollLeft <= 2, fim: caixa.scrollLeft + caixa.clientWidth >= caixa.scrollWidth - 2 });
  }, []);
  useEffect(() => {
    medir();
    window.addEventListener("resize", medir);
    return () => window.removeEventListener("resize", medir);
  }, [medir, produtos.length]);
  const andar = (direcao: 1 | -1) => {
    const caixa = trilho.current;
    const card = caixa?.querySelector<HTMLElement>("[data-bq-slide]");
    if (!caixa || !card) return;
    caixa.scrollBy({ left: direcao * (card.offsetWidth + 16), behavior: "smooth" });
  };
  return (
    <div className="relative">
      <div ref={trilho} onScroll={medir} className="bq-sem-barra flex snap-x snap-mandatory gap-2 overflow-x-auto lg:gap-4">
        {produtos.slice(0, 12).map((item) => (
          <div key={item.id} data-bq-slide="" className="w-[calc((100%-8px)/2)] shrink-0 snap-start lg:w-[calc((100%-48px)/4)]">
            <BoutiqueCardDoProduto
              produto={item}
              slug={slug}
              clienteId={clienteId}
              favoritos={favoritos}
              corDaMarca={corDaMarca}
              variante="relacionado"
            />
          </div>
        ))}
      </div>
      {produtos.length > 2 ? (
        <>
          <button type="button" aria-label="Anteriores" onClick={() => andar(-1)} disabled={ponta.inicio} className="bq-seta-relacionados left-0 lg:-left-[58px]">
            <ChevronLeft className="h-5 w-5" strokeWidth={1.5} />
          </button>
          <button type="button" aria-label="Próximos" onClick={() => andar(1)} disabled={ponta.fim} className="bq-seta-relacionados right-0 lg:-right-[58px]">
            <ChevronRight className="h-5 w-5" strokeWidth={1.5} />
          </button>
        </>
      ) : null}
    </div>
  );
}

/* ---------------------------------------------------------------- *
 *  A página
 * ---------------------------------------------------------------- */

export function BoutiqueProduto({
  slug,
  produto,
  imagens,
  categoriaNome,
  categoriaSlug,
  descricaoHtml,
  prazoTexto,
  previsaoTexto,
  horaDoCorte,
  especificacoes,
  relacionados,
  corDaMarca,
  gruposDeServico,
  servicosDoProduto,
  combos,
  clienteId,
  favoritos,
  notaMedia,
  quantasAvaliacoes,
  selos,
  avaliacoes,
  whatsapp,
  video = null,
  cupomDoAviso = null,
}: {
  slug: string;
  produto: BoutiqueProdutoDaPagina;
  imagens: BoutiqueImagem[];
  categoriaNome?: string | null;
  categoriaSlug?: string | null;
  descricaoHtml?: string | null;
  prazoTexto?: string | null;
  previsaoTexto?: string | null;
  /* A hora limite para o pedido entrar na produção do dia. */
  horaDoCorte?: string | null;
  especificacoes: BoutiqueEspecificacao[];
  relacionados: BoutiqueProdutoResumo[];
  corDaMarca: string;
  gruposDeServico?: GrupoDeServicos[];
  servicosDoProduto?: ServicoOpcional[];
  /* Os produtos que a loja sugere levar junto ("Compre junto"). */
  combos?: ProductCombo[];
  /* Quem está logado no portal, para o coração de favorito. */
  clienteId?: string | null;
  favoritos?: string[] | null;
  /* A nota do produto, mostrada acima do nome. */
  notaMedia?: number | null;
  quantasAvaliacoes?: number | null;
  /* Os selos de confiança do catálogo. */
  selos?: Array<{ icon?: string | null; title?: string | null }> | null;
  /* As avaliações chegam prontas do servidor. */
  avaliacoes?: React.ReactNode;
  /* O WhatsApp da loja, para o pedido pelo WhatsApp e a dúvida do sob consulta. */
  whatsapp?: string | null;
  /* O vídeo do produto (migration 183): o primeiro item da galeria. */
  video?: VideoDoProduto | null;
  /* O cupom da faixa de aviso, repetido na caixa de cupom da compra. */
  cupomDoAviso?: BoutiqueCupomDaPagina | null;
}) {
  const rota = useRouter();
  /* As regras da loja: o prazo de produção só aparece quando a loja deixa. */
  const visao = useVisaoDaLoja();
  const prazo = visao.regras.mostrarPrazo ? prazoTexto : null;
  const previsao = visao.regras.mostrarPrazo ? previsaoTexto : null;
  const galeria = useMemo(() => {
    const lista = (imagens || []).filter((imagem) => imagem?.image_url);
    if (!lista.length) return [];
    const principal = lista.find((imagem) => imagem.is_primary);
    return principal ? [principal, ...lista.filter((imagem) => imagem !== principal)] : lista;
  }, [imagens]);

  /* O vídeo é o primeiro item da galeria; depois, as fotos. */
  const itens = useMemo<ItemDaGaleria[]>(
    () => [
      ...(video ? [{ tipo: "video" as const }] : []),
      ...galeria.map((imagem, i) => ({ tipo: "foto" as const, id: String(imagem.id || `foto-${i}`), url: imagem.image_url })),
    ],
    [video, galeria]
  );
  const [indice, setIndice] = useState(0);
  const gabaritos = useMemo(() => gabaritosDoProduto(produto), [produto]);

  /* A opção escolhida no card de compra manda na galeria: se ela tem foto
     própria, é essa que aparece. */
  const seguirImagemDaOpcao = useCallback(
    (idDaImagem: string | null) => {
      if (!idDaImagem) return;
      const posicao = itens.findIndex((item) => item.tipo === "foto" && item.id === idDaImagem);
      if (posicao >= 0) setIndice(posicao);
    },
    [itens]
  );

  /* "Compre junto" mora embaixo, mas quem soma e manda para o carrinho é o
     card de compra: a escolha sobe para cá e desce para ele. */
  const [combosEscolhidos, setCombosEscolhidos] = useState<SelectedComboData[]>([]);
  const controle = useRef<BoutiqueControleDaCompra | null>(null);

  const temAvaliacoes = Number(quantasAvaliacoes) > 0 && visao.regras.avaliacoes;

  const prazoECorte =
    prazo || previsao || (horaDoCorte && visao.regras.mostrarPrazo) ? (
      <div className="space-y-2">
        {prazo || previsao ? (
          <div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-[12px] text-[#4b4f58]">
            {prazo ? (
              <span className="inline-flex items-center gap-1.5">
                <Clock3 className="h-4 w-4 shrink-0" strokeWidth={1.5} />
                Prazo de produção: <strong className="text-black">{prazo}</strong>
              </span>
            ) : null}
            {previsao ? (
              <span className="inline-flex items-center gap-1.5">
                <Package className="h-4 w-4 shrink-0" strokeWidth={1.5} />
                Previsão: <strong className="tabular-nums text-black">{previsao}</strong>
              </span>
            ) : null}
          </div>
        ) : null}
        {/* A contagem "entra em produção hoje" é prazo: some junto com a regra. */}
        {horaDoCorte && visao.regras.mostrarPrazo ? <BoutiqueCorteDeProducao horaLimite={horaDoCorte} /> : null}
      </div>
    ) : null;

  return (
    <main className="bq-produto pb-[96px] lg:pb-10">
      {/* A trilha, centralizada. */}
      <nav aria-label="Trilha" className="mx-auto flex max-w-[1240px] flex-wrap items-center justify-center gap-x-1.5 px-4 pb-6 pt-4 text-center text-[12px] text-[#99a3ad] lg:pb-10 max-lg:pb-3">
        <Link href={`/${slug}`} className="hover:text-black">
          Home
        </Link>
        {categoriaNome ? (
          <>
            <span aria-hidden="true">&gt;</span>
            <Link href={categoriaSlug ? `/${slug}/c/${categoriaSlug}` : `/${slug}`} className="hover:text-black">
              {categoriaNome}
            </Link>
          </>
        ) : null}
        <span aria-hidden="true">&gt;</span>
        <span className="text-[#6c7484]">{produto.name}</span>
      </nav>

      <div className="mx-auto w-full max-w-[1600px] lg:grid lg:grid-cols-[minmax(0,1fr)_450px] lg:items-start lg:gap-5 lg:px-[10px]">
        {/* ------------ galeria ------------ */}
        <div className="min-w-0 lg:sticky" style={{ top: "calc(var(--bq-header-h, 137px) + 16px)" }}>
          <Galeria itens={itens} indice={indice} aoMudar={setIndice} video={video} nome={produto.name} />
        </div>

        {/* ------------ compra ------------ */}
        <div className="min-w-0 px-[10px] pt-5 lg:px-0 lg:pt-0">
          {temAvaliacoes ? (
            <a href="#avaliacoes" className="mb-1.5 inline-flex items-center gap-2 text-[12px] text-[#666666] hover:underline">
              <Estrelas nota={Number(notaMedia) || 0} />
              Ver {quantasAvaliacoes} {Number(quantasAvaliacoes) === 1 ? "avaliação" : "avaliações"}
            </a>
          ) : null}
          <div className="flex items-start justify-between gap-3">
            <h1 className="min-w-0 text-[18px] font-normal leading-[27px] text-black">{produto.name}</h1>
            {/* Guardar para depois: o coração fica ao lado do nome. */}
            <span className="bq-coracao relative -mr-1 shrink-0">
              <ClientPortalFavoriteButton
                productId={produto.id}
                clientId={clienteId || null}
                initialFavorites={favoritos || null}
                primaryColor="#111111"
                onRequireLogin={() => rota.push(`/${slug}/cliente/login`)}
              />
            </span>
          </div>

          <div className="mt-2">
            <BoutiqueCompra
              produto={produto}
              slug={slug}
              corDaMarca={corDaMarca}
              gruposDeServico={gruposDeServico}
              servicosDoProduto={servicosDoProduto}
              combosEscolhidos={combosEscolhidos}
              aoPreferirImagem={seguirImagemDaOpcao}
              selos={selos}
              whatsapp={whatsapp}
              controleRef={controle}
              fotoPrincipal={galeria[0]?.image_url || null}
              cupomDoAviso={cupomDoAviso}
              ofertaFlutuante={!(video && video.flutuante)}
              antesDoBotao={
                gabaritos.length || prazoECorte ? (
                  <div className="space-y-4">
                    {/* O gabarito é a "Tabela de medidas" de quem imprime:
                        fica no mesmo lugar, logo acima do botão. */}
                    <BoutiqueGabarito gabaritos={gabaritos} />
                    {prazoECorte}
                  </div>
                ) : null
              }
            />
          </div>
        </div>
      </div>

      {/* ------------ a parte de baixo, em largura de container ------------ */}
      <div className="mx-auto mt-10 w-full max-w-[1240px] space-y-2 px-[10px] lg:mt-16 lg:space-y-16 lg:px-[10px]">
        {combos?.length ? (
          <BlocoDoProduto titulo="Compre junto">
            <BoutiqueCompreJunto
              combos={combos}
              slug={slug}
              corDaMarca={corDaMarca}
              aoEscolher={setCombosEscolhidos}
              principal={{ nome: produto.name, foto: galeria[0]?.image_url || null }}
              aoComprar={() => controle.current?.adicionar()}
            />
          </BlocoDoProduto>
        ) : null}

        {descricaoHtml || especificacoes.length ? (
          <BlocoDoProduto id="bq-descricao" titulo="Descrição do produto">
            <div className="bq-acordeao">
              {descricaoHtml ? (
                <details open>
                  <summary>Descrição</summary>
                  <div className="bq-descricao-texto" dangerouslySetInnerHTML={{ __html: descricaoHtml }} />
                </details>
              ) : null}
              {especificacoes.length ? (
                <details open={!descricaoHtml}>
                  <summary>Características</summary>
                  <dl className="bq-caracteristicas">
                    {especificacoes.map((linha) => (
                      <div key={linha.rotulo}>
                        <dt>{linha.rotulo}</dt>
                        <dd>{linha.valor}</dd>
                      </div>
                    ))}
                  </dl>
                </details>
              ) : null}
            </div>
          </BlocoDoProduto>
        ) : (
          <span id="bq-descricao" />
        )}

        {video ? (
          <BlocoDoProduto titulo="Vídeos do produto" acordeaoNoCelular={false}>
            <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:gap-8">
              <div className="flex gap-3 lg:w-[180px] lg:flex-col">
                <span className="relative block h-[98px] w-[180px] shrink-0 overflow-hidden border-2 border-black bg-white">
                  {galeria[0] ? (
                    /* eslint-disable-next-line @next/next/no-img-element */
                    <img src={galeria[0].image_url} alt="" className="h-full w-full object-contain" />
                  ) : null}
                  <SeloDePlay />
                </span>
              </div>
              <div className="min-w-0 flex-1 bg-black" style={{ aspectRatio: "16 / 9" }}>
                <PlayerDaGaleria video={video} capa={galeria[0]?.image_url ?? null} nome={produto.name} />
              </div>
            </div>
          </BlocoDoProduto>
        ) : null}

        {relacionados.length ? (
          <BlocoDoProduto titulo="Produtos Relacionados">
            <div className="lg:px-[48px]">
              <Relacionados produtos={relacionados} slug={slug} clienteId={clienteId} favoritos={favoritos} corDaMarca={corDaMarca} />
            </div>
          </BlocoDoProduto>
        ) : null}

        {avaliacoes ? (
          <section id="avaliacoes" className="bq-avaliacoes pt-6 lg:pt-0">
            {avaliacoes}
          </section>
        ) : null}
      </div>
    </main>
  );
}
