"use client";

import { useEffect, useMemo, useRef, useState, type MouseEvent, type ReactNode } from "react";
import Link from "next/link";
import { ArrowDown, ArrowUp, Info, Plus, X } from "lucide-react";
import { ColorField } from "@/components/ui/color-field";
import { getSupabaseClient } from "@/lib/supabase";
import { getCompanyContext } from "@/lib/company-context";
import { lerLink, type SecaoDoEditor, type Tema } from "@/lib/pagina-inicial";
import {
  LIMITE_DA_FAIXA,
  LIMITE_DA_OFERTA,
  LIMITE_DE_PERGUNTAS,
  LIMITE_DE_PONTOS,
  PROPORCOES_DO_WIDGET,
  instanteDeBrasilia,
  linkDeVideoValido,
  textoDeBrasilia,
  type ModoDoWidget,
  type ProporcaoDoWidget,
} from "@/lib/widgets-da-home";
import {
  Ajuste,
  CampoDeImagem,
  CampoDeLink,
  Chave,
  DesenhoDaProporcao,
  Escolha,
  ListaDeProdutos,
  Miniaturas,
  Segmentos,
  Texto,
  emReais,
  type CategoriaDoEditor,
  type ProdutoDoEditor,
} from "./campos";

/*
  Os ajustes dos blocos novos da página inicial (oferta, cupom, vídeo,
  perguntas...). Mesma regra do resto do painel de ajustes: cada mudança vai
  para o rascunho e a loja ao lado redesenha na hora; nada é gravado até
  "Publicar". O que o bloco lê do banco (cupons, combos, corte, endereço) é
  lido aqui só para escolher e conferir.
*/

type Props = {
  secao: SecaoDoEditor;
  tema: Tema;
  produtos: ProdutoDoEditor[];
  categorias: CategoriaDoEditor[];
  aoMudar: (secao: SecaoDoEditor) => void;
  /* Os pedaços que o painel de ajustes já monta (título e espaço). */
  titulo: ReactNode;
  margem: ReactNode;
};

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

function Nota({ children, tom = "neutro" }: { children: ReactNode; tom?: "neutro" | "alerta" }) {
  return (
    <div className="border-t border-[var(--ks-n-100)] px-5 py-4 first:border-t-0">
      <div
        className={`flex gap-2.5 rounded-xl px-3 py-2.5 text-[12px] leading-[1.5] ${
          tom === "alerta" ? "bg-amber-50 text-amber-900" : "bg-[var(--ks-brand-50)] text-[var(--ks-brand-800,#3b2393)]"
        }`}
      >
        <Info size={15} className="mt-0.5 shrink-0" />
        <div className="min-w-0">{children}</div>
      </div>
    </div>
  );
}

function AreaDeTexto({ valor, aoMudar, placeholder, max = 1500, linhas = 4, rotulo }: { valor: string; aoMudar: (v: string) => void; placeholder?: string; max?: number; linhas?: number; rotulo?: string }) {
  return (
    <textarea
      value={valor}
      rows={linhas}
      aria-label={rotulo}
      onChange={(e) => aoMudar(e.target.value.slice(0, max))}
      placeholder={placeholder}
      className="w-full resize-y rounded-xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-elevated)] px-3 py-2.5 text-[13px] leading-[1.5] text-[var(--ks-color-text-primary)] outline-none transition placeholder:text-[var(--ks-color-text-soft)] focus:border-[var(--ks-color-primary)] focus:shadow-[var(--ks-focus-ring)]"
    />
  );
}

function BotaoPequeno({ titulo, onClick, children, perigo, desligado }: { titulo: string; onClick: () => void; children: ReactNode; perigo?: boolean; desligado?: boolean }) {
  return (
    <button
      type="button"
      title={titulo}
      aria-label={titulo}
      disabled={desligado}
      onClick={onClick}
      className={`flex h-7 w-7 items-center justify-center rounded-lg text-[var(--ks-color-text-soft)] transition disabled:opacity-30 ${
        perigo ? "hover:bg-rose-50 hover:text-rose-600" : "hover:bg-[var(--ks-color-bg-hover)] hover:text-[var(--ks-color-primary)]"
      }`}
    >
      {children}
    </button>
  );
}

function BotaoDeAdicionar({ onClick, children }: { onClick: () => void; children: ReactNode }) {
  return (
    <button type="button" onClick={onClick} className="inline-flex items-center gap-1 text-[12px] font-bold text-[var(--ks-color-primary)] hover:underline">
      <Plus size={14} /> {children}
    </button>
  );
}

const DICA_DO_TEXTO = (
  <>
    Use <b>**negrito**</b>, <b>[texto do link](https://...)</b> e linhas começando com <b>- </b> para lista. Linha em branco separa parágrafos.
  </>
);

/* Os dados da empresa que só alguns blocos leem, uma vez por abertura. */
function useDaEmpresa<T>(ler: (supabase: ReturnType<typeof getSupabaseClient>, dono: string) => Promise<T>, inicial: T) {
  const [valor, setValor] = useState<T>(inicial);
  const [lido, setLido] = useState(false);
  const leitura = useRef(ler);
  useEffect(() => {
    let vivo = true;
    (async () => {
      try {
        const supabase = getSupabaseClient();
        const {
          data: { user },
        } = await supabase.auth.getUser();
        if (!user) return;
        const ctx = await getCompanyContext(supabase, user);
        const resultado = await leitura.current(supabase, ctx.ownerId ?? user.id);
        if (vivo) setValor(resultado);
      } catch {
        /* sem leitura: o bloco mostra o que tiver */
      } finally {
        if (vivo) setLido(true);
      }
    })();
    return () => {
      vivo = false;
    };
  }, []);
  return { valor, lido };
}

type Cupom = { id: string; code: string; type: string; value: number; min_total: number | null; active: boolean; starts_at: string | null; ends_at: string | null };
type Combo = { id: string; title: string | null; main_product_id: string; combo_product_id: string; discount_type: string; discount_value: number };

function descontoDoCupom(c: Cupom) {
  if (c.type === "free_shipping") return "Frete grátis";
  return c.type === "percent" ? `${Number(c.value).toLocaleString("pt-BR")}% OFF` : `${emReais(Number(c.value))} OFF`;
}

function situacaoDoCupom(c: Cupom) {
  const agora = Date.now();
  if (!c.active) return "desligado";
  if (c.starts_at && new Date(c.starts_at).getTime() > agora) return "ainda não começou";
  if (c.ends_at && new Date(c.ends_at).getTime() <= agora) return "vencido";
  return null;
}

/* -------------------------------------------------- os ajustes */

export function AjustesDoWidget({ secao, produtos, categorias, aoMudar, titulo, margem }: Props) {
  const c = secao.config;
  const modo = secao.modo as ModoDoWidget;
  const mudarConfig = (parcial: Record<string, unknown>) => aoMudar({ ...secao, config: { ...secao.config, ...parcial } });
  const texto = (chave: string) => String(c[chave] ?? "");

  switch (modo) {
    case "flash_offer": {
      const ids = Array.isArray(c.produtos) ? (c.produtos as string[]) : [];
      const fim = instanteDeBrasilia(c.termina_em);
      return (
        <>
          <Nota>
            Os produtos não têm preço promocional no cadastro, então a oferta mostra o <b>preço de verdade</b>, com o selo e o relógio. Para dar desconto de fato, baixe o preço do produto (ou crie um cupom) durante a oferta. Quando o relógio zera, o bloco some da loja sozinho.
          </Nota>
          {titulo}
          <Ajuste rotulo="Termina em" dica="Hora de Brasília.">
            <input
              type="datetime-local"
              value={texto("termina_em")}
              onChange={(e) => mudarConfig({ termina_em: e.target.value })}
              aria-label="Data e hora do fim da oferta"
              className="h-[38px] w-full rounded-xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-elevated)] px-3 text-[13px] text-[var(--ks-color-text-primary)] outline-none focus:border-[var(--ks-color-primary)]"
            />
            {fim !== null && fim <= Date.now() ? <p className="mt-2 text-[11.5px] font-semibold text-[var(--ks-color-status-danger)]">Essa hora já passou: a oferta não aparece na loja.</p> : null}
            <div className="mt-2 flex flex-wrap gap-1.5">
              {[
                { rotulo: "Hoje 23:59", valor: () => `${textoDeBrasilia(Date.now()).slice(0, 11)}23:59` },
                { rotulo: "+24 h", valor: () => textoDeBrasilia(Date.now() + 24 * 3600 * 1000) },
                { rotulo: "+3 dias", valor: () => textoDeBrasilia(Date.now() + 72 * 3600 * 1000) },
              ].map((atalho) => (
                <button
                  key={atalho.rotulo}
                  type="button"
                  onClick={() => mudarConfig({ termina_em: atalho.valor() })}
                  className="rounded-full bg-[var(--ks-color-bg-inset)] px-2.5 py-1 text-[11px] font-bold text-[var(--ks-color-text-secondary)] hover:text-[var(--ks-color-primary)]"
                >
                  {atalho.rotulo}
                </button>
              ))}
            </div>
          </Ajuste>
          <Ajuste rotulo={`Produtos (${ids.length} de ${LIMITE_DA_OFERTA})`}>
            <ListaDeProdutos ids={ids} aoMudar={(novos) => mudarConfig({ produtos: novos })} produtos={produtos} limite={LIMITE_DA_OFERTA} />
          </Ajuste>
          <Ajuste rotulo="Selo e frase">
            <div className="space-y-2">
              <Texto valor={texto("selo")} aoMudar={(v) => mudarConfig({ selo: v })} placeholder="Selo (ex.: Oferta, Só hoje)" max={30} rotulo="Selo" />
              <Texto valor={texto("subtitulo")} aoMudar={(v) => mudarConfig({ subtitulo: v })} placeholder="Frase de apoio (opcional)" max={140} rotulo="Frase de apoio" />
            </div>
          </Ajuste>
          {margem}
        </>
      );
    }

    case "coupon_highlight":
      return <AjustesDoCupom secao={secao} mudarConfig={mudarConfig} titulo={titulo} margem={margem} />;

    case "order_cutoff":
      return <AjustesDoCorte secao={secao} mudarConfig={mudarConfig} margem={margem} />;

    case "next_live":
      return (
        <>
          <Nota>
            Mostra a próxima live de venda com &quot;Mostrar na vitrine&quot; ligado (Produtos digitais &gt; Lives), com a contagem até começar. No ar, o botão vira <b>Entrar agora</b>. Sem live marcada, o bloco some (ou mostra o recado abaixo).
          </Nota>
          {titulo}
          <Chave ligada={c.mostrar_sem_live === true} aoMudar={(v) => mudarConfig({ mostrar_sem_live: v })} rotulo="Mostrar um recado quando não tiver live" />
          {c.mostrar_sem_live === true ? (
            <Ajuste rotulo="Recado">
              <Texto valor={texto("mensagem_sem_live")} aoMudar={(v) => mudarConfig({ mensagem_sem_live: v })} placeholder="Fique de olho: logo tem live nova por aqui." max={140} />
            </Ajuste>
          ) : null}
          {margem}
        </>
      );

    case "auto_list": {
      const lista = c.lista === "mais_vendidos" ? "mais_vendidos" : "lancamentos";
      return (
        <>
          <Ajuste rotulo="Qual lista">
            <Segmentos
              rotulo="Qual lista"
              valor={lista}
              aoMudar={(v) =>
                aoMudar({
                  ...secao,
                  title: !secao.title || secao.title === "Lançamentos" || secao.title === "Mais vendidos" ? (v === "mais_vendidos" ? "Mais vendidos" : "Lançamentos") : secao.title,
                  config: { ...secao.config, lista: v },
                })
              }
              opcoes={[
                { valor: "lancamentos", rotulo: "Lançamentos" },
                { valor: "mais_vendidos", rotulo: "Mais vendidos" },
              ]}
            />
          </Ajuste>
          <Nota>
            {lista === "mais_vendidos"
              ? "Conta as vendas de verdade: a soma das quantidades nos pedidos da loja no período, sem os cancelados. Atualiza sozinha (a loja refaz a conta a cada 2 minutos)."
              : "Os produtos cadastrados mais recentemente, entre os que estão à mostra na loja."}
            {" "}
            Não existe preço promocional no cadastro dos produtos, por isso não há a lista “Em promoção”.
          </Nota>
          {lista === "mais_vendidos" ? (
            <Ajuste rotulo="Vendas de quantos dias">
              <Segmentos
                rotulo="Vendas de quantos dias"
                valor={String(Number(c.dias) || 30)}
                aoMudar={(v) => mudarConfig({ dias: Number(v) })}
                opcoes={[
                  { valor: "7", rotulo: "7 dias" },
                  { valor: "30", rotulo: "30 dias" },
                  { valor: "90", rotulo: "90 dias" },
                ]}
              />
            </Ajuste>
          ) : null}
          <Ajuste rotulo="Quantos produtos">
            <Segmentos
              rotulo="Quantos produtos"
              valor={String(Number(c.quantidade) || 8)}
              aoMudar={(v) => mudarConfig({ quantidade: Number(v) })}
              opcoes={[4, 8, 12].map((n) => ({ valor: String(n), rotulo: String(n) }))}
            />
          </Ajuste>
          {titulo}
        </>
      );
    }

    case "combo_highlight":
      return <AjustesDosKits secao={secao} produtos={produtos} mudarConfig={mudarConfig} titulo={titulo} margem={margem} />;

    case "recently_viewed":
      return (
        <>
          <Nota>
            Os últimos produtos que <b>cada visitante</b> abriu, guardados só no navegador dele (nada vai para o servidor). Quem chega pela primeira vez não vê o bloco.
          </Nota>
          {titulo}
          <Ajuste rotulo="Quantos produtos">
            <Segmentos
              rotulo="Quantos produtos"
              valor={String(Number(c.quantidade) || 8)}
              aoMudar={(v) => mudarConfig({ quantidade: Number(v) })}
              opcoes={[4, 8, 12].map((n) => ({ valor: String(n), rotulo: String(n) }))}
            />
          </Ajuste>
          {margem}
        </>
      );

    case "video_section": {
      const url = texto("url");
      return (
        <>
          <Ajuste rotulo="Link do vídeo" dica="YouTube ou Vimeo. O vídeo só carrega quando o cliente toca no play (a página fica leve) e sem os rastreadores do YouTube.">
            <Texto valor={url} aoMudar={(v) => mudarConfig({ url: v.trim() })} placeholder="https://www.youtube.com/watch?v=..." max={500} rotulo="Link do vídeo" />
            {url && !linkDeVideoValido(url) ? <p className="mt-2 text-[11.5px] font-semibold text-[var(--ks-color-status-danger)]">Esse link não é de um vídeo do YouTube ou do Vimeo.</p> : null}
          </Ajuste>
          {titulo}
          <Ajuste rotulo="Onde fica o texto">
            <Segmentos
              rotulo="Onde fica o texto"
              valor={String(c.lado || "inteiro")}
              aoMudar={(v) => mudarConfig({ lado: v })}
              opcoes={[
                { valor: "inteiro", rotulo: "Embaixo" },
                { valor: "esquerda", rotulo: "À direita" },
                { valor: "direita", rotulo: "À esquerda" },
              ]}
            />
          </Ajuste>
          <Ajuste rotulo="Texto" dica={DICA_DO_TEXTO}>
            <AreaDeTexto valor={texto("texto")} aoMudar={(v) => mudarConfig({ texto: v })} placeholder="Conte o que o vídeo mostra (opcional)" max={600} rotulo="Texto do vídeo" />
          </Ajuste>
          <Ajuste rotulo="Capa" dica="Opcional. Sem capa, o YouTube manda a dele; o Vimeo fica com a cor da loja.">
            <CampoDeImagem valor={texto("capa")} aoMudar={(v) => mudarConfig({ capa: v })} proporcao={16 / 9} largura={1280} altura={720} />
          </Ajuste>
          {margem}
        </>
      );
    }

    case "text_image": {
      const proporcao = (["quadrado", "retrato", "paisagem"].includes(texto("proporcao")) ? texto("proporcao") : "quadrado") as ProporcaoDoWidget;
      const medida = PROPORCOES_DO_WIDGET[proporcao];
      return (
        <>
          <Ajuste rotulo="Imagem">
            <CampoDeImagem valor={texto("imagem")} aoMudar={(v) => mudarConfig({ imagem: v })} proporcao={medida.proporcao} largura={medida.largura} altura={medida.altura} />
          </Ajuste>
          <Ajuste rotulo="Formato da imagem">
            <Miniaturas<ProporcaoDoWidget>
              valor={proporcao}
              colunas={3}
              aoMudar={(v) => mudarConfig({ proporcao: v })}
              opcoes={(["quadrado", "retrato", "paisagem"] as ProporcaoDoWidget[]).map((chave) => ({
                valor: chave,
                nome: PROPORCOES_DO_WIDGET[chave].nome,
                detalhe: PROPORCOES_DO_WIDGET[chave].medida,
                desenho: <DesenhoDaProporcao proporcao={PROPORCOES_DO_WIDGET[chave].proporcao} />,
              }))}
            />
          </Ajuste>
          <Ajuste rotulo="Lado da imagem">
            <Segmentos
              rotulo="Lado da imagem"
              valor={texto("lado") === "direita" ? "direita" : "esquerda"}
              aoMudar={(v) => mudarConfig({ lado: v })}
              opcoes={[
                { valor: "esquerda", rotulo: "Imagem à esquerda" },
                { valor: "direita", rotulo: "Imagem à direita" },
              ]}
            />
          </Ajuste>
          <Ajuste rotulo="Chamada" dica="A linha pequena e colorida em cima do título (opcional).">
            <Texto valor={texto("chamada")} aoMudar={(v) => mudarConfig({ chamada: v })} placeholder="Ex.: Feito à mão desde 2012" max={60} />
          </Ajuste>
          {titulo}
          <Ajuste rotulo="Texto" dica={DICA_DO_TEXTO}>
            <AreaDeTexto valor={texto("texto")} aoMudar={(v) => mudarConfig({ texto: v })} placeholder="Escreva o texto" max={2000} linhas={6} rotulo="Texto" />
          </Ajuste>
          <Ajuste rotulo="Botão" dica="Opcional. Sem texto, não aparece.">
            <div className="space-y-2.5">
              <Texto valor={texto("botao_texto")} aoMudar={(v) => mudarConfig({ botao_texto: v })} placeholder="Texto do botão (ex.: Conheça a loja)" max={30} />
              {texto("botao_texto") ? (
                <CampoDeLink link={lerLink(c.botao_link)} aoMudar={(link) => mudarConfig({ botao_link: link })} produtos={produtos} categorias={categorias} />
              ) : null}
            </div>
          </Ajuste>
          {margem}
        </>
      );
    }

    case "faq": {
      const itens = (Array.isArray(c.itens) ? (c.itens as Array<{ pergunta?: string; resposta?: string }>) : []).slice(0, LIMITE_DE_PERGUNTAS);
      const mudarItens = (novos: typeof itens) => mudarConfig({ itens: novos.slice(0, LIMITE_DE_PERGUNTAS) });
      return (
        <>
          {titulo}
          <Ajuste
            rotulo={`Perguntas (${itens.length} de ${LIMITE_DE_PERGUNTAS})`}
            direita={itens.length < LIMITE_DE_PERGUNTAS ? <BotaoDeAdicionar onClick={() => mudarItens([...itens, { pergunta: "", resposta: "" }])}>Pergunta</BotaoDeAdicionar> : null}
            dica={<>As perguntas também vão para o Google (dados estruturados de perguntas frequentes). {DICA_DO_TEXTO}</>}
          >
            <div className="space-y-3">
              {itens.map((item, indice) => (
                <div key={indice} data-bloco={indice} className="rounded-xl border border-[var(--ks-color-border-subtle)] p-3">
                  <div className="mb-2 flex items-center justify-between">
                    <span className="text-[11px] font-bold uppercase tracking-[0.12em] text-[var(--ks-color-text-soft)]">Pergunta {indice + 1}</span>
                    <span className="flex">
                      <BotaoPequeno titulo="Subir" desligado={indice === 0} onClick={() => mudarItens(trocar(itens, indice, indice - 1))}>
                        <ArrowUp size={14} />
                      </BotaoPequeno>
                      <BotaoPequeno titulo="Descer" desligado={indice === itens.length - 1} onClick={() => mudarItens(trocar(itens, indice, indice + 1))}>
                        <ArrowDown size={14} />
                      </BotaoPequeno>
                      <BotaoPequeno titulo="Tirar" perigo onClick={() => mudarItens(itens.filter((_, i) => i !== indice))}>
                        <X size={14} />
                      </BotaoPequeno>
                    </span>
                  </div>
                  <div className="space-y-2">
                    <Texto valor={item.pergunta || ""} aoMudar={(v) => mudarItens(itens.map((x, i) => (i === indice ? { ...x, pergunta: v } : x)))} placeholder="A pergunta (ex.: Qual o prazo de entrega?)" max={200} />
                    <AreaDeTexto valor={item.resposta || ""} aoMudar={(v) => mudarItens(itens.map((x, i) => (i === indice ? { ...x, resposta: v } : x)))} placeholder="A resposta" max={1500} linhas={3} />
                  </div>
                </div>
              ))}
              {!itens.length ? (
                <p className="rounded-xl bg-[var(--ks-color-bg-inset)] px-3 py-4 text-center text-[12px] text-[var(--ks-color-text-soft)]">Toque em &quot;Pergunta&quot; para escrever a primeira.</p>
              ) : null}
            </div>
          </Ajuste>
          <Chave ligada={c.abrir_primeira === true} aoMudar={(v) => mudarConfig({ abrir_primeira: v })} rotulo="Primeira pergunta já aberta" />
          {margem}
        </>
      );
    }

    case "store_location":
      return <AjustesDoLocal secao={secao} mudarConfig={mudarConfig} titulo={titulo} margem={margem} />;

    case "marquee": {
      const itens = (Array.isArray(c.itens) ? (c.itens as string[]) : []).slice(0, LIMITE_DA_FAIXA);
      const mudarItens = (novos: string[]) => mudarConfig({ itens: novos.slice(0, LIMITE_DA_FAIXA) });
      return (
        <>
          <Ajuste
            rotulo={`Frases (${itens.length} de ${LIMITE_DA_FAIXA})`}
            direita={itens.length < LIMITE_DA_FAIXA ? <BotaoDeAdicionar onClick={() => mudarItens([...itens, ""])}>Frase</BotaoDeAdicionar> : null}
            dica="Passam uma atrás da outra, separadas por •. Quem pediu menos movimento no aparelho vê a faixa parada."
          >
            <div className="space-y-2">
              {itens.map((item, indice) => (
                <div key={indice} className="flex items-center gap-1.5">
                  <div className="min-w-0 flex-1">
                    <Texto valor={item} aoMudar={(v) => mudarItens(itens.map((x, i) => (i === indice ? v : x)))} placeholder="Ex.: Frete grátis acima de R$ 199" max={80} rotulo={`Frase ${indice + 1}`} />
                  </div>
                  <BotaoPequeno titulo="Tirar a frase" perigo onClick={() => mudarItens(itens.filter((_, i) => i !== indice))}>
                    <X size={14} />
                  </BotaoPequeno>
                </div>
              ))}
            </div>
          </Ajuste>
          <Ajuste rotulo="Velocidade">
            <Segmentos
              rotulo="Velocidade"
              valor={String(c.velocidade || "normal")}
              aoMudar={(v) => mudarConfig({ velocidade: v })}
              opcoes={[
                { valor: "devagar", rotulo: "Devagar" },
                { valor: "normal", rotulo: "Normal" },
                { valor: "rapido", rotulo: "Rápida" },
              ]}
            />
          </Ajuste>
          <Ajuste rotulo="Tamanho da letra">
            <Segmentos
              rotulo="Tamanho da letra"
              valor={String(c.tamanho || "m")}
              aoMudar={(v) => mudarConfig({ tamanho: v })}
              opcoes={[
                { valor: "p", rotulo: "P" },
                { valor: "m", rotulo: "M" },
                { valor: "g", rotulo: "G" },
              ]}
            />
          </Ajuste>
          <Ajuste rotulo="Cores" dica="Fundo vazio usa a cor da loja.">
            <div className="grid grid-cols-1 gap-2.5">
              <ColorField label="Fundo" value={texto("cor_de_fundo")} onChange={(v) => mudarConfig({ cor_de_fundo: v })} fallback="#7346E8" />
              <ColorField label="Texto" value={texto("cor_do_texto")} onChange={(v) => mudarConfig({ cor_do_texto: v })} allowAuto={false} />
            </div>
          </Ajuste>
        </>
      );
    }

    case "shoppable_image":
      return <AjustesDosPontos secao={secao} produtos={produtos} mudarConfig={mudarConfig} titulo={titulo} margem={margem} />;

    case "before_after": {
      const proporcao = (Object.keys(PROPORCOES_DO_WIDGET).includes(texto("proporcao")) ? texto("proporcao") : "paisagem") as ProporcaoDoWidget;
      const medida = PROPORCOES_DO_WIDGET[proporcao];
      return (
        <>
          {titulo}
          <Ajuste rotulo="Formato">
            <Miniaturas<ProporcaoDoWidget>
              valor={proporcao}
              colunas={4}
              aoMudar={(v) => mudarConfig({ proporcao: v })}
              opcoes={(Object.keys(PROPORCOES_DO_WIDGET) as ProporcaoDoWidget[]).map((chave) => ({
                valor: chave,
                nome: PROPORCOES_DO_WIDGET[chave].nome,
                detalhe: PROPORCOES_DO_WIDGET[chave].medida,
                desenho: <DesenhoDaProporcao proporcao={PROPORCOES_DO_WIDGET[chave].proporcao} />,
              }))}
            />
          </Ajuste>
          <Ajuste rotulo="Antes" dica="Use duas fotos do mesmo ângulo, recortadas no mesmo formato.">
            <div className="space-y-2">
              <CampoDeImagem valor={texto("antes")} aoMudar={(v) => mudarConfig({ antes: v })} proporcao={medida.proporcao} largura={medida.largura} altura={medida.altura} />
              <Texto valor={texto("rotulo_antes")} aoMudar={(v) => mudarConfig({ rotulo_antes: v })} placeholder="Antes" max={24} rotulo="Nome da foto de antes" />
            </div>
          </Ajuste>
          <Ajuste rotulo="Depois">
            <div className="space-y-2">
              <CampoDeImagem valor={texto("depois")} aoMudar={(v) => mudarConfig({ depois: v })} proporcao={medida.proporcao} largura={medida.largura} altura={medida.altura} />
              <Texto valor={texto("rotulo_depois")} aoMudar={(v) => mudarConfig({ rotulo_depois: v })} placeholder="Depois" max={24} rotulo="Nome da foto de depois" />
            </div>
          </Ajuste>
          <Ajuste rotulo="Onde a barra começa">
            <Segmentos
              rotulo="Onde a barra começa"
              valor={String(Number(c.inicio) || 50)}
              aoMudar={(v) => mudarConfig({ inicio: Number(v) })}
              opcoes={[
                { valor: "25", rotulo: "Mais antes" },
                { valor: "50", rotulo: "No meio" },
                { valor: "75", rotulo: "Mais depois" },
              ]}
            />
          </Ajuste>
          {margem}
        </>
      );
    }
  }
}

function trocar<T>(lista: T[], de: number, para: number): T[] {
  if (para < 0 || para >= lista.length) return lista;
  const nova = [...lista];
  [nova[de], nova[para]] = [nova[para], nova[de]];
  return nova;
}

/* ---------------------------------------------------------- cupom */

function AjustesDoCupom({ secao, mudarConfig, titulo, margem }: { secao: SecaoDoEditor; mudarConfig: (p: Record<string, unknown>) => void; titulo: ReactNode; margem: ReactNode }) {
  const c = secao.config;
  const { valor: cupons, lido } = useDaEmpresa<Cupom[]>(async (supabase, dono) => {
    const { data } = await supabase.from("catalog_coupons").select("id,code,type,value,min_total,active,starts_at,ends_at").eq("user_id", dono).order("created_at", { ascending: false }).limit(100);
    return (data || []) as Cupom[];
  }, []);
  const escolhido = cupons.find((x) => x.id === c.cupom_id) || null;
  const situacao = escolhido ? situacaoDoCupom(escolhido) : null;
  return (
    <>
      <Ajuste rotulo="Cupom" dica={<>Os cupons ficam em <Link href="/dashboard/catalog/products?aba=cupons" className="font-semibold underline">Catálogo &gt; Produtos &gt; Cupons</Link>.</>}>
        <Escolha
          valor={String(c.cupom_id || "")}
          itens={cupons}
          aoEscolher={(cupom) => mudarConfig({ cupom_id: cupom.id })}
          textoDoItem={(cupom) => cupom.code}
          detalheDoItem={(cupom) => `${descontoDoCupom(cupom)}${cupom.min_total ? ` · a partir de ${emReais(Number(cupom.min_total))}` : ""}${situacaoDoCupom(cupom) ? ` · ${situacaoDoCupom(cupom)}` : ""}`}
          placeholder={lido && !cupons.length ? "A loja ainda não tem cupom" : "Escolher o cupom"}
          vazio="Nenhum cupom com esse código."
        />
        {situacao ? <p className="mt-2 text-[11.5px] font-semibold text-amber-700">Este cupom está {situacao}: na loja, o bloco só aparece enquanto ele vale.</p> : null}
      </Ajuste>
      <Ajuste rotulo="Frase" dica="Aparece ao lado do código.">
        <Texto valor={String(c.chamada ?? "")} aoMudar={(v) => mudarConfig({ chamada: v })} placeholder="Ex.: Use na sua primeira compra" max={120} />
      </Ajuste>
      <Chave ligada={c.mostrar_validade !== false} aoMudar={(v) => mudarConfig({ mostrar_validade: v })} rotulo="Mostrar até quando vale" />
      {titulo}
      {margem}
    </>
  );
}

/* ----------------------------------------------------------- corte */

function AjustesDoCorte({ secao, mudarConfig, margem }: { secao: SecaoDoEditor; mudarConfig: (p: Record<string, unknown>) => void; margem: ReactNode }) {
  const c = secao.config;
  const { valor: corte, lido } = useDaEmpresa<{ ligado: boolean; hora: string | null }>(async (supabase, dono) => {
    const { data } = await supabase.from("profiles").select("production_cutoff_enabled,production_cutoff_time").eq("id", dono).maybeSingle();
    const linha = data as { production_cutoff_enabled?: boolean; production_cutoff_time?: string | null } | null;
    return { ligado: linha?.production_cutoff_enabled === true, hora: linha?.production_cutoff_time || null };
  }, { ligado: false, hora: null });
  return (
    <>
      {lido ? (
        corte.ligado && corte.hora ? (
          <Nota>
            O corte da loja é às <b>{corte.hora}</b>, de segunda a sexta (horário de Brasília). Antes dele o bloco mostra o tempo que falta; depois, avisa que o pedido entra no lote do próximo dia útil. A hora muda em{" "}
            <Link href="/dashboard/catalog" className="font-semibold underline">Catálogo &gt; Personalização &gt; Corte de produção</Link>.
          </Nota>
        ) : (
          <Nota tom="alerta">
            O corte de produção está desligado: o bloco não aparece na loja. Ligue e escolha a hora em{" "}
            <Link href="/dashboard/catalog" className="font-semibold underline">Catálogo &gt; Personalização &gt; Corte de produção</Link>.
          </Nota>
        )
      ) : null}
      <Ajuste rotulo="Frase (antes do corte)" dica={`Vazio usa: "Peça até as ${corte.hora || "16:00"} e o seu pedido entra na produção de hoje".`}>
        <div className="space-y-2">
          <Texto valor={String(c.frase ?? "")} aoMudar={(v) => mudarConfig({ frase: v })} placeholder="Frase principal (opcional)" max={120} />
          <Texto valor={String(c.destaque ?? "")} aoMudar={(v) => mudarConfig({ destaque: v })} placeholder="Linha de baixo (opcional)" max={60} />
        </div>
      </Ajuste>
      {margem}
    </>
  );
}

/* ------------------------------------------------------------ kits */

function AjustesDosKits({ secao, produtos, mudarConfig, titulo, margem }: { secao: SecaoDoEditor; produtos: ProdutoDoEditor[]; mudarConfig: (p: Record<string, unknown>) => void; titulo: ReactNode; margem: ReactNode }) {
  const c = secao.config;
  const { valor: combos, lido } = useDaEmpresa<Combo[]>(async (supabase, dono) => {
    const { data } = await supabase.from("product_combos").select("id,title,main_product_id,combo_product_id,discount_type,discount_value").eq("user_id", dono).eq("active", true).order("created_at", { ascending: false }).limit(200);
    return (data || []) as Combo[];
  }, []);
  const porId = useMemo(() => new Map(produtos.map((p) => [p.id, p])), [produtos]);
  const escolhidos = Array.isArray(c.combos) ? (c.combos as string[]) : [];
  const visiveis = combos.filter((k) => porId.has(k.main_product_id) && porId.has(k.combo_product_id));
  const alternar = (id: string) => mudarConfig({ combos: escolhidos.includes(id) ? escolhidos.filter((x) => x !== id) : [...escolhidos, id] });
  return (
    <>
      <Nota>
        Os kits saem do <b>Compre junto</b> de cada produto (editar o produto &gt; Compre junto). O clique leva ao produto principal, onde o cliente leva os dois com o desconto do combo.
      </Nota>
      {titulo}
      <Ajuste rotulo="Quantos kits">
        <Segmentos
          rotulo="Quantos kits"
          valor={String(Number(c.quantidade) || 6)}
          aoMudar={(v) => mudarConfig({ quantidade: Number(v) })}
          opcoes={[3, 6, 9].map((n) => ({ valor: String(n), rotulo: String(n) }))}
        />
      </Ajuste>
      <Ajuste rotulo="Quais kits" dica={escolhidos.length ? "Só os marcados, nesta ordem." : "Nenhum marcado: entram todos, os mais novos primeiro."}>
        {lido && !visiveis.length ? (
          <p className="rounded-xl bg-[var(--ks-color-bg-inset)] px-3 py-4 text-center text-[12px] text-[var(--ks-color-text-soft)]">A loja ainda não tem “compre junto” com os dois produtos à mostra.</p>
        ) : (
          <div className="max-h-72 space-y-1 overflow-y-auto">
            {visiveis.map((k) => {
              const marcado = escolhidos.includes(k.id);
              const a = porId.get(k.main_product_id);
              const b = porId.get(k.combo_product_id);
              return (
                <label key={k.id} className="flex cursor-pointer items-center gap-2.5 rounded-xl px-2 py-1.5 hover:bg-[var(--ks-color-bg-hover)]">
                  <input type="checkbox" checked={marcado} onChange={() => alternar(k.id)} className="h-4 w-4 shrink-0 accent-[var(--ks-color-primary)]" />
                  <span className="min-w-0 flex-1">
                    <span className="block truncate text-[12.5px] font-semibold text-[var(--ks-color-text-primary)]">
                      {a?.name} + {b?.name}
                    </span>
                    <span className="block truncate text-[11px] text-[var(--ks-color-text-soft)]">
                      {k.title || "Compre junto"}
                      {k.discount_type !== "none" && Number(k.discount_value) > 0 ? ` · ${k.discount_type === "percentage" ? `${Number(k.discount_value)}%` : emReais(Number(k.discount_value))} no segundo` : ""}
                    </span>
                  </span>
                  {marcado ? <span className="text-[11px] font-bold tabular-nums text-[var(--ks-color-primary)]">{escolhidos.indexOf(k.id) + 1}</span> : null}
                </label>
              );
            })}
          </div>
        )}
      </Ajuste>
      {margem}
    </>
  );
}

/* ---------------------------------------------------- onde estamos */

function AjustesDoLocal({ secao, mudarConfig, titulo, margem }: { secao: SecaoDoEditor; mudarConfig: (p: Record<string, unknown>) => void; titulo: ReactNode; margem: ReactNode }) {
  const c = secao.config;
  const { valor: endereco } = useDaEmpresa<string>(async (supabase, dono) => {
    const { data } = await supabase
      .from("profiles")
      .select("address_street,address_number,address_neighborhood,address_city,address_state,address")
      .eq("id", dono)
      .maybeSingle();
    const p = (data || {}) as Record<string, string | null>;
    const rua = [p.address_street, p.address_number].filter(Boolean).join(", ");
    const resto = [p.address_neighborhood, [p.address_city, p.address_state].filter(Boolean).join(" - ")].filter(Boolean).join(", ");
    return [rua, resto].filter(Boolean).join(" · ") || String(p.address || "");
  }, "");
  const daEmpresa = c.usar_endereco_da_loja !== false;
  return (
    <>
      {titulo}
      <Chave ligada={daEmpresa} aoMudar={(v) => mudarConfig({ usar_endereco_da_loja: v })} rotulo="Usar o endereço da empresa" dica={daEmpresa ? endereco || "A empresa ainda não tem endereço: preencha em Catálogo > Personalização > Rodapé." : undefined} />
      {!daEmpresa ? (
        <Ajuste rotulo="Endereço" dica="Uma linha por parte (rua e número, bairro e cidade...). É o que o mapa procura.">
          <AreaDeTexto valor={String(c.endereco ?? "")} aoMudar={(v) => mudarConfig({ endereco: v })} placeholder={"Rua das Flores, 120\nCentro, Campinas - SP"} max={300} linhas={3} />
        </Ajuste>
      ) : null}
      <Ajuste rotulo="Horários" dica="Uma linha por horário. Vazio não mostra.">
        <AreaDeTexto valor={String(c.horarios ?? "")} aoMudar={(v) => mudarConfig({ horarios: v })} placeholder={"Segunda a sexta, das 9h às 18h"} max={400} linhas={3} />
      </Ajuste>
      <Chave ligada={c.mostrar_mapa !== false} aoMudar={(v) => mudarConfig({ mostrar_mapa: v })} rotulo="Mostrar o mapa" dica="Mapa do Google, carregado só quando o cliente chega nele. O botão Traçar rota abre o Google Maps." />
      <Chave ligada={c.mostrar_retiradas === true} aoMudar={(v) => mudarConfig({ mostrar_retiradas: v })} rotulo="Listar os pontos de retirada" />
      {margem}
    </>
  );
}

/* --------------------------------------------- imagem com pontos */

function AjustesDosPontos({ secao, produtos, mudarConfig, titulo, margem }: { secao: SecaoDoEditor; produtos: ProdutoDoEditor[]; mudarConfig: (p: Record<string, unknown>) => void; titulo: ReactNode; margem: ReactNode }) {
  const c = secao.config;
  const proporcao = (Object.keys(PROPORCOES_DO_WIDGET).includes(String(c.proporcao)) ? String(c.proporcao) : "paisagem") as ProporcaoDoWidget;
  const medida = PROPORCOES_DO_WIDGET[proporcao];
  const pontos = (Array.isArray(c.pontos) ? (c.pontos as Array<{ x: number; y: number; produto_id?: string }>) : []).slice(0, LIMITE_DE_PONTOS);
  const [escolhido, setEscolhido] = useState<number | null>(null);
  const imagem = String(c.imagem || "");
  const mudarPontos = (novos: typeof pontos) => mudarConfig({ pontos: novos.slice(0, LIMITE_DE_PONTOS) });

  const marcar = (evento: MouseEvent<HTMLDivElement>) => {
    if (pontos.length >= LIMITE_DE_PONTOS) return;
    const area = evento.currentTarget.getBoundingClientRect();
    const x = Math.round(((evento.clientX - area.left) / area.width) * 1000) / 10;
    const y = Math.round(((evento.clientY - area.top) / area.height) * 1000) / 10;
    mudarPontos([...pontos, { x: Math.min(100, Math.max(0, x)), y: Math.min(100, Math.max(0, y)), produto_id: "" }]);
    setEscolhido(pontos.length);
  };

  return (
    <>
      {titulo}
      <Ajuste rotulo="Formato">
        <Miniaturas<ProporcaoDoWidget>
          valor={proporcao}
          colunas={4}
          aoMudar={(v) => mudarConfig({ proporcao: v })}
          opcoes={(Object.keys(PROPORCOES_DO_WIDGET) as ProporcaoDoWidget[]).map((chave) => ({
            valor: chave,
            nome: PROPORCOES_DO_WIDGET[chave].nome,
            detalhe: PROPORCOES_DO_WIDGET[chave].medida,
            desenho: <DesenhoDaProporcao proporcao={PROPORCOES_DO_WIDGET[chave].proporcao} />,
          }))}
        />
      </Ajuste>
      <Ajuste rotulo="Imagem">
        <CampoDeImagem valor={imagem} aoMudar={(v) => mudarConfig({ imagem: v })} proporcao={medida.proporcao} largura={medida.largura} altura={medida.altura} />
      </Ajuste>
      {imagem ? (
        <Ajuste rotulo={`Pontos (${pontos.length} de ${LIMITE_DE_PONTOS})`} dica="Toque na foto onde está o produto para pôr um ponto; depois escolha qual produto ele mostra.">
          <div
            role="button"
            tabIndex={-1}
            aria-label="Toque na imagem para pôr um ponto"
            onClick={marcar}
            className="relative w-full cursor-crosshair overflow-hidden rounded-xl bg-[var(--ks-color-bg-inset)]"
            style={{ aspectRatio: String(medida.proporcao) }}
            data-teste="imagem-dos-pontos"
          >
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img src={imagem} alt="" draggable={false} className="pointer-events-none absolute inset-0 h-full w-full object-cover" />
            {pontos.map((ponto, indice) => (
              <button
                key={indice}
                type="button"
                onClick={(e) => {
                  e.stopPropagation();
                  setEscolhido(indice);
                }}
                aria-label={`Ponto ${indice + 1}`}
                className={`absolute -ml-3 -mt-3 flex h-6 w-6 items-center justify-center rounded-full text-[11px] font-black text-white shadow-md ring-2 ${escolhido === indice ? "ring-amber-300" : "ring-white"}`}
                style={{ left: `${ponto.x}%`, top: `${ponto.y}%`, background: ponto.produto_id ? "var(--ks-color-primary)" : "#e11d48" }}
              >
                {indice + 1}
              </button>
            ))}
          </div>
          <div className="mt-3 space-y-2">
            {pontos.map((ponto, indice) => (
              <div key={indice} data-bloco={indice} className={`flex items-center gap-2 rounded-xl border p-2 ${escolhido === indice ? "border-[var(--ks-color-primary)]" : "border-[var(--ks-color-border-subtle)]"}`}>
                <span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-[var(--ks-color-primary)] text-[11px] font-black text-white">{indice + 1}</span>
                <div className="min-w-0 flex-1">
                  <Escolha
                    valor={ponto.produto_id || ""}
                    itens={produtos}
                    aoEscolher={(produto) => mudarPontos(pontos.map((p, i) => (i === indice ? { ...p, produto_id: produto.id } : p)))}
                    textoDoItem={(produto) => produto.name}
                    detalheDoItem={(produto) => emReais(produto.price)}
                    fotoDoItem={(produto) => produto.image_url}
                    placeholder="Escolher o produto"
                  />
                </div>
                <BotaoPequeno titulo="Tirar o ponto" perigo onClick={() => mudarPontos(pontos.filter((_, i) => i !== indice))}>
                  <X size={14} />
                </BotaoPequeno>
              </div>
            ))}
            {pontos.some((p) => !p.produto_id) ? <p className="text-[11.5px] font-semibold text-amber-700">Ponto sem produto não aparece na loja.</p> : null}
          </div>
        </Ajuste>
      ) : null}
      {margem}
    </>
  );
}
