"use client";

import { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore } from "react";
import { ArrowLeftRight, Ban, ChevronDown, CircleDot, Info, Pipette, Plus, Square, Sun, X, type LucideIcon } from "lucide-react";
import { IconeDeSepararBorda, IconeDeSepararCheio, IconeDoCantoRedondo, IconeDoCantoVivo } from "./icones-do-editor";
import { CampoDecimal } from "@/components/ui/campo-decimal";
import { corValida, cssDaPintura, sombraDura, sombraSuave, type Borda, type CantosDaLinha, type ParadaDoDegrade, type Pintura, type Sombra } from "@/lib/banner-editor/documento";

/*
  Os campos do editor de banners, num lugar só: cor (com a paleta da loja,
  as cores já usadas no banner e uma paleta viva), pintura (cor, degradê,
  radial), sombra, borda, réguas, números e grupos que abrem e fecham.
  Número digitado vai por CampoDecimal (nunca type="number").

  O jeito do painel lateral (nov/2026, pedido do Natan: "muito texto e muito
  bloco arredondado", "os slides são genéricos"): seções corridas com o
  ícone e o título, separadas por um fio quase invisível (Secao); a régua
  com trilho fino que enche em violeta (do meio quando vai para os dois
  lados) e o valor numa etiqueta; opções com ícone; botões com ícone
  (BotaoDoPainel, BotoesDeIcone); a explicação longa vira dica no título.
*/

/** Uma seção do painel: ícone, título, o que fica à direita (liga e desliga ou uma ação) e o conteúdo. */
export function Secao({
  titulo,
  icone: Icone,
  children,
  acao,
  ligado,
  aoLigar,
  dica,
}: {
  titulo: string;
  icone?: LucideIcon | ((p: { size?: number; className?: string }) => React.ReactNode);
  children?: React.ReactNode;
  acao?: React.ReactNode;
  /* Com aoLigar, a chave fica no título (e o conteúdo some desligado). */
  ligado?: boolean;
  aoLigar?: (v: boolean) => void;
  /* A explicação: aparece ao passar o mouse no "i" do título (em vez de um parágrafo). */
  dica?: string;
}) {
  const apagado = aoLigar ? !ligado : false;
  return (
    <section className="border-t border-[#EFEDF4] py-4 first:border-t-0 first:pt-1" data-secao={titulo}>
      <div className="flex min-h-7 items-center gap-2">
        {Icone ? (
          <span className={`flex shrink-0 items-center justify-center ${apagado ? "text-[#A9A4BC]" : "text-[#7C3AED]"}`}>
            <Icone size={16} />
          </span>
        ) : null}
        <h3 className={`min-w-0 flex-1 truncate text-[13px] font-semibold ${apagado ? "text-[#6B6584]" : "text-[#1F1B2E]"}`}>{titulo}</h3>
        {dica ? (
          <span className="flex shrink-0 cursor-help text-[#B5B0C7] hover:text-[#7C3AED]" title={dica} aria-label={dica}>
            <Info size={14} />
          </span>
        ) : null}
        {acao}
        {aoLigar ? <Chave rotulo="" ligado={Boolean(ligado)} aoMudar={aoLigar} /> : null}
      </div>
      {children && !apagado ? <div className="mt-3">{children}</div> : null}
    </section>
  );
}

/** Dica curta de uma linha (como mexer na arte), sem caixa. */
export function Dica({ children, icone: Icone = Info }: { children: React.ReactNode; icone?: LucideIcon }) {
  return (
    <p className="flex items-start gap-1.5 text-[11.5px] leading-snug text-[#8A849E]">
      <Icone size={13} className="mt-[1px] shrink-0 text-[#A78BFA]" />
      <span>{children}</span>
    </p>
  );
}

/** Botão do painel: sempre com ícone. `tom`: "normal" (contorno fino), "principal" (violeta) ou "perigo". */
export function BotaoDoPainel({
  icone: Icone,
  children,
  aoClicar,
  ativo = false,
  tom = "normal",
  titulo,
  largo = false,
  desligado = false,
  ...resto
}: {
  icone: LucideIcon | ((p: { size?: number; className?: string }) => React.ReactNode);
  children?: React.ReactNode;
  aoClicar: () => void;
  ativo?: boolean;
  tom?: "normal" | "principal" | "perigo";
  titulo?: string;
  largo?: boolean;
  desligado?: boolean;
} & Record<`data-${string}`, string | boolean | undefined>) {
  const cor =
    tom === "principal" || ativo
      ? "border-[#7C3AED] bg-[#7C3AED] text-white hover:bg-[#6D28D9]"
      : tom === "perigo"
        ? "border-[#E7E4EF] bg-white text-[#BE123C] hover:border-[#FDA4AF] hover:bg-[#FFF1F2]"
        : "border-[#E7E4EF] bg-white text-[#2B2640] hover:border-[#C4B5FD] hover:text-[#5B21B6]";
  return (
    <button type="button" title={titulo} aria-pressed={ativo || undefined} disabled={desligado} onClick={aoClicar} className={`flex h-9 min-w-0 items-center justify-center gap-1.5 rounded-[9px] border px-3 text-[12px] font-semibold transition disabled:opacity-40 ${largo ? "w-full" : ""} ${cor}`} {...resto}>
      <Icone size={15} />
      {children ? <span className="truncate">{children}</span> : null}
    </button>
  );
}

/** Uma fileira de botões só de ícone (alinhar, camadas, direções), com o nome no passar do mouse. */
export function BotoesDeIcone({ botoes }: { botoes: Array<{ icone: LucideIcon | ((p: { size?: number; className?: string }) => React.ReactNode); titulo: string; aoClicar: () => void; ativo?: boolean; chave?: string }> }) {
  return (
    <div className="flex flex-wrap gap-1">
      {botoes.map(({ icone: Icone, titulo, aoClicar, ativo, chave }) => (
        <button
          key={chave ?? titulo}
          type="button"
          title={titulo}
          aria-label={titulo}
          aria-pressed={ativo || undefined}
          onClick={aoClicar}
          className={`flex h-9 w-9 items-center justify-center rounded-[9px] transition ${ativo ? "bg-[#7C3AED] text-white" : "text-[#4B4760] hover:bg-[#F3F1F9] hover:text-[#5B21B6]"}`}
        >
          <Icone size={17} />
        </button>
      ))}
    </div>
  );
}

/* As cores que o seletor oferece: as da loja e as já usadas no banner chegam pelo editor. */
export const ContextoDasCores = createContext<{ daLoja: string[]; usadas: string[] }>({ daLoja: [], usadas: [] });

export const PALETA_VIVA = [
  "#FFFFFF", "#F4F4F5", "#A1A1AA", "#141414",
  "#FFD400", "#FFB020", "#FF7A00", "#FF3D00",
  "#E11D48", "#DB2777", "#C026D3", "#7C3AED",
  "#4F46E5", "#2563EB", "#0EA5E9", "#06B6D4",
  "#10B981", "#00A650", "#84CC16", "#7C2D12",
];

/* ---------------------------------------------- cores recentes e conta-gotas */

const CHAVE_DAS_RECENTES = "ktalogu:artes:cores-recentes";
const EVENTO_DAS_RECENTES = "ktalogu:cores-recentes";

function lerRecentes(): string[] {
  try {
    const lista = JSON.parse(window.localStorage.getItem(CHAVE_DAS_RECENTES) || "[]");
    return Array.isArray(lista) ? lista.map((c) => corValida(c, "")).filter(Boolean).slice(0, 12) : [];
  } catch {
    return [];
  }
}

/** Guarda a cor escolhida no topo das recentes (lembradas neste navegador). */
export function lembrarCor(cor: string) {
  const valida = corValida(cor, "");
  if (!valida) return;
  const lista = [valida, ...lerRecentes().filter((c) => c !== valida)].slice(0, 12);
  try {
    window.localStorage.setItem(CHAVE_DAS_RECENTES, JSON.stringify(lista));
  } catch {
    /* sem armazenamento, só não lembra */
  }
  window.dispatchEvent(new Event(EVENTO_DAS_RECENTES));
}

/** As cores usadas por último (atualiza quando outra parte do editor escolhe uma). */
export function useCoresRecentes() {
  const [lista, setLista] = useState<string[]>([]);
  useEffect(() => {
    const ler = () => setLista(lerRecentes());
    ler();
    window.addEventListener(EVENTO_DAS_RECENTES, ler);
    return () => window.removeEventListener(EVENTO_DAS_RECENTES, ler);
  }, []);
  return lista;
}

type ContaGotas = { open: () => Promise<{ sRGBHex: string }> };

/** Conta-gotas: pega a cor de qualquer ponto da tela (navegadores que têm, como Chrome e Edge). */
export function BotaoContaGotas({ aoPegar, grande = false }: { aoPegar: (cor: string) => void; grande?: boolean }) {
  /* O navegador tem conta-gotas? (no servidor, não). */
  const tem = useSyncExternalStore(
    () => () => undefined,
    () => "EyeDropper" in window,
    () => false,
  );
  if (!tem) return null;
  return (
    <button
      type="button"
      title="Conta-gotas: pegar uma cor da arte"
      onClick={async () => {
        try {
          const Construtor = (window as unknown as { EyeDropper: new () => ContaGotas }).EyeDropper;
          const { sRGBHex } = await new Construtor().open();
          const cor = corValida(sRGBHex, "");
          if (cor) {
            lembrarCor(cor);
            aoPegar(cor);
          }
        } catch {
          /* desistiu (Esc) */
        }
      }}
      className={`flex shrink-0 items-center justify-center rounded-lg border border-[var(--ks-color-border)] bg-white text-[#4B4760] transition hover:border-[#A78BFA] hover:text-[#6D28D9] ${grande ? "h-9 w-9 rounded-[10px]" : "h-9 w-9"}`}
    >
      <Pipette size={16} />
    </button>
  );
}

export function Rotulo({ children }: { children: React.ReactNode }) {
  return <span className="mb-1.5 block text-[12px] font-medium text-[#3F3A55]">{children}</span>;
}

/** Um grupo de ajustes que abre e fecha (o título sempre à vista). */
export function Grupo({ titulo, aberto: abertoDeInicio = true, children, acao }: { titulo: string; aberto?: boolean; children: React.ReactNode; acao?: React.ReactNode }) {
  const [aberto, setAberto] = useState(abertoDeInicio);
  return (
    <section className="border-t border-[var(--ks-color-border)] first:border-t-0">
      <div className="flex items-center gap-2 px-4 py-3">
        <button type="button" onClick={() => setAberto((v) => !v)} className="flex flex-1 items-center gap-1.5 text-left text-[12.5px] font-bold text-[var(--ks-color-text-primary)]">
          <ChevronDown size={14} className={`text-[var(--ks-color-text-soft)] transition-transform ${aberto ? "" : "-rotate-90"}`} />
          {titulo}
        </button>
        {acao}
      </div>
      {aberto ? <div className="space-y-3 px-4 pb-4">{children}</div> : null}
    </section>
  );
}

/**
 * A régua (deslizante): trilho fino que enche em violeta até o valor (do
 * zero, quando ela vai para os dois lados, como "para o lado" de -60 a 60),
 * a bolinha branca com aro e o valor numa etiqueta. Dois cliques no nome
 * voltam ao `padrao`, quando ele existe.
 */
export function Regua({
  rotulo,
  valor,
  min,
  max,
  passo = 1,
  aoMudar,
  formato = (v: number) => String(Math.round(v)),
  padrao,
}: {
  rotulo: string;
  valor: number;
  min: number;
  max: number;
  passo?: number;
  aoMudar: (v: number) => void;
  formato?: (v: number) => string;
  padrao?: number;
}) {
  const fracao = (v: number) => Math.max(0, Math.min(100, ((v - min) / Math.max(1e-9, max - min)) * 100));
  const zero = min < 0 && max > 0 ? fracao(0) : 0;
  const agora = fracao(valor);
  const estilo = { "--de": `${Math.min(zero, agora)}%`, "--ate": `${Math.max(zero, agora)}%` } as React.CSSProperties;
  return (
    <label className="block" data-regua>
      <span className="mb-1 flex items-center justify-between gap-2 text-[12px] font-medium text-[#3F3A55]">
        <span className="truncate" onDoubleClick={padrao !== undefined ? () => aoMudar(padrao) : undefined} title={padrao !== undefined ? "Dois cliques voltam ao padrão" : undefined}>
          {rotulo}
        </span>
        <span className="shrink-0 rounded-[6px] bg-[#F5F3FF] px-1.5 py-px text-[11.5px] font-semibold tabular-nums text-[#5B21B6]">{formato(valor)}</span>
      </span>
      <input type="range" min={min} max={max} step={passo} value={valor} onChange={(e) => aoMudar(Number(e.target.value))} className="ks-regua w-full" style={estilo} />
    </label>
  );
}

/** Escolha de uma entre poucas: botões lado a lado, cada um com o ícone (a escolhida em violeta). */
export function Opcoes<T extends string>({ valor, opcoes, aoMudar }: { valor: T; opcoes: Array<{ valor: T; rotulo: React.ReactNode; titulo?: string; icone?: LucideIcon | ((p: { size?: number; className?: string }) => React.ReactNode) }>; aoMudar: (v: T) => void }) {
  return (
    <div className="flex gap-0.5 rounded-[10px] border border-[#E7E4EF] bg-white p-0.5" role="radiogroup">
      {opcoes.map((o) => {
        const Icone = o.icone;
        return (
          <button
            key={o.valor}
            type="button"
            role="radio"
            aria-checked={valor === o.valor}
            title={o.titulo}
            onClick={() => aoMudar(o.valor)}
            className={`flex min-w-0 flex-1 items-center justify-center gap-1.5 rounded-[8px] px-1.5 py-1.5 text-[11.5px] font-semibold transition ${valor === o.valor ? "bg-[#7C3AED] text-white shadow-sm" : "text-[#5A5470] hover:bg-[#F6F5FA] hover:text-[#1F1B2E]"}`}
          >
            {Icone ? <Icone size={14} className="shrink-0" /> : null}
            <span className="truncate">{o.rotulo}</span>
          </button>
        );
      })}
    </div>
  );
}

export function Chave({ rotulo, ligado, aoMudar }: { rotulo: string; ligado: boolean; aoMudar: (v: boolean) => void }) {
  return (
    <button
      type="button"
      onClick={() => aoMudar(!ligado)}
      aria-pressed={ligado}
      className={`flex items-center justify-between gap-3 py-0.5 text-left text-[12px] font-semibold text-[var(--ks-color-text-primary)] ${rotulo ? "w-full" : "shrink-0"}`}
    >
      {rotulo}
      <span className={`relative h-5 w-9 shrink-0 rounded-full transition ${ligado ? "bg-[#7C3AED]" : "bg-[#D9D6E4]"}`}>
        <span className={`absolute top-0.5 h-4 w-4 rounded-full bg-white shadow transition-all ${ligado ? "left-[18px]" : "left-0.5"}`} />
      </span>
    </button>
  );
}

/** Número digitado (X, Y, largura...), com o rótulo dentro. */
export function Numero({ rotulo, valor, aoMudar, sufixo, negativo = false }: { rotulo: string; valor: number; aoMudar: (v: number) => void; sufixo?: string; negativo?: boolean }) {
  return (
    <label className="flex h-9 items-center gap-1.5 rounded-lg border border-[var(--ks-color-border)] bg-white px-2 focus-within:border-[#A78BFA]">
      <span className="text-[10.5px] font-bold text-[var(--ks-color-text-soft)]">{rotulo}</span>
      <CampoDecimal valor={Math.round(valor)} aoMudar={aoMudar} casas={0} permiteNegativo={negativo} className="w-full min-w-0 bg-transparent text-right text-[12.5px] font-semibold tabular-nums outline-none" />
      {sufixo ? <span className="text-[10.5px] text-[var(--ks-color-text-soft)]">{sufixo}</span> : null}
    </label>
  );
}

/* ------------------------------------------------------------------ cor */

function Amostra({ cor, ativa, aoClicar, titulo }: { cor: string; ativa?: boolean; aoClicar: () => void; titulo?: string }) {
  return (
    <button
      type="button"
      title={titulo || cor}
      onClick={aoClicar}
      className={`h-7 w-7 rounded-lg border transition hover:scale-110 ${ativa ? "ring-2 ring-[#7C3AED] ring-offset-1" : ""}`}
      style={{ background: cor, borderColor: "rgba(0,0,0,.1)" }}
    />
  );
}

/** O botão com a amostra da cor; abre a paleta (loja, usadas, viva) e o seletor livre. */
export function Cor({ valor, aoMudar, rotulo, compacta = false }: { valor: string; aoMudar: (cor: string) => void; rotulo?: string; compacta?: boolean }) {
  const [aberta, setAberta] = useState(false);
  const [rascunho, setRascunho] = useState(valor);
  const caixa = useRef<HTMLDivElement | null>(null);
  const { daLoja, usadas } = useContext(ContextoDasCores);
  const recentes = useCoresRecentes();

  useEffect(() => {
    if (!aberta) return;
    const fora = (e: MouseEvent) => {
      if (!caixa.current?.contains(e.target as Node)) setAberta(false);
    };
    document.addEventListener("mousedown", fora);
    return () => document.removeEventListener("mousedown", fora);
  }, [aberta]);

  const escolher = (cor: string) => {
    aoMudar(cor);
    setRascunho(cor);
    lembrarCor(cor);
  };

  return (
    <div ref={caixa} className="relative">
      <button
        type="button"
        onClick={() => {
          setRascunho(valor);
          setAberta((v) => !v);
        }}
        title={rotulo}
        className={compacta ? "flex h-8 w-8 items-center justify-center rounded-lg border border-[var(--ks-color-border)] bg-white hover:border-[#A78BFA]" : "flex h-9 w-full items-center gap-2 rounded-lg border border-[var(--ks-color-border)] bg-white px-2 text-left hover:border-[#A78BFA]"}
      >
        <span className="h-5 w-5 shrink-0 rounded-md border" style={{ background: valor, borderColor: "rgba(0,0,0,.12)" }} />
        {compacta ? null : (
          <span className="min-w-0 flex-1">
            {rotulo ? <span className="block truncate text-[11.5px] font-semibold text-[var(--ks-color-text-primary)]">{rotulo}</span> : null}
            <span className="block text-[10.5px] uppercase tabular-nums text-[var(--ks-color-text-soft)]">{valor}</span>
          </span>
        )}
      </button>
      {aberta ? (
        <div className="absolute left-0 top-[calc(100%+6px)] z-50 w-[248px] rounded-2xl border border-[var(--ks-color-border)] bg-white p-3 shadow-[0_18px_40px_-12px_rgba(20,11,43,0.35)]">
          {recentes.length ? (
            <>
              <Rotulo>Recentes</Rotulo>
              <div className="mb-3 flex flex-wrap gap-1.5">
                {recentes.slice(0, 8).map((c) => (
                  <Amostra key={`r${c}`} cor={c} ativa={c === valor} aoClicar={() => escolher(c)} />
                ))}
              </div>
            </>
          ) : null}
          {daLoja.length ? (
            <>
              <Rotulo>Da loja</Rotulo>
              <div className="mb-3 flex flex-wrap gap-1.5">
                {daLoja.map((c) => (
                  <Amostra key={`l${c}`} cor={c} ativa={c === valor} aoClicar={() => escolher(c)} />
                ))}
              </div>
            </>
          ) : null}
          {usadas.length ? (
            <>
              <Rotulo>No banner</Rotulo>
              <div className="mb-3 flex flex-wrap gap-1.5">
                {usadas.slice(0, 14).map((c) => (
                  <Amostra key={`u${c}`} cor={c} ativa={c === valor} aoClicar={() => escolher(c)} />
                ))}
              </div>
            </>
          ) : null}
          <Rotulo>Cores</Rotulo>
          <div className="mb-3 grid grid-cols-8 gap-1.5">
            {PALETA_VIVA.map((c) => (
              <Amostra key={`p${c}`} cor={c} ativa={c === valor} aoClicar={() => escolher(c)} />
            ))}
          </div>
          <div className="flex items-center gap-2">
            <label className="relative h-9 w-9 shrink-0 cursor-pointer overflow-hidden rounded-lg border border-[var(--ks-color-border)]" title="Escolher qualquer cor" style={{ background: "conic-gradient(red, yellow, lime, cyan, blue, magenta, red)" }}>
              <input type="color" value={corValida(valor, "#000000")} onChange={(e) => escolher(e.target.value.toUpperCase())} className="absolute inset-0 h-full w-full cursor-pointer opacity-0" />
            </label>
            <BotaoContaGotas aoPegar={escolher} />
            <input
              value={rascunho}
              onChange={(e) => {
                setRascunho(e.target.value);
                const cor = corValida(e.target.value, "");
                if (cor) aoMudar(cor);
              }}
              maxLength={7}
              className="ks-field h-9 min-w-0 flex-1 font-mono text-[12.5px] uppercase"
              placeholder="#FFFFFF"
            />
          </div>
        </div>
      ) : null}
    </div>
  );
}

/* -------------------------------------------------------------- pintura */

/** Cor única, degradê (com direção) ou radial, para qualquer coisa. */
/** `permiteSem`: oferece "Sem cor" (forma só com borda, letra só com contorno). */
export function CampoDePintura({ valor, aoMudar, rotulo = "Cor", permiteSem = false }: { valor: Pintura; aoMudar: (p: Pintura) => void; rotulo?: string; permiteSem?: boolean }) {
  return (
    <div className="space-y-2.5">
      <Opcoes
        valor={valor.tipo}
        opcoes={[
          { valor: "solida", rotulo: "Cor", icone: Square },
          { valor: "linear", rotulo: "Degradê", icone: IconeDoDegrade },
          { valor: "radial", rotulo: "Radial", icone: CircleDot },
          ...(permiteSem ? [{ valor: "nenhuma" as const, rotulo: "Sem", titulo: "Sem preenchimento", icone: Ban }] : []),
        ]}
        aoMudar={(tipo) => aoMudar({ ...valor, tipo, cor2: tipo !== "solida" && valor.cor2 === valor.cor ? "#FFFFFF" : valor.cor2 })}
      />
      {valor.tipo === "nenhuma" ? (
        <Dica>Sem preenchimento: fica só a borda (ou o contorno da letra).</Dica>
      ) : valor.tipo === "solida" ? (
        <Cor rotulo={rotulo} valor={valor.cor} aoMudar={(cor) => aoMudar({ ...valor, cor, cor2: cor })} />
      ) : (
        <>
          {/* A barra com todas as cores (as do meio também), da primeira à última. */}
          <div className="h-6 rounded-lg border border-[var(--ks-color-border)]" data-barra-do-degrade style={{ background: cssDaPintura({ ...valor, tipo: "linear", angulo: 90, pontos: undefined }) }} />
          <div className="flex items-center gap-1.5">
            <div className="min-w-0 flex-1">
              <Cor rotulo={valor.tipo === "radial" ? "Centro" : "Início"} valor={valor.cor} aoMudar={(cor) => aoMudar({ ...valor, cor })} />
            </div>
            <button type="button" title="Inverter as cores" onClick={() => aoMudar({ ...valor, cor: valor.cor2, cor2: valor.cor })} className="flex h-9 w-8 shrink-0 items-center justify-center rounded-lg text-[var(--ks-color-text-soft)] hover:bg-[var(--ks-color-bg-inset)] hover:text-[#5B21B6]">
              <ArrowLeftRight size={14} />
            </button>
            <div className="min-w-0 flex-1">
              <Cor rotulo={valor.tipo === "radial" ? "Borda" : "Fim"} valor={valor.cor2} aoMudar={(cor2) => aoMudar({ ...valor, cor2 })} />
            </div>
          </div>
          <CoresDoMeio valor={valor} aoMudar={aoMudar} />
          {valor.tipo === "linear" ? <Regua rotulo="Direção" valor={((valor.angulo % 360) + 360) % 360} min={0} max={360} aoMudar={(angulo) => aoMudar({ ...valor, angulo, pontos: undefined })} formato={(v) => `${Math.round(v)}°`} /> : null}
          {valor.tipo === "radial" ? <CentroDoRadial valor={valor} aoMudar={aoMudar} /> : null}
        </>
      )}
      {/* Transparência da tinta (a peça continua inteira; só a cor deixa ver o que está atrás). */}
      {valor.tipo === "solida" ? (
        <Regua rotulo="Cobertura da cor" valor={Math.round((valor.alfa ?? 1) * 100)} min={0} max={100} aoMudar={(v) => aoMudar({ ...valor, alfa: v / 100 })} formato={(v) => `${Math.round(v)}%`} />
      ) : valor.tipo !== "nenhuma" ? (
        <div className="grid grid-cols-2 gap-2">
          <Regua rotulo={valor.tipo === "radial" ? "Cobre no centro" : "Cobre no início"} valor={Math.round((valor.alfa ?? 1) * 100)} min={0} max={100} aoMudar={(v) => aoMudar({ ...valor, alfa: v / 100 })} formato={(v) => `${Math.round(v)}%`} />
          <Regua rotulo={valor.tipo === "radial" ? "Cobre na borda" : "Cobre no fim"} valor={Math.round((valor.alfa2 ?? valor.alfa ?? 1) * 100)} min={0} max={100} aoMudar={(v) => aoMudar({ ...valor, alfa2: v / 100 })} formato={(v) => `${Math.round(v)}%`} />
        </div>
      ) : null}
    </div>
  );
}

/** As cores do meio do degradê (3 ou mais cores): cada uma com a posição; o "+" põe uma no meio do caminho. */
function CoresDoMeio({ valor, aoMudar }: { valor: Pintura; aoMudar: (p: Pintura) => void }) {
  const paradas = valor.paradas || [];
  const mudar = (lista: ParadaDoDegrade[]) => aoMudar({ ...valor, paradas: lista.length ? [...lista].sort((a, b) => a.pos - b.pos) : undefined, ...(lista.length ? { meio: undefined } : {}) });
  return (
    <div className="space-y-2" data-cores-do-meio>
      {paradas.map((q, i) => (
        <div key={i} className="rounded-lg bg-[var(--ks-color-bg-inset)] p-2">
          <div className="flex items-center gap-1.5">
            <div className="min-w-0 flex-1">
              <Cor rotulo={`Cor do meio ${i + 1}`} valor={q.cor} aoMudar={(cor) => mudar(paradas.map((x, j) => (j === i ? { ...x, cor } : x)))} />
            </div>
            <button type="button" title="Tirar esta cor" aria-label={`Tirar a cor do meio ${i + 1}`} onClick={() => mudar(paradas.filter((_, j) => j !== i))} className="flex h-9 w-8 shrink-0 items-center justify-center rounded-lg text-[var(--ks-color-text-soft)] hover:bg-white hover:text-[#BE123C]">
              <X size={14} />
            </button>
          </div>
          <div className="mt-1.5">
            <Regua rotulo="Onde fica" valor={Math.round(q.pos * 100)} min={1} max={99} aoMudar={(v) => mudar(paradas.map((x, j) => (j === i ? { ...x, pos: v / 100 } : x)))} formato={(v) => `${Math.round(v)}%`} />
          </div>
        </div>
      ))}
      {paradas.length < 6 ? (
        <button
          type="button"
          onClick={() => {
            /* A nova entra no maior vão entre as cores que já existem. */
            const posicoes = [0, ...paradas.map((q) => q.pos), 1];
            let melhor = 0.5;
            let vao = 0;
            for (let i = 1; i < posicoes.length; i += 1) {
              if (posicoes[i] - posicoes[i - 1] > vao) {
                vao = posicoes[i] - posicoes[i - 1];
                melhor = (posicoes[i] + posicoes[i - 1]) / 2;
              }
            }
            mudar([...paradas, { pos: Math.round(melhor * 100) / 100, cor: misturarCores(valor.cor, valor.cor2) }]);
          }}
          className="flex h-8 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-[var(--ks-color-border)] text-[12px] font-semibold text-[var(--ks-color-text-soft)] transition hover:border-[#A78BFA] hover:text-[#5B21B6]"
        >
          <Plus size={13} /> Cor no meio
        </button>
      ) : null}
    </div>
  );
}

/** O meio de duas cores (para a cor nova do degradê nascer combinando). */
function misturarCores(a: string, b: string) {
  const p = (c: string) => [1, 3, 5].map((i) => parseInt((/^#[0-9a-f]{6}$/i.test(c) ? c : "#888888").slice(i, i + 2), 16));
  const [x, y] = [p(a), p(b)];
  return `#${x.map((v, i) => Math.round((v + y[i]) / 2).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
}

/** O radial com o centro onde quiser (o holofote fora do meio) e o tamanho do círculo. */
function CentroDoRadial({ valor, aoMudar }: { valor: Pintura; aoMudar: (p: Pintura) => void }) {
  const pt = valor.pontos;
  const cx = pt ? pt.x1 : 0.5;
  const cy = pt ? pt.y1 : 0.5;
  const raio = pt ? Math.hypot(pt.x2 - pt.x1, pt.y2 - pt.y1) : 0.5;
  const mudar = (x: number, y: number, r: number) => aoMudar({ ...valor, pontos: { x1: x, y1: y, x2: x + Math.max(0.02, r), y2: y } });
  return (
    <div className="space-y-1.5" data-centro-do-radial>
      <div className="grid grid-cols-2 gap-2">
        <Regua rotulo="Centro: lado" valor={Math.round(cx * 100)} min={-50} max={150} aoMudar={(v) => mudar(v / 100, cy, raio)} formato={(v) => `${Math.round(v)}%`} />
        <Regua rotulo="Centro: altura" valor={Math.round(cy * 100)} min={-50} max={150} aoMudar={(v) => mudar(cx, v / 100, raio)} formato={(v) => `${Math.round(v)}%`} />
      </div>
      <Regua rotulo="Tamanho do círculo" valor={Math.round(raio * 100)} min={5} max={200} aoMudar={(v) => mudar(cx, cy, v / 100)} formato={(v) => `${Math.round(v)}%`} />
      <Dica>Na arte, arraste as alças: a bolinha do começo é o centro, a do fim é a borda.</Dica>
    </div>
  );
}

/* --------------------------------------------------------------- sombra */

export function CampoDeSombra({ valor, aoMudar }: { valor: Sombra; aoMudar: (s: Sombra) => void }) {
  const tipo = !valor ? "nenhuma" : valor.desfoque === 0 ? "dura" : valor.x === 0 && valor.y === 0 ? "brilho" : "suave";
  return (
    <div className="space-y-2.5">
      <Opcoes
        valor={tipo}
        opcoes={[
          { valor: "nenhuma", rotulo: "Sem", titulo: "Sem sombra", icone: Ban },
          { valor: "suave", rotulo: "Suave", icone: IconeDaSombraSuave },
          { valor: "dura", rotulo: "Forte", titulo: "Sombra marcada (sem desfoque)", icone: IconeDaSombraMarcada },
          { valor: "brilho", rotulo: "Brilho", icone: Sun },
        ]}
        aoMudar={(v) =>
          aoMudar(v === "nenhuma" ? null : v === "suave" ? sombraSuave() : v === "dura" ? sombraDura() : { cor: "#FFFFFF", x: 0, y: 0, desfoque: 30, opacidade: 0.8 })
        }
      />
      {valor ? (
        <>
          <Cor rotulo="Cor da sombra" valor={valor.cor} aoMudar={(cor) => aoMudar({ ...valor, cor })} />
          <div className="grid grid-cols-2 gap-3">
            <Regua rotulo="Para o lado" valor={valor.x} min={-60} max={60} aoMudar={(x) => aoMudar({ ...valor, x })} padrao={0} />
            <Regua rotulo="Para baixo" valor={valor.y} min={-60} max={60} aoMudar={(y) => aoMudar({ ...valor, y })} padrao={0} />
          </div>
          <Regua rotulo="Desfoque" valor={valor.desfoque} min={0} max={120} aoMudar={(desfoque) => aoMudar({ ...valor, desfoque })} />
          <Regua rotulo="Força" valor={Math.round(valor.opacidade * 100)} min={5} max={100} aoMudar={(v) => aoMudar({ ...valor, opacidade: v / 100 })} formato={(v) => `${Math.round(v)}%`} />
        </>
      ) : null}
    </div>
  );
}

/* ---------------------------------------------------------------- borda */

/**
 * Borda ou contorno: liga e desliga (`semChave`: a seção já tem a chave), cor
 * e espessura. `cantos` (o de agora): mostra o pontudo e o arredondado.
 * `aoSeparar`: o "Separar contorno" (só a borda ou cheio).
 */
export function CampoDeBorda({
  valor,
  aoMudar,
  rotulo = "Borda",
  padrao = 6,
  semChave = false,
  cantos,
  buracos = false,
  aoSeparar,
}: {
  valor: Borda;
  aoMudar: (b: Borda) => void;
  rotulo?: string;
  padrao?: number;
  semChave?: boolean;
  cantos?: CantosDaLinha;
  /* Contorno arredondado da letra: manter ou fechar os buracos pequenos que sobram dentro das letras. */
  buracos?: boolean;
  aoSeparar?: (modo: "borda" | "cheio") => void;
}) {
  return (
    <div className="space-y-3">
      {semChave ? null : <Chave rotulo={rotulo} ligado={Boolean(valor)} aoMudar={(v) => aoMudar(v ? { cor: "#FFFFFF", largura: padrao } : null)} />}
      {valor ? (
        <>
          <div className="flex items-end gap-2.5">
            <div className="w-[52px] shrink-0">
              <Cor compacta valor={valor.cor} aoMudar={(cor) => aoMudar({ ...valor, cor })} rotulo={`Cor da ${rotulo.toLowerCase()}`} />
            </div>
            <div className="min-w-0 flex-1">
              <Regua rotulo="Espessura" valor={valor.largura} min={1} max={80} aoMudar={(largura) => aoMudar({ ...valor, largura })} />
            </div>
          </div>
          {cantos ? (
            <div data-cantos-do-contorno>
              <Rotulo>Cantos</Rotulo>
              <Opcoes<CantosDaLinha>
                valor={cantos}
                opcoes={[
                  { valor: "vivos", rotulo: "Pontudo", icone: IconeDoCantoVivo, titulo: "Cantos pontudos (em bico)" },
                  { valor: "redondos", rotulo: "Arredondado", icone: IconeDoCantoRedondo, titulo: "Cantos arredondados" },
                ]}
                aoMudar={(c) => aoMudar({ ...valor, cantos: c })}
              />
            </div>
          ) : null}
          {buracos && cantos === "redondos" ? (
            <div data-buracos-do-contorno>
              <Rotulo>Buracos dentro das letras</Rotulo>
              <Opcoes<"manter" | "fechar">
                valor={valor.semBuracos ? "fechar" : "manter"}
                opcoes={[
                  { valor: "manter", rotulo: "Manter", icone: IconeDosBuracos, titulo: "Os buracos pequenos que sobram dentro das letras ficam (como no Corel)" },
                  { valor: "fechar", rotulo: "Fechar", icone: IconeSemBuracos, titulo: "Tapa os buracos pequenos que sobram dentro das letras" },
                ]}
                aoMudar={(v) => aoMudar({ ...valor, semBuracos: v === "fechar" ? true : undefined })}
              />
            </div>
          ) : null}
          {aoSeparar ? (
            <div data-separar-contorno>
              <Rotulo>Separar contorno</Rotulo>
              <div className="grid grid-cols-2 gap-2">
                <BotaoDoPainel icone={IconeDeSepararBorda} aoClicar={() => aoSeparar("borda")} titulo="O contorno vira uma peça própria: só a linha (como aparece)" data-separar="borda">
                  Só a borda
                </BotaoDoPainel>
                <BotaoDoPainel icone={IconeDeSepararCheio} aoClicar={() => aoSeparar("cheio")} titulo="O contorno vira uma peça própria: a silhueta inteira, preenchida na cor dele" data-separar="cheio">
                  Preenchido
                </BotaoDoPainel>
              </div>
            </div>
          ) : null}
        </>
      ) : null}
    </div>
  );
}

/* --------------------------------------------------- ícones das opções */

function IconeDoDegrade({ size = 14, className }: { size?: number; className?: string }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" className={className} aria-hidden="true">
      <defs>
        <linearGradient id="ks-icone-degrade" x1="0" x2="1">
          <stop offset="0" stopColor="currentColor" />
          <stop offset="1" stopColor="currentColor" stopOpacity="0.12" />
        </linearGradient>
      </defs>
      <rect x="3" y="3" width="18" height="18" rx="3" fill="url(#ks-icone-degrade)" stroke="currentColor" strokeWidth="2" />
    </svg>
  );
}

function IconeDaSombraSuave({ size = 14, className }: { size?: number; className?: string }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className={className} aria-hidden="true">
      <rect x="5" y="9" width="15" height="12" rx="3" fill="currentColor" stroke="none" opacity={0.18} />
      <rect x="3" y="3" width="14" height="13" rx="2.5" />
    </svg>
  );
}

function IconeDaSombraMarcada({ size = 14, className }: { size?: number; className?: string }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className={className} aria-hidden="true">
      <rect x="7" y="7" width="14" height="14" rx="2" fill="currentColor" stroke="none" opacity={0.55} />
      <rect x="3" y="3" width="14" height="14" rx="2" fill="white" />
    </svg>
  );
}

/* O "B" com os buracos (manter) e sem (fechar). */
function IconeDosBuracos({ size = 14, className }: { size?: number; className?: string }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinejoin="round" className={className} aria-hidden="true">
      <path d="M6 3h7a4.5 4.5 0 0 1 2.6 8.2A5 5 0 0 1 14 21H6Z" />
      <path d="M10 7h2.5a1.5 1.5 0 0 1 0 3H10ZM10 14h3a1.6 1.6 0 0 1 0 3.2h-3Z" />
    </svg>
  );
}

function IconeSemBuracos({ size = 14, className }: { size?: number; className?: string }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth={2} strokeLinejoin="round" className={className} aria-hidden="true">
      <path d="M6 3h7a4.5 4.5 0 0 1 2.6 8.2A5 5 0 0 1 14 21H6Z" />
    </svg>
  );
}
