"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { ChevronDown, CreditCard, LogIn, Minus, Plus, Send, ShoppingBag, Sparkles, Tag, Trash2, Truck, X } from "lucide-react";
import { useCart } from "@/context/CartContext";
import { BoutiqueValorMinimo } from "./BoutiqueValorMinimo";
import { useVisaoDaLoja } from "@/components/VisaoDaLojaContext";
import { faltaParaOPedidoMinimo } from "@/lib/loja/regras-da-loja";
import { normalizeWhatsappForLink } from "@/lib/phone";
import { trackCatalogEvent } from "@/lib/catalog-analytics";
import { isPickupShippingOption } from "@/lib/catalog-shipping";
import { moedaDaBoutique, numeroDaBoutique } from "./formato";
import { getReadableTextColor, normalizeHexColor } from "@/lib/color-contrast";

/*
  O carrinho da Boutique, no desenho da referência: no computador, gaveta da
  direita de 430 px com o cabeçalho preto "MEU CARRINHO"; no celular, folha
  de tela inteira com o cabeçalho preto "Meu carrinho" e a seta que fecha.
  Itens em linhas (foto, nome em caixa alta, opções, medidas, quantidade e
  valor), cupom, totais e o botão preto. O carrinho dos outros templates
  continua onde está, intocado.

  A conta, o cupom e o frete vêm do contexto do carrinho — os mesmos números
  que o checkout vai cobrar. Aqui só se decide como isso aparece.

  O fechamento obedece às regras da loja (lib/loja/regras-da-loja.ts):
  entrar antes de fechar, loja em pausa, lista de orçamento ou carrinho comum.
  O pedido sem pagamento online nasce no servidor (/api/catalog/pedido), que
  precifica pelo banco, confere cupom, estoque e frete e avisa a loja. Antes
  o navegador gravava o pedido direto, com os preços que ele mesmo mandava.
*/

/* O símbolo do WhatsApp, usado nos botões que levam à conversa. */
function IconeDoWhats() {
  return (
    <svg viewBox="0 0 24 24" className="h-4 w-4" fill="currentColor" aria-hidden="true">
      <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z" />
    </svg>
  );
}

/* O campo de texto do painel (pedido de orçamento): borda fina, sem raio. */
const CLASSE_DO_CAMPO = "bq-campo text-[13px]";

function Linha({ rotulo, valor, forte }: { rotulo: string; valor: string; forte?: boolean }) {
  return (
    <div className="flex items-center justify-between gap-3">
      <span className={forte ? "text-[15px] font-bold text-black" : "text-[13px] text-[#666666]"}>{rotulo}</span>
      <span className={forte ? "text-[20px] font-bold tabular-nums text-black" : "text-[13px] tabular-nums text-[#252525]"}>{valor}</span>
    </div>
  );
}

/* Num produto por m², o preço guardado no carrinho é o do METRO: o valor da
   linha só fecha multiplicando pela área de cada peça. Sem isso a linha
   mostrava um número e o total do carrinho cobrava outro. */
function areaDaPeca(item: { unit_type?: string | null; width_m?: number | null; height_m?: number | null }) {
  if (item.unit_type !== "square_meter") return 0;
  const l = Number(item.width_m) || 0;
  const a = Number(item.height_m) || 0;
  return l > 0 && a > 0 ? l * a : 0;
}

function valorDaLinha(item: {
  price: number;
  quantity: number;
  unit_type?: string | null;
  width_m?: number | null;
  height_m?: number | null;
  valor_minimo_aplicado?: number | null;
}) {
  /* Valor mínimo do item: a linha inteira vale o mínimo. */
  if (item.valor_minimo_aplicado != null && item.valor_minimo_aplicado > 0) return item.valor_minimo_aplicado;
  const area = areaDaPeca(item);
  return item.price * item.quantity * (area > 0 ? area : 1);
}

export function BoutiqueCarrinho({
  slug,
  whatsapp,
  corDaLoja,
}: {
  slug: string;
  whatsapp?: string | null;
  /* A cor principal da loja (Personalização). O carrinho é montado pelo
     StoreLayout, fora do shell onde moram as cores do lojista: sem esta
     prop o cabeçalho e os botões ficavam pretos em qualquer loja. */
  corDaLoja?: string | null;
}) {
  const router = useRouter();
  /* O que este visitante pode ver e fazer (regras da loja). */
  const visao = useVisaoDaLoja();
  const comPreco = visao.mostrarPreco;
  const modoOrcamento = visao.modoDeCompra === "quote";
  const modoCarrinho = visao.modoDeCompra === "cart";
  const textoSemPreco = visao.textoNoLugarDoPreco;
  /* Preço só para quem entrou, ou cadastro exigido para fechar: o botão de
     fechar leva ao login, e o pedido vem depois. */
  const precisaEntrarParaFechar = visao.precisaEntrar || (visao.exigeLoginParaFechar && !visao.cliente);
  /* "Meu Carrinho" é o nome de sempre deste painel; no pedido de orçamento
     ele vira a lista, com o nome que as regras dão. */
  const titulo = modoOrcamento ? visao.tituloDoCarrinho : "Meu Carrinho";
  const {
    items,
    isCartOpen,
    toggleCart,
    removeFromCart,
    updateQuantity,
    clearCart,
    applyCoupon,
    clearCoupon,
    appliedCoupons,
    removeCoupon,
    orderCouponCodes,
    couponNotices,
    availableCoupons,
    cartSubtotal,
    discountTotal,
    shippingDiscount,
    cartTotal,
    shippingTotal,
    shippingSelection,
    avisosDeEstoque,
  } = useCart();
  /* O pedido mínimo da loja (em reais ou em unidades), conferido aqui e de
     novo no servidor. */
  const faltaMinimo = faltaParaOPedidoMinimo(visao.regras, {
    total: cartSubtotal,
    unidades: items.filter((i) => !i.is_combo_item).reduce((soma, i) => soma + Number(i.quantity || 0), 0),
    mostrarPreco: visao.mostrarPreco,
  });

  /* Se a loja aceita pagamento online. Enquanto não se sabe, o WhatsApp fica
     escondido: mostrar e sumir é pior do que aparecer um instante depois. */
  const [temPagamento, setTemPagamento] = useState<boolean | null>(null);
  const [cupom, setCupom] = useState("");
  const [avisoDoCupom, setAvisoDoCupom] = useState<{ ok: boolean; texto: string } | null>(null);
  const [aplicando, setAplicando] = useState(false);
  const [aviso, setAviso] = useState("");
  const [enviando, setEnviando] = useState(false);
  /* O que deu errado no fechamento, mostrado junto do botão. */
  const [erro, setErro] = useState("");
  /* O pedido de orçamento enviado: o carrinho esvazia e a confirmação fica
     no lugar da lista até o painel fechar. */
  const [sucesso, setSucesso] = useState("");
  /* O pedido já nasceu na loja, mas o navegador barrou a janela do
     WhatsApp: o link fica à mão, para não registrar o pedido duas vezes. */
  const [linkPendente, setLinkPendente] = useState("");
  /* Quem pede, quando não há cadastro: o pedido de orçamento precisa de um
     nome e um contato para a loja responder. */
  const [contato, setContato] = useState({ nome: "", whatsapp: "", email: "", observacoes: "" });
  /* Há item "sob consulta" com preço visível: o total é parcial. */
  const temSobConsulta = items.some((item) => item.price_on_request);

  /* Fechar o painel por dentro (X, fundo, Esc, link): as mensagens do
     fechamento anterior não devem reaparecer na próxima abertura. */
  const fecharPainel = useCallback(() => {
    setSucesso("");
    setErro("");
    setLinkPendente("");
    toggleCart();
  }, [toggleCart]);

  /* Com o painel aberto, a página de trás não pode rolar junto. */
  useEffect(() => {
    if (!isCartOpen) return;
    const antes = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      document.body.style.overflow = antes;
    };
  }, [isCartOpen]);

  /* Perguntado só quando o carrinho abre, e uma vez por visita. Fora do
     carrinho comum não há pagamento a perguntar. */
  useEffect(() => {
    if (!isCartOpen || temPagamento !== null || !slug || !modoCarrinho) return;
    let ativo = true;
    fetch(`/api/catalog/payment/ativo?slug=${encodeURIComponent(slug)}`)
      .then((r) => (r.ok ? r.json() : { ativo: false }))
      .then((j) => {
        if (ativo) setTemPagamento(Boolean(j?.ativo));
      })
      .catch(() => {
        if (ativo) setTemPagamento(false);
      });
    return () => {
      ativo = false;
    };
  }, [isCartOpen, temPagamento, slug, modoCarrinho]);

  useEffect(() => {
    if (!isCartOpen) return;
    const comEsc = (evento: KeyboardEvent) => {
      if (evento.key === "Escape") fecharPainel();
    };
    document.addEventListener("keydown", comEsc);
    return () => document.removeEventListener("keydown", comEsc);
  }, [isCartOpen, fecharPainel]);

  const digitosDoWhats = useMemo(() => normalizeWhatsappForLink(whatsapp), [whatsapp]);

  /* O mesmo pedido, em texto, para o modo "pedir pelo WhatsApp", em que a
     conversa é o pedido e nada é registrado na loja. Sem preço na tela, a
     mensagem também sai sem valor. */
  const mensagemDoWhats = useMemo(() => {
    if (!items.length) return "";
    const linhas = items.map((item) => {
      const detalhe = item.variation_description ? ` (${item.variation_description})` : "";
      const area = areaDaPeca(item);
      const medida =
        area > 0
          ? ` (${numeroDaBoutique(Number(item.width_m) || 0, 2)}m x ${numeroDaBoutique(Number(item.height_m) || 0, 2)}m = ${numeroDaBoutique(area, 2)}m²)`
          : "";
      const valor = comPreco && !item.price_on_request ? ` — ${moedaDaBoutique(valorDaLinha(item))}` : "";
      return `• ${item.quantity}x ${item.name}${medida}${detalhe}${valor}`;
    });
    const total = comPreco ? `\n\nTotal: ${moedaDaBoutique(cartTotal)}` : "";
    return encodeURIComponent(`Olá! Quero fazer este pedido:\n\n${linhas.join("\n")}${total}`);
  }, [items, cartTotal, comPreco]);

  /* Os itens como o servidor os lê (lib/pedido-da-loja.server.ts). O preço
     vai só de pista: quem precifica é o banco. */
  const itensParaOServidor = () =>
    items.map((item) => ({
      product_id: item.product_id,
      name: item.name,
      price: Number(item.price || 0),
      quantity: Number(item.quantity || 0),
      unit_type: item.unit_type || "unit",
      width_m: item.width_m ?? 0,
      height_m: item.height_m ?? 0,
      length_m: item.length_m ?? 0,
      shipping_weight_kg: item.shipping_weight_kg ?? 0,
      shipping_width_cm: item.shipping_width_cm ?? 0,
      shipping_height_cm: item.shipping_height_cm ?? 0,
      shipping_length_cm: item.shipping_length_cm ?? 0,
      variation_description: item.variation_description || "",
      selected_options: item.selected_options || null,
      price_on_request: Boolean(item.price_on_request),
      is_combo_item: Boolean(item.is_combo_item),
      combo_parent_id: item.combo_parent_id || null,
    }));

  /* O pedido nasce no servidor: é lá que o preço vem do banco, o cupom é
     conferido, o frete é validado e a loja é avisada. */
  async function enviarPedido(modo: "whatsapp" | "orcamento") {
    try {
      const resposta = await fetch("/api/catalog/pedido", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          slug,
          modo,
          items: itensParaOServidor(),
          couponCodes: orderCouponCodes,
          shippingSelection: modo === "whatsapp" ? shippingSelection : null,
          clearAfterOpen: true,
          customer: { name: contato.nome, whatsapp: contato.whatsapp, email: contato.email, notes: contato.observacoes },
        }),
      });
      const dados = (await resposta.json().catch(() => null)) as
        | { ok?: boolean; order_number?: number | null; whatsapp_url?: string | null; error?: string }
        | null;
      if (!resposta.ok || !dados?.ok) {
        return { ok: false as const, mensagem: dados?.error || "Não foi possível registrar o pedido." };
      }
      return { ok: true as const, numero: dados.order_number ?? null, whatsappUrl: dados.whatsapp_url || "" };
    } catch {
      return { ok: false as const, mensagem: "Não foi possível registrar o pedido. Tente de novo em instantes." };
    }
  }

  /* Fechar pelo WhatsApp não é só abrir a conversa: o pedido tem de nascer na
     loja, senão ele existe apenas no celular de quem atende. O servidor grava
     e devolve o endereço da conversa já com o número do pedido. */
  async function enviarPeloWhats() {
    if (enviando || !digitosDoWhats) return;
    setEnviando(true);
    setErro("");
    setLinkPendente("");

    void trackCatalogEvent({
      slug,
      eventName: "checkout_started",
      meta: { items_count: items.length, cart_total: Number(cartTotal.toFixed(2)) },
    });

    const resultado = await enviarPedido("whatsapp");
    if (!resultado.ok) {
      setEnviando(false);
      setErro(resultado.mensagem);
      return;
    }

    void trackCatalogEvent({
      slug,
      eventName: "order_created",
      meta: { items_count: items.length, cart_total: Number(cartTotal.toFixed(2)) },
    });

    const endereco = resultado.whatsappUrl || `https://wa.me/${digitosDoWhats}?text=${mensagemDoWhats}`;
    const janela = window.open(endereco, "_blank");
    if (!janela) {
      setEnviando(false);
      setErro("O navegador bloqueou a janela do WhatsApp. O pedido já foi registrado: abra a conversa pelo botão abaixo.");
      setLinkPendente(endereco);
      return;
    }

    clearCoupon();
    clearCart();
    setEnviando(false);
    if (isCartOpen) toggleCart();
  }

  /* O pedido de orçamento: a lista vai para a loja (sem valor nenhum quando
     o visitante não vê preço); a loja recebe com os preços do cadastro e
     responde. */
  async function enviarPedidoDeOrcamento() {
    if (enviando) return;
    if (!visao.cliente) {
      if (!contato.nome.trim()) {
        setErro("Diga o seu nome para a loja responder.");
        return;
      }
      if (!contato.whatsapp.trim() && !contato.email.trim()) {
        setErro("Informe um WhatsApp ou e-mail para a loja responder.");
        return;
      }
    }
    setEnviando(true);
    setErro("");
    void trackCatalogEvent({ slug, eventName: "checkout_started", meta: { items_count: items.length, quote_request: true } });

    const resultado = await enviarPedido("orcamento");
    setEnviando(false);
    if (!resultado.ok) {
      setErro(resultado.mensagem);
      return;
    }
    void trackCatalogEvent({ slug, eventName: "order_created", meta: { items_count: items.length, quote_request: true } });

    clearCoupon();
    clearCart();
    setSucesso(`Pedido de orçamento${resultado.numero ? ` nº ${resultado.numero}` : ""} enviado! A loja vai responder em breve.`);
    if (resultado.whatsappUrl) window.open(resultado.whatsappUrl, "_blank");
  }

  /* O botão de fechar leva ao login e traz de volta para esta página. */
  function irParaOLogin() {
    if (isCartOpen) fecharPainel();
    router.push(`/${slug}/cliente/login?next=${encodeURIComponent(window.location.pathname)}`);
  }

  /* O pedido já existe na loja; a conversa abriu pelo link de reserva. */
  function concluirPeloLinkPendente() {
    setLinkPendente("");
    setErro("");
    clearCoupon();
    clearCart();
    if (isCartOpen) toggleCart();
  }

  async function usarCupom(digitado?: string) {
    const codigo = (digitado ?? cupom).trim();
    if (!codigo) return;
    setAplicando(true);
    const resposta = await applyCoupon(codigo);
    setAplicando(false);
    setAvisoDoCupom({ ok: resposta.ok, texto: resposta.message });
    if (resposta.ok) setCupom("");
  }

  if (!isCartOpen) return null;

  const quantosItens = items.filter((i) => !i.is_combo_item).length;
  /* As cores de ação do carrinho (cabeçalho, Aplicar, Seguir para pagamento)
     pela cor da loja; o texto é escolhido pelo contraste para nunca sumir. */
  const cor = String(corDaLoja || "").trim() ? normalizeHexColor(corDaLoja, "#000000") : null;
  const coresDoCarrinho = cor
    ? ({
        "--bq-primary": cor,
        "--bq-primary-fg": getReadableTextColor(cor),
        "--bq-primary-hover": `color-mix(in srgb, ${cor} 85%, #000000)`,
      } as React.CSSProperties)
    : undefined;

  return (
    /* Acima do chat: com o balão da loja por cima, o botão de pagar ficava
       coberto na hora de fechar a compra. */
    <div className="fixed inset-0 z-[85]">
      <div className="bq-carrinho-fundo absolute inset-0 bg-black/40" onClick={fecharPainel} role="presentation" />

      {/* Computador: gaveta da direita de 430 px, altura total. Celular: folha
          de tela inteira, com o cabeçalho preto "Meu carrinho" e a seta para
          baixo que fecha (REFERENCIA.md 4.2/4.3). */}
      <aside
        className="bq-carrinho-painel absolute inset-x-0 bottom-0 top-[24px] flex flex-col overflow-hidden rounded-t-[8px] bg-white lg:inset-y-0 lg:left-auto lg:right-0 lg:top-0 lg:w-[430px] lg:rounded-none"
        role="dialog"
        aria-label="Meu carrinho"
        style={coresDoCarrinho}
      >
        <header
          className="flex h-[56px] shrink-0 items-center justify-between px-5 lg:h-[64px]"
          style={{ backgroundColor: "var(--bq-primary)", color: "var(--bq-primary-fg)" }}
        >
          <h2 className="text-[17px] font-normal lg:text-[14px] lg:font-bold lg:uppercase lg:tracking-[0.08em]">
            {modoOrcamento ? titulo : "Meu carrinho"}
          </h2>
          <button type="button" onClick={fecharPainel} aria-label="Fechar carrinho" className="-mr-1 p-1 text-current">
            <ChevronDown className="h-6 w-6 lg:hidden" strokeWidth={1.4} />
            <X className="hidden h-5 w-5 lg:block" strokeWidth={1.6} />
          </button>
        </header>

        {items.length ? (
          <div className="flex shrink-0 items-center justify-between border-b px-5 py-2.5 text-[12px] text-[#666666]" style={{ borderColor: "#efefef" }}>
            <span>
              {quantosItens} {quantosItens === 1 ? "item" : "itens"}
            </span>
            <span className="flex items-center gap-4">
              <Link href={`/${slug}/cliente`} onClick={fecharPainel} className="inline-flex items-center gap-1 hover:text-black">
                <ShoppingBag className="h-3.5 w-3.5" strokeWidth={1.6} />
                Meus pedidos
              </Link>
              <button type="button" onClick={() => clearCart()} className="underline underline-offset-2 hover:text-black">
                Limpar
              </button>
            </span>
          </div>
        ) : null}

        <div className="min-h-0 flex-1 overflow-y-auto px-5">
          {!items.length ? (
            <div className="flex h-full flex-col items-center justify-center gap-5 py-10 text-center">
              <CarrinhoVazio />
              {sucesso ? (
                <p className="max-w-[280px] text-[14px] font-semibold text-[#252525]" role="status">
                  {sucesso}
                </p>
              ) : (
                <>
                  <p className="text-[16px] text-[#6c7484]">{modoOrcamento ? "Sua lista está vazia" : "Seu carrinho está vazio"}</p>
                  <button type="button" onClick={fecharPainel} className="text-[12px] uppercase tracking-[0.08em] text-black underline underline-offset-4">
                    Continuar comprando
                  </button>
                </>
              )}
            </div>
          ) : (
            <div>
              {items.map((item) => (
                <article key={item.id} className="flex gap-4 border-b py-4" style={{ borderColor: "#efefef" }}>
                  <span className="h-[96px] w-[80px] shrink-0 overflow-hidden border bg-white" style={{ borderColor: "#efefef" }}>
                    {item.image_url ? (
                      /* eslint-disable-next-line @next/next/no-img-element */
                      <img src={item.image_url} alt="" className="h-full w-full object-cover" />
                    ) : (
                      <span className="flex h-full w-full items-center justify-center text-[10px] text-[#999999]">sem foto</span>
                    )}
                  </span>

                  <div className="min-w-0 flex-1">
                    <p className="text-[12.5px] uppercase leading-snug tracking-[0.04em] text-black">{item.name}</p>
                    {/* No produto por m² a conta é peças × área: "5 m²" onde são
                        5 peças de 3,75 m² escondia 13,75 m². */}
                    <p className="mt-1 text-[12px] text-[#666666]">
                      {item.quantity.toLocaleString("pt-BR")}{" "}
                      {areaDaPeca(item) > 0
                        ? item.quantity === 1
                          ? "peça"
                          : "peças"
                        : item.quantity === 1
                          ? "unidade"
                          : "unidades"}
                      {areaDaPeca(item) > 0 ? (
                        <>
                          {" · "}
                          {numeroDaBoutique(Number(item.width_m) || 0, 2)}m × {numeroDaBoutique(Number(item.height_m) || 0, 2)}m
                          {" · "}
                          {numeroDaBoutique(areaDaPeca(item) * item.quantity, 2)} m² no total
                        </>
                      ) : null}
                    </p>
                    {comPreco && !item.price_on_request && item.valor_minimo_aplicado != null ? (
                      <p className="mt-1">
                        <BoutiqueValorMinimo minimo={item.valor_minimo_aplicado} modo="linha" />
                      </p>
                    ) : areaDaPeca(item) > 0 && comPreco && !item.price_on_request ? (
                      <p className="mt-0.5 text-[11.5px] text-[#666666]">{moedaDaBoutique(item.price)} / m²</p>
                    ) : null}
                    {item.variation_description ? (
                      <p className="mt-1 text-[11.5px] leading-snug text-[#666666]" data-bq-opcoes-do-item="">
                        {item.variation_description}
                      </p>
                    ) : null}
                    {avisosDeEstoque[item.id] ? (
                      /* Estoque v2: o servidor conferiu o carrinho inteiro. */
                      <p className="mt-1 text-[11.5px] font-semibold leading-snug text-[#d7271d]">{avisosDeEstoque[item.id]}</p>
                    ) : null}

                    <div className="mt-2.5 flex items-center justify-between gap-2">
                      <div className="bq-stepper h-8">
                        <button
                          type="button"
                          aria-label="Diminuir"
                          className="!w-8"
                          onClick={() => {
                            const r = updateQuantity(item.id, item.quantity - 1);
                            if (!r.ok && r.message) setAviso(r.message);
                          }}
                        >
                          <Minus className="h-3 w-3" />
                        </button>
                        <span className="flex w-10 items-center justify-center border-x text-[13px] font-semibold tabular-nums" style={{ borderColor: "#e1e1e1" }}>
                          {item.quantity}
                        </span>
                        <button
                          type="button"
                          aria-label="Aumentar"
                          className="!w-8"
                          onClick={() => {
                            const r = updateQuantity(item.id, item.quantity + 1);
                            if (!r.ok && r.message) setAviso(r.message);
                          }}
                        >
                          <Plus className="h-3 w-3" />
                        </button>
                      </div>
                      {/* Sem preço para este visitante a linha fica sem valor;
                          item sob consulta leva o texto da loja, não R$ 0. */}
                      {comPreco ? (
                        <p className="text-[15px] font-semibold tabular-nums text-black">
                          {item.price_on_request ? textoSemPreco : moedaDaBoutique(valorDaLinha(item))}
                        </p>
                      ) : null}
                    </div>
                    <button
                      type="button"
                      onClick={() => removeFromCart(item.id)}
                      className="mt-2 inline-flex items-center gap-1 text-[11.5px] text-[#666666] underline-offset-2 hover:text-black hover:underline"
                    >
                      <Trash2 className="h-3 w-3" strokeWidth={1.6} />
                      Remover
                    </button>
                  </div>
                </article>
              ))}

              {aviso ? <p className="my-3 bg-[#f6f6f6] px-3 py-2 text-[12.5px] text-[#252525]">{aviso}</p> : null}
            </div>
          )}
        </div>

        {items.length ? (
          <footer className="shrink-0 border-t bg-white px-5 pb-[calc(16px+env(safe-area-inset-bottom))] pt-4" style={{ borderColor: "#efefef" }}>
            {/* cupom: só no carrinho comum, com preço na tela */}
            {comPreco && modoCarrinho ? (
              <div className="mb-3">
                {appliedCoupons.map((c) => (
                  <div key={c.code} className="mb-2 flex items-start justify-between gap-3 border border-dashed px-3 py-2" style={{ borderColor: "#c4bcb4" }}>
                    <span className="min-w-0">
                      <span className="flex items-center gap-1.5 text-[12.5px] font-semibold text-black">
                        {c.slot === "frete" ? <Truck className="h-3.5 w-3.5 shrink-0" /> : c.automatic ? <Sparkles className="h-3.5 w-3.5 shrink-0" /> : <Tag className="h-3.5 w-3.5 shrink-0" />}
                        <span className="truncate">
                          {c.slot === "frete"
                            ? `Frete grátis: ${c.automatic ? c.name : c.code}`
                            : c.automatic
                              ? `Desconto aplicado: ${c.name}`
                              : `Cupom ${c.code}`}
                        </span>
                      </span>
                      <span className="mt-0.5 block text-[11.5px] leading-snug text-[#666666]">
                        {c.description}
                        {c.waitingShipping ? ". O frete grátis entra quando você escolher a entrega." : ""}
                      </span>
                    </span>
                    {c.removable ? (
                      <button
                        type="button"
                        onClick={() => {
                          removeCoupon(c.code);
                          setAvisoDoCupom(null);
                        }}
                        className="shrink-0 text-[12px] text-[#666666] underline hover:text-black"
                      >
                        Remover
                      </button>
                    ) : null}
                  </div>
                ))}
                {appliedCoupons.length < 2 ? (
                  <div className="flex">
                    <input
                      value={cupom}
                      onChange={(e) => {
                        setCupom(e.target.value.toUpperCase());
                        setAvisoDoCupom(null);
                      }}
                      onKeyDown={(e) => {
                        if (e.key === "Enter") void usarCupom();
                      }}
                      placeholder={appliedCoupons.length ? "Tem outro cupom?" : "Cupom de desconto"}
                      aria-label="Código do cupom"
                      autoComplete="off"
                      className="bq-carrinho-campo"
                    />
                    <button
                      type="button"
                      onClick={() => void usarCupom()}
                      disabled={aplicando || !cupom.trim()}
                      className="h-10 shrink-0 px-4 text-[12px] font-bold uppercase transition-opacity disabled:opacity-40"
                      style={{ backgroundColor: "var(--bq-primary)", color: "var(--bq-primary-fg)" }}
                    >
                      {aplicando ? "..." : "Aplicar"}
                    </button>
                  </div>
                ) : null}
                {avisoDoCupom ? (
                  <p className="mt-1.5 text-[12px]" style={{ color: avisoDoCupom.ok ? "#00863a" : "#d7271d" }}>
                    {avisoDoCupom.texto}
                  </p>
                ) : null}
                {couponNotices.map((n) => (
                  <p key={n.code} className="mt-1.5 text-[12px] text-[#d7271d]">
                    {n.code}: {n.message}
                    <button type="button" onClick={() => removeCoupon(n.code)} className="ml-2 font-semibold underline">
                      Tirar
                    </button>
                  </p>
                ))}
                {availableCoupons.length ? (
                  <div className="mt-2 flex flex-wrap gap-1.5">
                    {availableCoupons.map((c) => (
                      <button
                        key={c.code}
                        type="button"
                        title={c.frase}
                        onClick={() => void usarCupom(c.code)}
                        disabled={aplicando}
                        className="inline-flex max-w-full items-center gap-1.5 border border-dashed px-2.5 py-1 text-[11.5px] transition hover:bg-[#faf6f2] disabled:opacity-50"
                        style={{ borderColor: "#c4bcb4", borderRadius: 3 }}
                      >
                        {c.vaga === "frete" ? <Truck className="h-3 w-3 shrink-0" style={{ color: "var(--bq-accent)" }} /> : null}
                        <span className="font-bold tracking-wide text-black">{c.code}</span>
                        <span className="truncate text-[#666666]">{c.rotulo}</span>
                      </button>
                    ))}
                  </div>
                ) : null}
              </div>
            ) : null}

            {comPreco ? (
              <div className="space-y-1.5">
                <Linha rotulo="Subtotal" valor={moedaDaBoutique(cartSubtotal)} />
                {discountTotal > 0 ? (
                  <Linha
                    rotulo={`Desconto${(() => {
                      const c = appliedCoupons.find((x) => x.slot === "desconto");
                      return c ? ` (${c.automatic ? c.name : c.code})` : "";
                    })()}`}
                    valor={`- ${moedaDaBoutique(discountTotal)}`}
                  />
                ) : null}
                {/* A entrega aparece sempre que houver uma escolhida: grátis
                    também é resposta. */}
                {shippingSelection ? (
                  <Linha
                    rotulo={
                      isPickupShippingOption(shippingSelection.option)
                        ? `Retirada${shippingSelection.option.service ? ` (${shippingSelection.option.service})` : ""}`
                        : `Entrega${shippingSelection.option.service ? ` (${shippingSelection.option.service})` : ""}`
                    }
                    valor={shippingTotal > 0 ? moedaDaBoutique(shippingTotal) : "Grátis"}
                  />
                ) : null}
                {shippingDiscount > 0 ? (
                  <Linha
                    rotulo={`Frete grátis${(() => {
                      const c = appliedCoupons.find((x) => x.slot === "frete");
                      return c ? ` (${c.automatic ? c.name : c.code})` : "";
                    })()}`}
                    valor={`- ${moedaDaBoutique(shippingDiscount)}`}
                  />
                ) : null}
                <div className="border-t pt-2" style={{ borderColor: "#efefef" }}>
                  <Linha rotulo={temSobConsulta ? "Total parcial" : "Total"} valor={moedaDaBoutique(cartTotal)} forte />
                </div>
                {temSobConsulta ? (
                  <p className="text-[11.5px] text-[#666666]">Itens &ldquo;{textoSemPreco}&rdquo; não entram no total.</p>
                ) : null}
                {visao.avisoDePreco ? <p className="text-[11.5px] text-[#666666]">{visao.avisoDePreco}</p> : null}
              </div>
            ) : (
              /* Sem preço para este visitante não há total: a loja responde com os valores. */
              <p className="bg-[#f6f6f6] px-3 py-2 text-[12.5px] text-[#666666]">
                {modoOrcamento ? "Os valores vêm no orçamento da loja." : textoSemPreco}
              </p>
            )}

            {/* Abaixo do pedido mínimo: avisa antes do clique e trava o botão. */}
            {faltaMinimo && !precisaEntrarParaFechar && visao.podeComprar ? (
              <p className="mt-3 px-3 py-2 text-[12.5px] font-medium" style={{ backgroundColor: "#fffbeb", color: "#b45309" }}>
                {faltaMinimo}
              </p>
            ) : null}

            {/* Quem pede, no pedido de orçamento. */}
            {modoOrcamento && !precisaEntrarParaFechar && visao.podeComprar ? (
              <div className="mt-3 space-y-2">
                {!visao.cliente ? (
                  <>
                    <p className="text-[11px] font-semibold uppercase tracking-wide text-[#666666]">Para a loja responder</p>
                    <input
                      value={contato.nome}
                      onChange={(e) => setContato((atual) => ({ ...atual, nome: e.target.value }))}
                      placeholder="Seu nome"
                      autoComplete="name"
                      className={CLASSE_DO_CAMPO}
                    />
                    <input
                      value={contato.whatsapp}
                      onChange={(e) => setContato((atual) => ({ ...atual, whatsapp: e.target.value }))}
                      placeholder="WhatsApp"
                      inputMode="tel"
                      autoComplete="tel"
                      className={CLASSE_DO_CAMPO}
                    />
                    <input
                      value={contato.email}
                      onChange={(e) => setContato((atual) => ({ ...atual, email: e.target.value }))}
                      placeholder="E-mail (opcional)"
                      inputMode="email"
                      autoComplete="email"
                      className={CLASSE_DO_CAMPO}
                    />
                  </>
                ) : null}
                <textarea
                  value={contato.observacoes}
                  onChange={(e) => setContato((atual) => ({ ...atual, observacoes: e.target.value }))}
                  placeholder={visao.cliente ? "Observações para a loja (opcional)" : "Observações (opcional)"}
                  rows={2}
                  className={`${CLASSE_DO_CAMPO} h-auto py-2`}
                />
              </div>
            ) : null}

            {erro ? <p className="mt-3 text-[12.5px] font-medium text-[#d7271d]">{erro}</p> : null}

            {linkPendente ? (
              <a
                href={linkPendente}
                target="_blank"
                rel="noopener noreferrer"
                onClick={concluirPeloLinkPendente}
                className="bq-carrinho-botao mt-4 text-white"
                style={{ backgroundColor: "var(--bq-whats)", color: "#ffffff" }}
              >
                <IconeDoWhats />
                Abrir o WhatsApp
              </a>
            ) : precisaEntrarParaFechar ? (
              /* Primeiro o login, depois o pedido. */
              <button type="button" onClick={irParaOLogin} className="bq-carrinho-botao mt-4">
                <LogIn className="h-4 w-4" />
                {visao.precisaEntrar ? visao.regras.textoPrecoLogin : "Entrar para fechar o pedido"}
              </button>
            ) : !visao.podeComprar ? (
              /* Loja em pausa, cadastro em análise, só vitrine: parado, com o motivo. */
              <button type="button" disabled className="bq-carrinho-botao mt-4">
                {visao.motivoDoBloqueio || "Indisponível"}
              </button>
            ) : modoOrcamento ? (
              <button type="button" onClick={enviarPedidoDeOrcamento} disabled={enviando || Boolean(faltaMinimo)} className="bq-carrinho-botao mt-4">
                <Send className="h-4 w-4" />
                {enviando ? "Enviando..." : visao.rotuloDeFechar || "Enviar pedido de orçamento"}
              </button>
            ) : visao.modoDeCompra === "whatsapp" ? (
              /* "Pedir pelo WhatsApp": a conversa é o pedido. */
              digitosDoWhats ? (
                <a
                  href={`https://wa.me/${digitosDoWhats}?text=${mensagemDoWhats}`}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="bq-carrinho-botao mt-4 text-white"
                  style={{ backgroundColor: "var(--bq-whats)", color: "#ffffff" }}
                >
                  <IconeDoWhats />
                  {visao.rotuloDeFechar || "Enviar pedido pelo WhatsApp"}
                </a>
              ) : (
                <p className="mt-3 text-center text-[12.5px] text-[#666666]">
                  Esta loja ainda não tem forma de fechar o pedido pela internet. Fale com a loja para combinar.
                </p>
              )
            ) : (
              <>
                {temPagamento !== false ? (
                  <button
                    type="button"
                    onClick={() => {
                      toggleCart();
                      router.push(`/${slug}/checkout`);
                    }}
                    disabled={Boolean(faltaMinimo)}
                    className="bq-carrinho-botao mt-4"
                  >
                    <CreditCard className="h-4 w-4" strokeWidth={1.6} />
                    {visao.rotuloDeFechar || "Seguir para pagamento"}
                  </button>
                ) : null}

                {/* O WhatsApp só entra quando a loja NÃO tem pagamento online. */}
                {temPagamento === false && digitosDoWhats ? (
                  <button
                    type="button"
                    onClick={enviarPeloWhats}
                    disabled={enviando || Boolean(faltaMinimo)}
                    className="bq-carrinho-botao mt-4 text-white"
                    style={{ backgroundColor: "var(--bq-whats)", color: "#ffffff" }}
                  >
                    <IconeDoWhats />
                    {enviando ? "Registrando o pedido..." : visao.rotuloDeFechar || "Enviar pedido pelo WhatsApp"}
                  </button>
                ) : null}

                {temPagamento === false && !digitosDoWhats ? (
                  <p className="mt-3 text-center text-[12.5px] text-[#666666]">
                    Esta loja ainda não tem forma de fechar o pedido pela internet. Fale com a loja para combinar.
                  </p>
                ) : null}
              </>
            )}

            <button type="button" onClick={fecharPainel} className="mt-3 w-full text-center text-[12px] uppercase tracking-[0.08em] text-[#252525] underline underline-offset-4">
              Continuar comprando
            </button>
          </footer>
        ) : null}
      </aside>
    </div>
  );
}

/* O carrinho vazio da referência: o desenho de traço fino do carrinho. */
function CarrinhoVazio() {
  return (
    <svg viewBox="0 0 140 110" className="h-[106px] w-[140px]" aria-hidden="true" fill="none">
      <path d="M118 6h12" stroke="#99a3ad" strokeWidth="1" />
      <path d="M118 6l-6 16" stroke="#99a3ad" strokeWidth="1" />
      <path d="M17 22h95l-14 50H31L17 22z" fill="#f2f2f2" stroke="#7a8696" strokeWidth="1" />
      <path d="M36 22l7 50M57 22l3 50M78 22l-2 50M98 22l-7 50M22 39h85M27 56h75" stroke="#7a8696" strokeWidth="0.8" />
      <path d="M38 72l4 12h66V68" stroke="#7a8696" strokeWidth="1" />
      <circle cx="48" cy="94" r="4.5" fill="#7a8696" />
      <circle cx="94" cy="94" r="4.5" fill="#7a8696" />
      <path d="M2 100h136" stroke="#7a8696" strokeWidth="1" />
      <path d="M6 100c0-10 6-17 14-20-2 8-2 14 4 20H6z" fill="#18324d" />
      <path d="M134 100c0-10-6-17-14-20 2 8 2 14-4 20h18z" fill="#18324d" />
      <path d="M14 100c2-8 6-13 12-16" stroke="#99a3ad" strokeWidth="1" />
      <path d="M126 100c-2-8-6-13-12-16" stroke="#99a3ad" strokeWidth="1" />
    </svg>
  );
}
