"use client";

import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { motion, useReducedMotion } from "framer-motion";
import {
  Check,
  Download,
  ExternalLink,
  FileText,
  LayoutGrid,
  Loader2,
  MessageCircle,
  RectangleVertical,
  RefreshCw,
  Share2,
  ShoppingBag,
  Smartphone,
  SquareDashed,
} from "lucide-react";
import { Anel, CabecalhoDoPainel, Eyebrow, Opcao, Painel } from "@/components/assinatura/primitivos";
import { Aviso } from "@/components/ui/aviso";
import { Input } from "@/components/ui/input";
import { PageHeader } from "@/components/ui/page-header";
import { Switch } from "@/components/ui/switch";
import { anoEmSaoPaulo, emDestaque, LIMITE_DO_SUBTITULO, LIMITE_DO_TITULO, opcoesPadrao, type OpcoesDoCatalogo } from "@/lib/catalogo-pdf/opcoes";
import { contarPaginas } from "@/lib/catalogo-pdf/paginas";
import type { ResumoDaLoja } from "@/lib/catalogo-pdf/servidor/carregar";
import type { SituacaoDoCatalogo } from "@/lib/catalogo-pdf/servidor/fila";

/*
  Catálogo em PDF: a pessoa escolhe como quer o catálogo, o servidor monta o
  PDF com o desenho aprovado (cores e logo da loja) e a tela entrega o
  arquivo para baixar ou mandar direto no WhatsApp.

  Gerar leva de segundos a alguns minutos, então a tela acompanha o
  andamento (a fila responde na hora e a tela pergunta a cada segundo). O
  número do catálogo em andamento fica guardado na aba: recarregar a página
  não perde o que já estava sendo feito.
*/

const GUARDADO = "ktalogu:catalogo-pdf:tarefa";

type Arquivo = { blob: Blob; url: string; nome: string };

function guardar(id: string | null) {
  try {
    if (id) sessionStorage.setItem(GUARDADO, id);
    else sessionStorage.removeItem(GUARDADO);
  } catch {
    /* aba sem armazenamento: só não sobrevive ao recarregar */
  }
}

function guardado() {
  try {
    return sessionStorage.getItem(GUARDADO);
  } catch {
    return null;
  }
}

function tamanhoLegivel(bytes: number) {
  if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toLocaleString("pt-BR", { maximumFractionDigits: 1 })} MB`;
  return `${Math.max(1, Math.round(bytes / 1024)).toLocaleString("pt-BR")} KB`;
}

function plural(n: number, um: string, varios: string) {
  return `${n.toLocaleString("pt-BR")} ${n === 1 ? um : varios}`;
}

/* O andamento em uma frase e numa fração do anel. */
function andamento(situacao: SituacaoDoCatalogo | null): { texto: string; fracao: number } {
  if (!situacao) return { texto: "Começando…", fracao: 0.02 };
  const parte = situacao.total > 0 ? Math.min(1, situacao.feito / situacao.total) : 0;
  switch (situacao.etapa) {
    case "fila":
      return {
        texto: situacao.naFrente > 0 ? `Na fila · ${plural(situacao.naFrente, "catálogo", "catálogos")} na frente` : "Começando…",
        fracao: 0.02,
      };
    case "loja":
      return { texto: "Lendo a sua loja", fracao: 0.06 };
    case "fotos":
      return { texto: situacao.total ? `Preparando as fotos · ${situacao.feito} de ${situacao.total}` : "Preparando as fotos", fracao: 0.1 + parte * 0.6 };
    case "paginas":
      return { texto: "Montando as páginas", fracao: 0.7 + parte * 0.15 };
    case "pdf":
      return { texto: "Gerando o PDF", fracao: 0.9 };
    case "pronto":
      return { texto: "Pronto", fracao: 1 };
    default:
      return { texto: "Parou", fracao: 0 };
  }
}

/* ------------------------------------------------------------------ peças */

function LinhaDeEscolha({
  titulo,
  texto,
  ligado,
  aoMudar,
  desativado = false,
  id,
}: {
  titulo: string;
  texto: ReactNode;
  ligado: boolean;
  aoMudar: (valor: boolean) => void;
  desativado?: boolean;
  id: string;
}) {
  return (
    <div className={`flex items-start justify-between gap-5 border-t border-[var(--ks-color-border-subtle)] px-6 py-4 ${desativado ? "opacity-60" : ""}`}>
      <div className="min-w-0">
        <label htmlFor={id} className="text-sm font-semibold text-[var(--ks-color-text-primary)]">
          {titulo}
        </label>
        <p className="mt-0.5 text-sm leading-6 text-[var(--ks-color-text-muted)]">{texto}</p>
      </div>
      <Switch id={id} checked={ligado} disabled={desativado} onCheckedChange={aoMudar} aria-label={titulo} className="mt-0.5" />
    </div>
  );
}

/*
  A capa em miniatura, com as cores, a logo, a fonte e as fotos da loja. É a
  capa de verdade desenhada no tamanho real (450 × 800 ou A4) e encolhida,
  para as proporções baterem com o PDF.
*/
function PreviaDaCapa({ resumo, opcoes, produtos, categorias }: { resumo: ResumoDaLoja; opcoes: OpcoesDoCatalogo; produtos: number; categorias: number }) {
  const a4 = opcoes.formato === "a4";
  const [largura, altura] = a4 ? [794, 1123] : [450, 800];
  const mostrada = a4 ? 236 : 210;
  const escala = mostrada / largura;
  const fotos = resumo.capa.slice(0, a4 ? (resumo.capa.length >= 4 ? 4 : 0) : resumo.capa.length >= 6 ? 6 : resumo.capa.length >= 3 ? 3 : 0);
  const frase = opcoes.subtitulo || resumo.slogan || resumo.nome;
  const { cores } = resumo;
  return (
    <div className="relative mx-auto overflow-hidden rounded-[14px] shadow-[0_18px_40px_-18px_rgba(26,26,43,0.45)]" style={{ width: mostrada, height: altura * escala }}>
      {resumo.fonte.folhas.map((folha) => (
        <link key={folha} rel="stylesheet" href={folha} precedence="default" />
      ))}
      <div
        aria-hidden
        className="absolute left-0 top-0 flex flex-col"
        style={{
          width: largura,
          height: altura,
          transform: `scale(${escala})`,
          transformOrigin: "top left",
          background: cores.marca,
          color: cores.tintaNaMarca,
          padding: a4 ? "56px 56px 0" : "34px 32px 0",
        }}
      >
        <div style={{ height: a4 ? 84 : 60, display: "flex", alignItems: "center" }}>
          {resumo.logo ? (
            <span
              style={{
                height: a4 ? 76 : 56,
                display: "inline-flex",
                alignItems: "center",
                ...(resumo.logo.placa ? { padding: "8px 12px", borderRadius: 14, background: resumo.logo.placa === "branca" ? "#FFFFFF" : cores.tinta } : {}),
              }}
            >
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img src={resumo.logo.url} alt="" style={{ height: "100%", width: "auto", objectFit: "contain" }} />
            </span>
          ) : (
            <span style={{ fontFamily: resumo.fonte.titulo, fontWeight: 800, fontSize: 28 }}>{resumo.nome}</span>
          )}
        </div>
        <div style={{ marginTop: a4 ? 56 : 30 }}>
          <span
            style={{
              display: "inline-block",
              padding: a4 ? "9px 16px" : "7px 12px",
              borderRadius: 999,
              background: cores.tinta,
              color: cores.sobreTinta,
              fontWeight: 700,
              fontSize: a4 ? 13 : 11,
              letterSpacing: ".16em",
              textTransform: "uppercase",
            }}
          >
            {opcoes.titulo}
          </span>
          <h1
            style={{
              fontFamily: resumo.fonte.titulo,
              fontWeight: 800,
              fontSize: fotos.length ? (a4 ? 68 : 40) : a4 ? 92 : 54,
              lineHeight: 1.04,
              letterSpacing: "-.02em",
              marginTop: a4 ? 22 : 16,
              maxWidth: a4 ? 640 : undefined,
              textWrap: "balance",
            }}
          >
            {frase}
          </h1>
        </div>
        {fotos.length ? (
          <div style={{ marginTop: a4 ? 48 : 26, display: "grid", gridTemplateColumns: `repeat(${a4 ? 4 : 3}, 1fr)`, gap: a4 ? 14 : 10 }}>
            {fotos.map((foto) => (
              <span key={foto} style={{ aspectRatio: "1", borderRadius: a4 ? 22 : 18, overflow: "hidden", background: "#FFFFFF" }}>
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img src={foto} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />
              </span>
            ))}
          </div>
        ) : null}
        <div
          style={{
            margin: a4 ? "auto -56px 0" : "auto -32px 0",
            background: cores.tinta,
            color: cores.sobreTinta,
            padding: a4 ? "30px 56px 32px" : "20px 32px 22px",
            display: "flex",
            gap: 22,
            fontSize: a4 ? 15 : 13,
          }}
        >
          <span>
            <b style={{ fontFamily: resumo.fonte.titulo, fontSize: a4 ? 36 : 26, fontWeight: 800, marginRight: 6 }}>{produtos}</b> produtos
          </span>
          <span>
            <b style={{ fontFamily: resumo.fonte.titulo, fontSize: a4 ? 36 : 26, fontWeight: 800, marginRight: 6 }}>{categorias}</b>{" "}
            {categorias === 1 ? "categoria" : "categorias"}
          </span>
        </div>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ tela */

export default function CatalogoEmPdfPage() {
  const parado = useReducedMotion();
  const [resumo, setResumo] = useState<ResumoDaLoja | null>(null);
  const [erroDaLoja, setErroDaLoja] = useState<string | null>(null);
  const [opcoes, setOpcoes] = useState<OpcoesDoCatalogo>(() => opcoesPadrao(anoEmSaoPaulo()));
  const [soAlgumas, setSoAlgumas] = useState(false);
  const [marcadas, setMarcadas] = useState<string[]>([]);
  const [tarefa, setTarefa] = useState<string | null>(null);
  const [situacao, setSituacao] = useState<SituacaoDoCatalogo | null>(null);
  const [erro, setErro] = useState<string | null>(null);
  const [pedindo, setPedindo] = useState(false);
  const [arquivo, setArquivo] = useState<Arquivo | null>(null);
  const [podeCompartilhar, setPodeCompartilhar] = useState(false);
  /* As escolhas com que o PDF pronto foi feito, para avisar quando mudarem. */
  const [escolhasDoArquivo, setEscolhasDoArquivo] = useState<string | null>(null);
  const urlDoArquivo = useRef<string | null>(null);

  const mudar = useCallback(<K extends keyof OpcoesDoCatalogo>(chave: K, valor: OpcoesDoCatalogo[K]) => {
    setOpcoes((atual) => ({ ...atual, [chave]: valor }));
  }, []);

  /* A loja: categorias, contagens e a cara dela. */
  useEffect(() => {
    let viva = true;
    (async () => {
      try {
        const resposta = await fetch("/api/catalogo-pdf", { cache: "no-store" });
        const dados = await resposta.json().catch(() => ({}));
        if (!viva) return;
        if (!resposta.ok) {
          setErroDaLoja(dados.error || "Não foi possível abrir a sua loja agora. Tente de novo em instantes.");
          return;
        }
        const loja = dados.loja as ResumoDaLoja;
        setResumo(loja);
        setMarcadas(loja.categorias.map((cat) => cat.id));
        if (!loja.whatsapp) setOpcoes((atual) => (atual.botao === "whatsapp" ? { ...atual, botao: "loja" } : atual));
        /* Loja com preço escondido (Regras da loja): o PDF nasce sem preço.
           A pessoa ainda pode ligar, se o catálogo for para quem pode ver. */
        if (loja.precosNaLoja === false) setOpcoes((atual) => ({ ...atual, mostrarPreco: false }));
      } catch {
        if (viva) setErroDaLoja("Sem conexão agora. Confira a internet e recarregue a página.");
      }
    })();
    /* Um catálogo que já estava sendo feito antes de recarregar. */
    const anterior = guardado();
    if (anterior) queueMicrotask(() => viva && setTarefa(anterior));
    return () => {
      viva = false;
    };
  }, []);

  /* Acompanha o catálogo na fila, uma pergunta por segundo. */
  useEffect(() => {
    if (!tarefa) return;
    let viva = true;
    let relogio: ReturnType<typeof setTimeout> | undefined;
    const perguntar = async () => {
      try {
        const resposta = await fetch(`/api/catalogo-pdf/${tarefa}`, { cache: "no-store" });
        const dados = await resposta.json().catch(() => ({}));
        if (!viva) return;
        if (resposta.status === 404) {
          guardar(null);
          setTarefa(null);
          setSituacao(null);
          setErro("O catálogo foi interrompido antes de ficar pronto. Gere de novo.");
          return;
        }
        if (!resposta.ok) throw new Error(dados.error);
        const atual = dados as SituacaoDoCatalogo;
        setSituacao(atual);
        if (atual.etapa === "erro") {
          guardar(null);
          setTarefa(null);
          setErro(atual.erro || "Não foi possível gerar o catálogo agora. Tente de novo em instantes.");
          return;
        }
        if (atual.etapa === "pronto" && atual.pronto) {
          const pdf = await fetch(`/api/catalogo-pdf/${tarefa}?baixar=1`, { cache: "no-store" });
          if (!viva) return;
          if (!pdf.ok) throw new Error("download");
          const blob = await pdf.blob();
          if (!viva) return;
          if (urlDoArquivo.current) URL.revokeObjectURL(urlDoArquivo.current);
          const url = URL.createObjectURL(blob);
          urlDoArquivo.current = url;
          setArquivo({ blob, url, nome: atual.pronto.nome });
          try {
            const teste = new File([blob], atual.pronto.nome, { type: "application/pdf" });
            setPodeCompartilhar(typeof navigator.canShare === "function" && navigator.canShare({ files: [teste] }));
          } catch {
            setPodeCompartilhar(false);
          }
          guardar(null);
          setTarefa(null);
          return;
        }
      } catch {
        /* rede oscilou: pergunta de novo no próximo segundo */
      }
      if (viva) relogio = setTimeout(perguntar, 1000);
    };
    void perguntar();
    return () => {
      viva = false;
      if (relogio) clearTimeout(relogio);
    };
  }, [tarefa]);

  useEffect(
    () => () => {
      if (urlDoArquivo.current) URL.revokeObjectURL(urlDoArquivo.current);
    },
    []
  );

  /* O que entra no PDF com as escolhas de agora. */
  const escolhidas = useMemo(() => {
    if (!resumo) return [];
    return resumo.categorias.filter((cat) => !soAlgumas || marcadas.includes(cat.id));
  }, [resumo, soAlgumas, marcadas]);
  const tamanhos = escolhidas.map((cat) => (opcoes.soComFoto ? cat.comFoto : cat.produtos));
  const produtos = tamanhos.reduce((soma, n) => soma + n, 0);
  const categoriasNoPdf = tamanhos.filter((n) => n > 0).length;
  const paginas = contarPaginas(tamanhos, opcoes);
  const destaque = emDestaque(opcoes);
  const limite = resumo ? (destaque ? resumo.limites.destaque : resumo.limites.grade) : 0;
  const passouDoLimite = produtos > limite;
  const gerando = Boolean(tarefa) || pedindo;
  const escolhasDeAgora = JSON.stringify({ ...opcoes, categorias: soAlgumas ? [...marcadas].sort() : null });

  const motivoParaNaoGerar = !resumo
    ? null
    : produtos === 0
      ? soAlgumas && !marcadas.length
        ? "Marque pelo menos uma categoria."
        : "Nenhum produto entra nessas escolhas."
      : passouDoLimite
        ? `São ${plural(produtos, "produto", "produtos")}, e ${destaque ? "o destaque" : "este formato"} aceita até ${limite}. Escolha algumas categorias${destaque ? " ou use a vitrine" : ""}.`
        : null;

  async function gerar() {
    if (!resumo || motivoParaNaoGerar || gerando) return;
    setErro(null);
    setArquivo(null);
    setSituacao(null);
    setPedindo(true);
    setEscolhasDoArquivo(escolhasDeAgora);
    try {
      const resposta = await fetch("/api/catalogo-pdf", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ ...opcoes, categorias: soAlgumas ? marcadas : null }),
      });
      const dados = await resposta.json().catch(() => ({}));
      if ((resposta.ok || resposta.status === 409) && typeof dados.id === "string") {
        guardar(dados.id);
        setTarefa(dados.id);
        return;
      }
      setErro(dados.error || "Não foi possível começar o catálogo agora. Tente de novo em instantes.");
    } catch {
      setErro("Sem conexão agora. Confira a internet e tente de novo.");
    } finally {
      setPedindo(false);
    }
  }

  function baixar() {
    if (!arquivo) return;
    const link = document.createElement("a");
    link.href = arquivo.url;
    link.download = arquivo.nome;
    document.body.appendChild(link);
    link.click();
    link.remove();
  }

  async function compartilhar() {
    if (!arquivo) return;
    try {
      await navigator.share({ files: [new File([arquivo.blob], arquivo.nome, { type: "application/pdf" })], title: arquivo.nome });
    } catch {
      /* a pessoa fechou a janela de compartilhar */
    }
  }

  function outro() {
    if (urlDoArquivo.current) {
      URL.revokeObjectURL(urlDoArquivo.current);
      urlDoArquivo.current = null;
    }
    setArquivo(null);
    setSituacao(null);
    setErro(null);
  }

  const passo = andamento(situacao);
  const pronto = arquivo && situacao?.pronto ? situacao.pronto : null;

  if (erroDaLoja) {
    return (
      <div className="space-y-6">
        <PageHeader eyebrow="Catálogo" title="Catálogo em PDF" subtitle="O catálogo da sua loja num PDF para mandar no WhatsApp." />
        <Aviso tom="atencao" titulo="Ainda não dá para gerar o catálogo">
          {erroDaLoja}
        </Aviso>
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <PageHeader
        eyebrow="Catálogo"
        title="Catálogo em PDF"
        subtitle="O catálogo da sua loja num PDF para mandar no WhatsApp, com fotos, preços e o botão que leva o cliente direto ao produto."
        actions={
          resumo ? (
            <a href={resumo.urlDaLoja} target="_blank" rel="noopener noreferrer" className="ks-button ks-button-secondary">
              <ExternalLink size={16} />
              Ver a loja
            </a>
          ) : null
        }
      />

      {erro ? (
        <Aviso tom="ruim" titulo="O catálogo não ficou pronto" aoFechar={() => setErro(null)}>
          {erro}
        </Aviso>
      ) : null}

      <div className="grid gap-6 lg:grid-cols-12 lg:items-start">
        {/* ------------------------------------------ prévia, andamento e o arquivo */}
        <div className="order-first lg:order-last lg:col-span-5 lg:sticky lg:top-6">
          <Painel>
            {pronto && arquivo ? (
              <div className="p-6">
                <div className="flex items-center justify-between gap-3">
                  <Eyebrow>Pronto</Eyebrow>
                  <span className="inline-flex items-center gap-1.5 text-xs font-semibold text-[var(--ks-color-status-success)]">
                    <Check size={14} strokeWidth={2.6} />
                    {plural(pronto.paginas, "página", "páginas")} · {tamanhoLegivel(pronto.tamanho)}
                  </span>
                </div>
                <p className="mt-1 break-words text-lg font-extrabold tracking-tight text-[var(--ks-color-text-primary)]">{pronto.nome}</p>
                <div className="-mx-6 mt-5 flex gap-3 overflow-x-auto px-6 pb-2">
                  {pronto.miniaturas.map((miniatura, indice) => (
                    <motion.img
                      key={indice}
                      src={miniatura}
                      alt={`Página ${indice + 1} do catálogo`}
                      initial={parado ? false : { opacity: 0, y: 6 }}
                      animate={{ opacity: 1, y: 0 }}
                      transition={{ delay: indice * 0.06 }}
                      className={`shrink-0 rounded-lg border border-[var(--ks-color-border-subtle)] shadow-sm ${opcoes.formato === "a4" ? "h-40" : "h-44"}`}
                    />
                  ))}
                </div>
                {escolhasDoArquivo && escolhasDoArquivo !== escolhasDeAgora ? (
                  <div className="mt-4 rounded-xl bg-[var(--ks-color-bg-inset)] px-4 py-3">
                    <p className="text-sm leading-6 text-[var(--ks-color-text-secondary)]">Você mudou as escolhas depois de gerar. Este PDF ainda é o de antes.</p>
                    <button type="button" onClick={gerar} disabled={Boolean(motivoParaNaoGerar)} className="ks-button ks-button-secondary mt-2 w-full">
                      <RefreshCw size={16} />
                      Gerar com as mudanças
                    </button>
                  </div>
                ) : null}
                <div className="mt-5 grid gap-2">
                  <button type="button" onClick={baixar} className="ks-button ks-button-primary w-full">
                    <Download size={16} />
                    Baixar o PDF
                  </button>
                  {podeCompartilhar ? (
                    <button type="button" onClick={compartilhar} className="ks-button ks-button-secondary w-full">
                      <Share2 size={16} />
                      Mandar pelo WhatsApp
                    </button>
                  ) : null}
                  <div className="grid grid-cols-2 gap-2">
                    <a href={arquivo.url} target="_blank" rel="noopener noreferrer" className="ks-button ks-button-ghost w-full">
                      <ExternalLink size={16} />
                      Abrir
                    </a>
                    <button type="button" onClick={outro} className="ks-button ks-button-ghost w-full">
                      <RefreshCw size={16} />
                      Gerar outro
                    </button>
                  </div>
                </div>
                <p className="mt-4 text-xs leading-5 text-[var(--ks-color-text-soft)]">
                  {podeCompartilhar
                    ? "Em “Mandar pelo WhatsApp”, escolha o WhatsApp na lista e a conversa."
                    : "Baixe o PDF e anexe na conversa do WhatsApp como documento."}{" "}
                  Os botões do PDF abrem a loja e o WhatsApp no celular do cliente.
                </p>
              </div>
            ) : gerando ? (
              <div className="flex flex-col items-center gap-5 p-8 text-center">
                <Anel fracao={passo.fracao} tamanho={120} espessura={10}>
                  <span className="ks-num text-2xl font-extrabold text-[var(--ks-color-text-primary)]">{Math.round(passo.fracao * 100)}%</span>
                </Anel>
                <div>
                  <p className="text-base font-bold text-[var(--ks-color-text-primary)]">{passo.texto}</p>
                  <p className="mt-1 text-sm text-[var(--ks-color-text-muted)]">Pode continuar usando o sistema. Leva de alguns segundos a poucos minutos, conforme o número de fotos.</p>
                </div>
              </div>
            ) : (
              <div className="p-6">
                <Eyebrow>Prévia da capa</Eyebrow>
                <div className="mt-4 min-h-[200px]">
                  {resumo ? (
                    <PreviaDaCapa resumo={resumo} opcoes={opcoes} produtos={produtos} categorias={categoriasNoPdf} />
                  ) : (
                    <div className="mx-auto h-[373px] w-[210px] animate-pulse rounded-[14px] bg-[var(--ks-color-bg-soft)]" />
                  )}
                </div>
                <p className="mt-4 text-center text-xs leading-5 text-[var(--ks-color-text-soft)]">As cores, a logo e as letras são as da sua loja.</p>
              </div>
            )}

            {!pronto && !gerando ? (
              <div className="flex flex-col gap-3 border-t border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-inset)] px-6 py-4">
                <p className="text-center text-sm text-[var(--ks-color-text-secondary)]">
                  {resumo ? (
                    <>
                      <span className="ks-num font-semibold text-[var(--ks-color-text-primary)]">{plural(produtos, "produto", "produtos")}</span> ·{" "}
                      <span className="ks-num">{plural(paginas, "página", "páginas")}</span>
                    </>
                  ) : (
                    "Lendo a sua loja…"
                  )}
                </p>
                <button type="button" onClick={gerar} disabled={!resumo || Boolean(motivoParaNaoGerar)} className="ks-button ks-button-primary w-full">
                  {pedindo ? <Loader2 size={16} className="animate-spin" /> : <FileText size={16} />}
                  Gerar PDF
                </button>
              </div>
            ) : null}
            {motivoParaNaoGerar && !gerando && !pronto ? (
              <p className="border-t border-[var(--ks-color-border-subtle)] px-6 py-3 text-sm text-[var(--ks-color-status-danger)]">{motivoParaNaoGerar}</p>
            ) : null}
          </Painel>
        </div>

        {/* ------------------------------------------ as escolhas */}
        <fieldset disabled={gerando} className="min-w-0 space-y-6 lg:col-span-7">
          <Painel>
            <CabecalhoDoPainel titulo="Formato" texto="Onde o catálogo vai ser lido." />
            <div role="radiogroup" aria-label="Formato" className="grid gap-4 p-6 md:grid-cols-2">
              <Opcao selecionada={opcoes.formato === "celular"} aoEscolher={() => mudar("formato", "celular")} titulo="Celular">
                <span className="flex items-start gap-3 text-sm leading-6 text-[var(--ks-color-text-muted)]">
                  <Smartphone size={18} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" />
                  Cada página cabe na tela do celular, sem dar zoom. O melhor para mandar no WhatsApp.
                </span>
              </Opcao>
              <Opcao selecionada={opcoes.formato === "a4"} aoEscolher={() => mudar("formato", "a4")} titulo="Folha A4">
                <span className="flex items-start gap-3 text-sm leading-6 text-[var(--ks-color-text-muted)]">
                  <FileText size={18} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" />
                  Para imprimir ou mandar por e-mail. Seis produtos por página, com a descrição.
                </span>
              </Opcao>
            </div>
            {opcoes.formato === "celular" ? (
              <>
                <div className="border-t border-[var(--ks-color-border-subtle)] px-6 pt-4 text-sm font-semibold text-[var(--ks-color-text-primary)]">Jeito de mostrar</div>
                <div role="radiogroup" aria-label="Jeito de mostrar" className="grid gap-4 p-6 pt-3 md:grid-cols-2">
                  <Opcao selecionada={opcoes.layout === "vitrine"} aoEscolher={() => mudar("layout", "vitrine")} titulo="Vitrine">
                    <span className="flex items-start gap-3 text-sm leading-6 text-[var(--ks-color-text-muted)]">
                      <LayoutGrid size={18} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" />
                      Quatro produtos por página. Mostra a loja toda em poucas páginas.
                    </span>
                  </Opcao>
                  <Opcao selecionada={opcoes.layout === "destaque"} aoEscolher={() => mudar("layout", "destaque")} titulo="Destaque">
                    <span className="flex items-start gap-3 text-sm leading-6 text-[var(--ks-color-text-muted)]">
                      <RectangleVertical size={18} className="mt-0.5 shrink-0 text-[var(--ks-brand-600)]" />
                      Um produto por página, com fotos extras, as cores e a tabela de quantidade.
                    </span>
                  </Opcao>
                </div>
              </>
            ) : null}
          </Painel>

          <Painel>
            <CabecalhoDoPainel titulo="Produtos" texto="Os que estão à venda na loja, na mesma ordem." />
            <div role="radiogroup" aria-label="Quais produtos" className="grid gap-4 p-6 md:grid-cols-2">
              <Opcao selecionada={!soAlgumas} aoEscolher={() => setSoAlgumas(false)} titulo="A loja inteira">
                <span className="text-sm leading-6 text-[var(--ks-color-text-muted)]">
                  {resumo ? `${plural(resumo.totais.produtos, "produto", "produtos")} em ${plural(resumo.categorias.length, "categoria", "categorias")}.` : "…"}
                </span>
              </Opcao>
              <Opcao selecionada={soAlgumas} aoEscolher={() => setSoAlgumas(true)} titulo="Só algumas categorias">
                <span className="text-sm leading-6 text-[var(--ks-color-text-muted)]">Para um cliente que só quer brindes, ou só banners.</span>
              </Opcao>
            </div>
            {soAlgumas && resumo ? (
              <div className="border-t border-[var(--ks-color-border-subtle)] px-6 py-4">
                <div className="mb-2 flex items-center justify-between gap-3">
                  <span className="text-sm font-semibold text-[var(--ks-color-text-primary)]">
                    {plural(marcadas.length, "categoria marcada", "categorias marcadas")}
                  </span>
                  <span className="flex gap-3 text-sm">
                    <button type="button" className="font-semibold text-[var(--ks-brand-600)] hover:underline" onClick={() => setMarcadas(resumo.categorias.map((cat) => cat.id))}>
                      Todas
                    </button>
                    <button type="button" className="font-semibold text-[var(--ks-brand-600)] hover:underline" onClick={() => setMarcadas([])}>
                      Nenhuma
                    </button>
                  </span>
                </div>
                <ul className="grid gap-x-6 sm:grid-cols-2">
                  {resumo.categorias.map((cat) => {
                    const marcada = marcadas.includes(cat.id);
                    return (
                      <li key={cat.id}>
                        <label className="flex cursor-pointer items-center gap-3 rounded-lg px-2 py-2 hover:bg-[var(--ks-color-bg-subtle)]/60">
                          <input
                            type="checkbox"
                            className="h-4 w-4 shrink-0 accent-[var(--ks-brand-600)]"
                            checked={marcada}
                            onChange={(evento) =>
                              setMarcadas((atual) => (evento.target.checked ? [...atual, cat.id] : atual.filter((id) => id !== cat.id)))
                            }
                          />
                          <span className="min-w-0 flex-1 truncate text-sm text-[var(--ks-color-text-primary)]">{cat.nome}</span>
                          <span className="ks-num shrink-0 text-xs text-[var(--ks-color-text-soft)]">{cat.produtos}</span>
                        </label>
                      </li>
                    );
                  })}
                </ul>
              </div>
            ) : null}
            <LinhaDeEscolha
              id="so-com-foto"
              titulo="Só produtos com foto"
              texto={
                resumo
                  ? resumo.totais.comFoto === resumo.totais.produtos
                    ? "Todos os produtos da loja têm foto."
                    : `${plural(resumo.totais.comFoto, "produto tem", "produtos têm")} foto. Sem esta opção, quem não tem entra com a sua logo no lugar da foto.`
                  : "…"
              }
              ligado={opcoes.soComFoto}
              aoMudar={(valor) => mudar("soComFoto", valor)}
            />
          </Painel>

          <Painel>
            <CabecalhoDoPainel titulo="Preço e botão" texto="O que o cliente vê e para onde o toque leva." />
            <LinhaDeEscolha
              id="mostrar-preco"
              titulo="Mostrar os preços"
              texto={
                resumo && resumo.precosNaLoja === false
                  ? "Na loja os preços estão escondidos, então aqui nasce desligado. Ligue só se o catálogo for para quem pode ver os preços."
                  : "O preço que aparece é o mesmo “a partir de” da loja. Desligado, o catálogo mostra só os produtos."
              }
              ligado={opcoes.mostrarPreco}
              aoMudar={(valor) => mudar("mostrarPreco", valor)}
            />
            <LinhaDeEscolha
              id="mostrar-escada"
              titulo="Mostrar a tabela de quantidade"
              texto="“Quanto mais, menos paga”: os preços por quantidade e o selo de desconto, nos produtos que têm."
              ligado={opcoes.mostrarPreco && opcoes.mostrarEscada}
              desativado={!opcoes.mostrarPreco}
              aoMudar={(valor) => mudar("mostrarEscada", valor)}
            />
            <div className="border-t border-[var(--ks-color-border-subtle)] px-6 pt-4 text-sm font-semibold text-[var(--ks-color-text-primary)]">Botão de cada produto</div>
            <div role="radiogroup" aria-label="Botão de cada produto" className="grid gap-3 p-6 pt-3">
              <Opcao selecionada={opcoes.botao === "loja"} aoEscolher={() => mudar("botao", "loja")} titulo="Comprar">
                <span className="flex items-start gap-2.5 text-sm leading-6 text-[var(--ks-color-text-muted)]">
                  <ShoppingBag size={17} className="mt-1 shrink-0 text-[var(--ks-brand-600)]" />
                  Abre o produto na loja, para o cliente escolher e comprar.
                </span>
              </Opcao>
              <Opcao
                selecionada={opcoes.botao === "whatsapp"}
                aoEscolher={() => (resumo?.whatsapp ? mudar("botao", "whatsapp") : undefined)}
                titulo="WhatsApp"
                className={resumo && !resumo.whatsapp ? "cursor-not-allowed opacity-55" : ""}
              >
                <span className="flex items-start gap-2.5 text-sm leading-6 text-[var(--ks-color-text-muted)]">
                  <MessageCircle size={17} className="mt-1 shrink-0 text-[var(--ks-brand-600)]" />
                  {resumo && !resumo.whatsapp
                    ? "Cadastre o WhatsApp da loja em Configurações para usar."
                    : "Abre uma conversa com você, com o nome do produto já escrito."}
                </span>
              </Opcao>
              <Opcao selecionada={opcoes.botao === "nenhum"} aoEscolher={() => mudar("botao", "nenhum")} titulo="Sem botão">
                <span className="flex items-start gap-2.5 text-sm leading-6 text-[var(--ks-color-text-muted)]">
                  <SquareDashed size={17} className="mt-1 shrink-0 text-[var(--ks-brand-600)]" />
                  Só para mostrar. Bom para imprimir.
                </span>
              </Opcao>
            </div>
          </Painel>

          <Painel>
            <CabecalhoDoPainel titulo="Capa e páginas" texto="O começo do catálogo e como ele se organiza." />
            <div className="grid gap-5 p-6 md:grid-cols-2">
              <Input
                id="titulo-da-capa"
                label="Selo da capa"
                description="Aparece em destaque em cima da frase. Ex.: Catálogo de Natal."
                value={opcoes.titulo}
                maxLength={LIMITE_DO_TITULO}
                placeholder={`Catálogo ${anoEmSaoPaulo()}`}
                onChange={(evento) => mudar("titulo", evento.target.value)}
              />
              <Input
                id="frase-da-capa"
                label="Frase da capa"
                description="Em branco, vai o slogan da loja."
                value={opcoes.subtitulo}
                maxLength={LIMITE_DO_SUBTITULO}
                placeholder={resumo?.slogan || resumo?.nome || ""}
                onChange={(evento) => mudar("subtitulo", evento.target.value)}
              />
            </div>
            <LinhaDeEscolha
              id="indice"
              titulo="Índice das categorias"
              texto="Uma página com as categorias; tocar numa leva direto a ela. Entra quando o catálogo tem três categorias ou mais."
              ligado={opcoes.indice}
              aoMudar={(valor) => mudar("indice", valor)}
            />
            <LinhaDeEscolha
              id="aberturas"
              titulo="Página de abertura das categorias"
              texto={
                opcoes.formato === "a4"
                  ? "Só no formato celular."
                  : "Uma página com o nome e as fotos da categoria antes dos produtos dela, nas categorias grandes."
              }
              ligado={opcoes.formato === "celular" && opcoes.divisores}
              desativado={opcoes.formato === "a4"}
              aoMudar={(valor) => mudar("divisores", valor)}
            />
          </Painel>
        </fieldset>
      </div>
    </div>
  );
}
