"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import Link from "next/link";
import { faxinarSlug } from "@/lib/faxina-html";
import { getSupabaseClient } from "@/lib/supabase";
import { DESENHOS, NIVEIS, ROTULO_DO_NIVEL } from "@/lib/help";
import type { Artigo, Nivel, Secao } from "@/lib/help";
import "./editor.css";

/**
 * A folha de escrita do centro de aprendizado.
 *
 * O desenho é o mesmo que ele aprovou no boletim: uma folha de papel, não um
 * formulário de blocos. O que muda são as peças que só um manual precisa —
 * passo com print, caminho no sistema, aviso em três tons, vídeo e pergunta.
 *
 * A formatação usa `document.execCommand`. Está obsoleto há anos e continua
 * sendo o único caminho que funciona em todo navegador sem arrastar um editor
 * inteiro para dentro do projeto.
 */

const ESPERA_PARA_SALVAR = 1800;

/* Andaimes: bloco vazio no meio do texto some da vista, e a pessoa não
   descobre que precisa preencher. Todo bloco nasce com exemplo dentro. */
const ANDAIME_PASSOS = `<div class="help-passos"><div class="help-passo"><div class="help-passo-corpo"><h3>Primeiro passo</h3><p>O que fazer, numa frase.</p></div></div><div class="help-passo"><div class="help-passo-corpo"><h3>Segundo passo</h3><p>O que fazer, numa frase.</p></div></div></div><p><br /></p>`;

const ANDAIME_AVISO = (tom: string, titulo: string) =>
  `<div class="help-aviso help-aviso-${tom}"><b class="help-aviso-titulo">${titulo}</b>A frase que ninguém pode perder.</div><p><br /></p>`;

const ANDAIME_CAMINHO = `<p><span class="help-caminho">Pedidos › Novo pedido</span></p>`;

const ANDAIME_TABELA = `<table class="help-tabela"><thead><tr><th>O que aparece</th><th>De onde vem</th></tr></thead><tbody><tr><td>Primeira linha</td><td>—</td></tr><tr><td>Segunda linha</td><td>—</td></tr></tbody></table><p><br /></p>`;

const ANDAIME_PERGUNTA = `<details class="help-faq"><summary class="help-faq-pergunta">A pergunta que aparece no suporte</summary><p class="help-faq-resposta">A resposta, curta.</p></details><p><br /></p>`;

/** Só o ID do YouTube. A página monta o endereço do player, não o editor. */
function idDoYoutube(bruto: string) {
  const texto = bruto.trim();
  if (/^[A-Za-z0-9_-]{6,20}$/.test(texto)) return texto;
  try {
    const url = new URL(texto);
    if (url.hostname === "youtu.be") return url.pathname.slice(1).split("/")[0] || null;
    if (/(^|\.)youtube\.com$/.test(url.hostname)) {
      const v = url.searchParams.get("v");
      if (v) return v;
      const partes = url.pathname.split("/").filter(Boolean);
      const alvo = partes[partes.length - 1];
      if (alvo && /^[A-Za-z0-9_-]{6,20}$/.test(alvo)) return alvo;
    }
  } catch {
    return null;
  }
  return null;
}

function Desenho({ nome, tamanho = 18 }: { nome: string; tamanho?: number }) {
  return (
    <svg width={tamanho} height={tamanho} viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <path d={DESENHOS[nome] ?? DESENHOS.livro} stroke="currentColor" strokeWidth="1.9" strokeLinejoin="round" strokeLinecap="round" />
    </svg>
  );
}

export default function EditorDoArtigo({
  inicial,
  secoes,
  base,
  sugestaoDeSecao,
  sugestaoDeTitulo,
  sugestaoDeTermo,
}: {
  inicial: Artigo | null;
  secoes: Secao[];
  base: string;
  sugestaoDeSecao: string;
  sugestaoDeTitulo: string;
  sugestaoDeTermo: string;
}) {
  const folha = useRef<HTMLDivElement | null>(null);
  const relogio = useRef<ReturnType<typeof setTimeout> | null>(null);
  const selecaoGuardada = useRef<Range | null>(null);

  /* O id de verdade vive no ref. `setId` chega tarde demais: sem o ref, dois
     salvamentos no mesmo intervalo criariam dois artigos. */
  const idRef = useRef(inicial?.id ?? "");
  const salvandoRef = useRef<Promise<string | null> | null>(null);

  const [, setId] = useState(inicial?.id ?? "");
  const [sectionId, setSectionId] = useState(inicial?.section_id ?? sugestaoDeSecao ?? secoes[0]?.id ?? "");
  const [title, setTitle] = useState(inicial?.title ?? sugestaoDeTitulo ?? "");
  const [subtitle, setSubtitle] = useState(inicial?.subtitle ?? "");
  const [slug, setSlug] = useState(inicial?.slug ?? "");
  const [level, setLevel] = useState<Nivel>(inicial?.level ?? "comecando");
  const [keywords, setKeywords] = useState<string[]>(
    inicial?.keywords ?? (sugestaoDeTermo ? [sugestaoDeTermo] : [])
  );
  const [novaPalavra, setNovaPalavra] = useState("");
  const [status, setStatus] = useState<"draft" | "published">(inicial?.status ?? "draft");
  const [needsReview, setNeedsReview] = useState(inicial?.needs_review ?? false);
  const [corpo, setCorpo] = useState(inicial?.body_html ?? "");

  const [salvando, setSalvando] = useState(false);
  const [publicando, setPublicando] = useState(false);
  const [salvoEm, setSalvoEm] = useState("");
  const [erro, setErro] = useState("");
  const [enviandoImagem, setEnviandoImagem] = useState(false);

  /* Painéis próprios para pedir endereço. A casa não usa `window.prompt`:
     ele trava a aba, não dá para colar com o teclado do celular e não tem a
     cara do resto do sistema. */
  const [pedindoVideo, setPedindoVideo] = useState(false);
  const [enderecoDoVideo, setEnderecoDoVideo] = useState("");
  const [pedindoLink, setPedindoLink] = useState(false);
  const [enderecoDoLink, setEnderecoDoLink] = useState("");

  const secao = secoes.find((s) => s.id === sectionId);
  const enderecoFinal = `${base}/${secao?.slug ?? "secao"}/${slug || faxinarSlug(title) || "artigo"}`;

  /* O sumário sai do próprio texto, na renderização, e não de um estado que
     um efeito preencheria ao montar — a casa proíbe `setState` dentro de
     efeito, e sem isso o artigo já salvo abriria com o sumário vazio. */
  const titulos = useMemo(() => {
    const achados: Array<{ texto: string; nivel: number }> = [];
    const padrao = /<(h2|h3)[^>]*>([\s\S]*?)<\/\1>/gi;
    let achado: RegExpExecArray | null;
    while ((achado = padrao.exec(corpo)) !== null) {
      const texto = achado[2].replace(/<[^>]*>/g, "").replace(/&nbsp;/g, " ").trim();
      achados.push({ texto: texto || "Sem título", nivel: achado[1].toLowerCase() === "h2" ? 2 : 3 });
    }
    return achados;
  }, [corpo]);

  const salvar = useCallback(
    async (publicar?: boolean): Promise<string | null> => {
      if (!title.trim()) {
        setErro("O artigo precisa de um título.");
        return null;
      }
      if (!sectionId) {
        setErro("Escolha a seção onde o artigo vive.");
        return null;
      }

      /* Um salvamento por vez: o que chegar durante outro espera, para só
         então gravar com o id que acabou de nascer. */
      if (salvandoRef.current) await salvandoRef.current.catch(() => null);
      if (relogio.current) {
        clearTimeout(relogio.current);
        relogio.current = null;
      }

      const tarefa = (async (): Promise<string | null> => {
        setSalvando(true);
        if (publicar !== undefined) setPublicando(true);
        setErro("");
        try {
          const payload: Record<string, unknown> = {
            section_id: sectionId,
            title: title.trim(),
            subtitle: subtitle.trim() || null,
            slug: slug.trim() || faxinarSlug(title),
            level,
            keywords,
            needs_review: needsReview,
            body_html: folha.current?.innerHTML ?? corpo,
          };
          if (publicar !== undefined) payload.status = publicar ? "published" : "draft";

          const idAtual = idRef.current;
          const resposta = await fetch("/api/help/articles", {
            method: idAtual ? "PATCH" : "POST",
            headers: { "content-type": "application/json" },
            body: JSON.stringify(idAtual ? { ...payload, id: idAtual } : payload),
          });
          const retorno = (await resposta.json().catch(() => null)) as
            | { error?: string; article?: { id: string; slug: string; status: string } }
            | null;
          if (!resposta.ok) throw new Error(retorno?.error || "Não foi possível salvar.");

          const artigo = retorno?.article;
          if (!idAtual && artigo?.id) {
            idRef.current = artigo.id;
            setId(artigo.id);
            /* Troca o endereço da barra sem recarregar: quem começou em "novo"
               passa a estar editando, e um F5 não cria um segundo artigo. */
            window.history.replaceState(null, "", `/aprender/${artigo.id}`);
          }
          if (artigo?.slug) setSlug(artigo.slug);
          if (artigo?.status === "published" || artigo?.status === "draft") setStatus(artigo.status);
          setSalvoEm(new Date().toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" }));
          return artigo?.id || idRef.current;
        } catch (falha) {
          setErro(falha instanceof Error ? falha.message : "Não foi possível salvar.");
          return null;
        } finally {
          setSalvando(false);
          if (publicar !== undefined) setPublicando(false);
        }
      })();

      salvandoRef.current = tarefa;
      try {
        return await tarefa;
      } finally {
        if (salvandoRef.current === tarefa) salvandoRef.current = null;
      }
    },
    [title, subtitle, slug, sectionId, level, keywords, needsReview, corpo]
  );

  const agendarSalvamento = useCallback(() => {
    if (relogio.current) clearTimeout(relogio.current);
    relogio.current = setTimeout(() => {
      if (title.trim() && sectionId) void salvar();
    }, ESPERA_PARA_SALVAR);
  }, [salvar, title, sectionId]);

  useEffect(() => {
    return () => {
      if (relogio.current) clearTimeout(relogio.current);
    };
  }, []);

  function aoDigitar() {
    setCorpo(folha.current?.innerHTML ?? "");
    agendarSalvamento();
  }

  function guardarSelecao() {
    const selecao = window.getSelection();
    if (selecao && selecao.rangeCount > 0) selecaoGuardada.current = selecao.getRangeAt(0).cloneRange();
  }

  function devolverSelecao() {
    const guardada = selecaoGuardada.current;
    if (!guardada) return;
    const selecao = window.getSelection();
    selecao?.removeAllRanges();
    selecao?.addRange(guardada);
  }

  function comando(nome: string, valor?: string) {
    folha.current?.focus();
    devolverSelecao();
    document.execCommand(nome, false, valor);
    aoDigitar();
  }

  function inserir(html: string) {
    folha.current?.focus();
    devolverSelecao();
    document.execCommand("insertHTML", false, html);
    aoDigitar();
  }

  function confirmarVideo() {
    const id = idDoYoutube(enderecoDoVideo);
    if (!id) {
      setErro("Não reconheci esse endereço do YouTube.");
      return;
    }
    inserir(
      `<figure class="help-video" data-youtube="${id}"><figcaption class="help-video-legenda">Uma linha dizendo o que o vídeo mostra.</figcaption></figure><p><br /></p>`
    );
    setEnderecoDoVideo("");
    setPedindoVideo(false);
    setErro("");
  }

  async function enviarImagem(ficheiro: File) {
    setEnviandoImagem(true);
    setErro("");
    try {
      const supabase = getSupabaseClient();
      const extensao = (ficheiro.name.split(".").pop() || "png").toLowerCase();
      const caminho = `help/${Math.random().toString(36).slice(2)}_${Date.now()}.${extensao}`;
      const { error } = await supabase.storage.from("products").upload(caminho, ficheiro, { upsert: true });
      if (error) throw new Error(error.message);
      const { data } = supabase.storage.from("products").getPublicUrl(caminho);
      inserir(
        `<figure class="help-figura"><img src="${data.publicUrl}" alt="" /><figcaption>Legenda da imagem.</figcaption></figure><p><br /></p>`
      );
    } catch (falha) {
      setErro(falha instanceof Error ? falha.message : "Não foi possível enviar a imagem.");
    } finally {
      setEnviandoImagem(false);
    }
  }

  function adicionarPalavra() {
    const limpa = novaPalavra.trim().toLowerCase();
    if (!limpa) return;
    setKeywords((antes) => (antes.includes(limpa) ? antes : [...antes, limpa]));
    setNovaPalavra("");
    agendarSalvamento();
  }

  const ferramenta = "hpe-fer";

  return (
    <div className="hp hpe">
      {/* ==================================== BARRA DE TRABALHO */}
      <div className="hpe-trabalho">
        <Link className="hpe-volta" href="/aprender">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M19 12H6M11 6l-6 6 6 6" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" /></svg>
          Artigos
        </Link>
        <span className="hpe-onde">
          <span className="hp-chapa">{secao?.title ?? "Sem seção"} /</span>
          <b>{title || "Sem título"}</b>
        </span>
        <div className="hpe-fim">
          <span className="hpe-salvo">
            <i data-ligado={salvando ? "0" : "1"} />
            {salvando ? "salvando…" : salvoEm ? `salvo às ${salvoEm}` : "ainda não salvo"}
          </span>
          {status === "published" ? (
            <a className="hp-btn hp-btn-papel" href={enderecoFinal} target="_blank" rel="noopener noreferrer" style={{ height: 38, padding: "0 15px", fontSize: 13.5 }}>
              Ver publicado
            </a>
          ) : null}
          <button
            type="button"
            className="hp-btn hp-btn-marca"
            style={{ height: 38, padding: "0 16px", fontSize: 13.5 }}
            onClick={() => void salvar(status !== "published")}
            disabled={publicando}
          >
            {publicando ? "…" : status === "published" ? "Despublicar" : "Publicar"}
          </button>
        </div>
      </div>

      <div className="hpe-tela">
        {/* ==================================== ESTRUTURA */}
        <aside className="hpe-estrutura">
          <span className="hp-chapa">Estrutura do artigo</span>
          <nav className="hpe-sumario">
            {titulos.length === 0 ? (
              <p className="hpe-vazio">Os títulos que você escrever aparecem aqui.</p>
            ) : (
              titulos.map((t, i) => (
                <span key={`${t.texto}-${i}`} className={t.nivel === 3 ? "hpe-sub" : ""}>
                  {t.texto}
                </span>
              ))
            )}
          </nav>

          <span className="hp-chapa">Blocos</span>
          <div className="hpe-blocos">
            <button type="button" className="hpe-bloco" onClick={() => comando("formatBlock", "<h2>")}>
              <span className="hpe-marca" style={{ background: "#5f31d6" }}><Desenho nome="orcamento" tamanho={14} /></span>
              Título de seção
            </button>
            <button type="button" className="hpe-bloco" onClick={() => comando("formatBlock", "<h3>")}>
              <span className="hpe-marca" style={{ background: "#45209f" }}><Desenho nome="orcamento" tamanho={14} /></span>
              Subtítulo
            </button>
            <button type="button" className="hpe-bloco" onClick={() => inserir(ANDAIME_PASSOS)}>
              <span className="hpe-marca" style={{ background: "#16112b" }}><Desenho nome="producao" tamanho={14} /></span>
              Passo com print
            </button>
            <button type="button" className="hpe-bloco" onClick={() => setPedindoVideo(true)}>
              <span className="hpe-marca" style={{ background: "#f0526e" }}><Desenho nome="chat" tamanho={14} /></span>
              Vídeo do YouTube
            </button>
            <button type="button" className="hpe-bloco" onClick={() => inserir(ANDAIME_AVISO("dica", "Dica"))}>
              <span className="hpe-marca" style={{ background: "#5f31d6" }}><Desenho nome="preco" tamanho={14} /></span>
              Dica
            </button>
            <button type="button" className="hpe-bloco" onClick={() => inserir(ANDAIME_AVISO("atencao", "Atenção"))}>
              <span className="hpe-marca" style={{ background: "#f79c2d" }}><Desenho nome="preco" tamanho={14} /></span>
              Atenção
            </button>
            <button type="button" className="hpe-bloco" onClick={() => inserir(ANDAIME_AVISO("cuidado", "Cuidado"))}>
              <span className="hpe-marca" style={{ background: "#f0526e" }}><Desenho nome="preco" tamanho={14} /></span>
              Cuidado
            </button>
            <button type="button" className="hpe-bloco" onClick={() => inserir(ANDAIME_CAMINHO)}>
              <span className="hpe-marca" style={{ background: "#14c78d" }}><Desenho nome="relatorio" tamanho={14} /></span>
              Caminho no sistema
            </button>
            <button type="button" className="hpe-bloco" onClick={() => inserir(ANDAIME_TABELA)}>
              <span className="hpe-marca" style={{ background: "#2f9bf0" }}><Desenho nome="pedido" tamanho={14} /></span>
              Tabela
            </button>
            <button type="button" className="hpe-bloco" onClick={() => inserir(ANDAIME_PERGUNTA)}>
              <span className="hpe-marca" style={{ background: "#45209f" }}><Desenho nome="chat" tamanho={14} /></span>
              Pergunta
            </button>
            <label className="hpe-bloco" style={{ cursor: enviandoImagem ? "wait" : "pointer" }}>
              <span className="hpe-marca" style={{ background: "#15c5c5" }}><Desenho nome="loja" tamanho={14} /></span>
              {enviandoImagem ? "Enviando…" : "Imagem"}
              <input
                type="file"
                accept="image/*"
                style={{ display: "none" }}
                onChange={(e) => {
                  const f = e.target.files?.[0];
                  if (f) void enviarImagem(f);
                  e.target.value = "";
                }}
              />
            </label>
          </div>
        </aside>

        {/* ======================================== A FOLHA */}
        <main className="hpe-meio">
          <div className="hpe-regua-fora">
            <div className="hpe-regua">
              <select
                className="hpe-select"
                defaultValue="p"
                onChange={(e) => comando("formatBlock", `<${e.target.value}>`)}
              >
                <option value="p">Texto</option>
                <option value="h2">Título de seção</option>
                <option value="h3">Subtítulo</option>
              </select>
              <span className="hpe-sep" />
              <button type="button" className={ferramenta} style={{ fontWeight: 800 }} onClick={() => comando("bold")}>B</button>
              <button type="button" className={ferramenta} style={{ fontStyle: "italic", fontFamily: "Georgia, serif" }} onClick={() => comando("italic")}>I</button>
              <button type="button" className={ferramenta} style={{ textDecoration: "line-through" }} onClick={() => comando("strikeThrough")}>S</button>
              <button
                type="button"
                className={ferramenta}
                onClick={() => {
                  guardarSelecao();
                  setPedindoLink(true);
                }}
              >
                <svg width="15" height="15" viewBox="0 0 24 24" fill="none"><path d="M10.4 13.6a4 4 0 0 0 5.7 0l2.6-2.6a4 4 0 0 0-5.7-5.7l-1.3 1.3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" /><path d="M13.6 10.4a4 4 0 0 0-5.7 0l-2.6 2.6a4 4 0 0 0 5.7 5.7l1.3-1.3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" /></svg>
              </button>
              <span className="hpe-sep" />
              <button type="button" className={ferramenta} onClick={() => comando("insertUnorderedList")}>
                <svg width="15" height="15" viewBox="0 0 24 24" fill="none"><circle cx="4.6" cy="6.4" r="1.6" fill="currentColor" /><circle cx="4.6" cy="12" r="1.6" fill="currentColor" /><circle cx="4.6" cy="17.6" r="1.6" fill="currentColor" /><path d="M9.4 6.4h10M9.4 12h10M9.4 17.6h10" stroke="currentColor" strokeWidth="2" strokeLinecap="round" /></svg>
              </button>
              <button type="button" className={ferramenta} style={{ fontFamily: "var(--fonte-mono)", fontSize: 12 }} onClick={() => comando("insertOrderedList")}>1.</button>
              <span className="hpe-sep" />
              <button type="button" className={ferramenta} onClick={() => inserir(ANDAIME_PASSOS)}>Passo</button>
              <button type="button" className={ferramenta} onClick={() => setPedindoVideo(true)}>Vídeo</button>
              <button type="button" className={ferramenta} onClick={() => inserir(ANDAIME_AVISO("atencao", "Atenção"))}>Aviso</button>
              <button type="button" className={ferramenta} onClick={() => inserir(ANDAIME_TABELA)}>Tabela</button>
              <button type="button" className={ferramenta} onClick={() => inserir(ANDAIME_CAMINHO)}>Caminho</button>
            </div>
          </div>

          {pedindoVideo ? (
            <div className="hpe-pergunta">
              <label className="hp-rot" htmlFor="hpe-video">Endereço do vídeo no YouTube</label>
              <div style={{ display: "flex", gap: 8 }}>
                <input
                  id="hpe-video"
                  className="hp-cx hp-mono"
                  value={enderecoDoVideo}
                  onChange={(e) => setEnderecoDoVideo(e.target.value)}
                  placeholder="https://youtu.be/aX9k2Lm4Qsw"
                  autoFocus
                />
                <button type="button" className="hp-btn hp-btn-marca" onClick={confirmarVideo}>Inserir</button>
                <button type="button" className="hp-btn hp-btn-papel" onClick={() => setPedindoVideo(false)}>Cancelar</button>
              </div>
            </div>
          ) : null}

          {pedindoLink ? (
            <div className="hpe-pergunta">
              <label className="hp-rot" htmlFor="hpe-link">Para onde o link vai</label>
              <div style={{ display: "flex", gap: 8 }}>
                <input
                  id="hpe-link"
                  className="hp-cx hp-mono"
                  value={enderecoDoLink}
                  onChange={(e) => setEnderecoDoLink(e.target.value)}
                  placeholder="https://ktalogu.com.br"
                  autoFocus
                />
                <button
                  type="button"
                  className="hp-btn hp-btn-marca"
                  onClick={() => {
                    if (enderecoDoLink.trim()) comando("createLink", enderecoDoLink.trim());
                    setEnderecoDoLink("");
                    setPedindoLink(false);
                  }}
                >
                  Ligar
                </button>
                <button type="button" className="hp-btn hp-btn-papel" onClick={() => setPedindoLink(false)}>Cancelar</button>
              </div>
            </div>
          ) : null}

          <div className="hpe-papel">
            <div className="hpe-escrita">
              <input
                className="hpe-titulo"
                value={title}
                onChange={(e) => {
                  setTitle(e.target.value);
                  agendarSalvamento();
                }}
                placeholder="Do que trata este artigo?"
              />
              <textarea
                className="hpe-sub"
                rows={2}
                value={subtitle}
                onChange={(e) => {
                  setSubtitle(e.target.value);
                  agendarSalvamento();
                }}
                placeholder="Uma ou duas frases dizendo por que vale ler."
              />
              <div
                ref={folha}
                className="hpe-corpo"
                contentEditable
                suppressContentEditableWarning
                onInput={aoDigitar}
                onBlur={guardarSelecao}
                onKeyUp={guardarSelecao}
                onMouseUp={guardarSelecao}
                dangerouslySetInnerHTML={{ __html: inicial?.body_html ?? "<p><br /></p>" }}
              />
            </div>
          </div>
        </main>

        {/* ======================================= AJUSTES */}
        <aside className="hpe-ajustes">
          <div className="hpe-grupo">
            <span className="hp-chapa">Onde vive</span>
            <label className="hp-rot" htmlFor="hpe-secao">Seção</label>
            <select
              id="hpe-secao"
              className="hp-cx"
              value={sectionId}
              onChange={(e) => {
                setSectionId(e.target.value);
                agendarSalvamento();
              }}
            >
              {secoes.length === 0 ? <option value="">Nenhuma seção ainda</option> : null}
              {secoes.map((s) => (
                <option key={s.id} value={s.id}>{s.title}</option>
              ))}
            </select>

            <label className="hp-rot" htmlFor="hpe-slug">Endereço</label>
            <input
              id="hpe-slug"
              className="hp-cx hp-mono"
              value={slug}
              onChange={(e) => {
                setSlug(e.target.value);
                agendarSalvamento();
              }}
              placeholder={faxinarSlug(title) || "abrir-e-fechar-o-caixa"}
            />
            <p className="hpe-nota hp-mono">{enderecoFinal}</p>

            <span className="hp-rot">Nível</span>
            <div className="hpe-niveis">
              {NIVEIS.map((n) => (
                <button
                  key={n}
                  type="button"
                  className="hpe-nivel"
                  data-ativo={level === n ? "1" : "0"}
                  onClick={() => {
                    setLevel(n);
                    agendarSalvamento();
                  }}
                >
                  {ROTULO_DO_NIVEL[n]}
                </button>
              ))}
            </div>
          </div>

          <div className="hpe-grupo">
            <span className="hp-chapa">Palavras que levam até aqui</span>
            <p className="hpe-nota">Além do título. É o que a busca do centro de aprendizado procura.</p>
            <div className="hpe-palavras">
              {keywords.map((k) => (
                <button
                  key={k}
                  type="button"
                  className="hpe-palavra"
                  onClick={() => {
                    setKeywords((antes) => antes.filter((x) => x !== k));
                    agendarSalvamento();
                  }}
                  title="Tirar"
                >
                  {k} ×
                </button>
              ))}
            </div>
            <div style={{ display: "flex", gap: 7, marginTop: 8 }}>
              <input
                className="hp-cx"
                value={novaPalavra}
                onChange={(e) => setNovaPalavra(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === "Enter") {
                    e.preventDefault();
                    adicionarPalavra();
                  }
                }}
                placeholder="caixa, gaveta, fechamento"
              />
              <button type="button" className="hp-btn hp-btn-papel" style={{ height: 44, padding: "0 14px" }} onClick={adicionarPalavra}>
                Somar
              </button>
            </div>
          </div>

          <div className="hpe-grupo">
            <span className="hp-chapa">Publicação</span>
            <div className="hpe-niveis">
              <button type="button" className="hpe-nivel" data-ativo={status === "draft" ? "1" : "0"} onClick={() => void salvar(false)}>
                Rascunho
              </button>
              <button type="button" className="hpe-nivel" data-ativo={status === "published" ? "1" : "0"} onClick={() => void salvar(true)}>
                No ar
              </button>
            </div>

            <label className="hpe-chave">
              <input
                type="checkbox"
                checked={needsReview}
                onChange={(e) => {
                  setNeedsReview(e.target.checked);
                  agendarSalvamento();
                }}
              />
              <span>
                <b>Marcar para revisar</b>
                <small>Aparece numa aba própria do painel, sem sair do ar.</small>
              </span>
            </label>

            <p className="hpe-nota">
              Publicado, o artigo aparece em <span className="hp-mono">{base.replace(/^https?:\/\//, "")}</span> em até um minuto.
            </p>
          </div>

          {erro ? <div className="hp-aviso-erro">{erro}</div> : null}
        </aside>
      </div>
    </div>
  );
}
