import { useEffect, useMemo, useState } from 'react';
import { DataPanel } from './DataPanel';
import {
  createBotFlowNode,
  deleteBotFlowNode,
  getBotFlow,
  listBotFlowVersions,
  publishBotFlow,
  updateBotFlowNode,
} from '../services/knowledgeService';

const fieldStyle = {
  width: '100%',
  border: '1px solid var(--color-border)',
  borderRadius: 14,
  padding: '0.78rem 0.9rem',
  background: '#fff',
  color: 'var(--color-text)',
  fontWeight: 600,
};

const primaryButton = {
  border: 'none',
  borderRadius: 14,
  padding: '0.78rem 1rem',
  background: 'var(--color-primary)',
  color: '#fff',
  fontWeight: 800,
};

const ghostButton = {
  border: '1px solid var(--color-border)',
  borderRadius: 14,
  padding: '0.72rem 0.9rem',
  background: '#fff',
  color: 'var(--color-text)',
  fontWeight: 800,
};

const emptyDraft = {
  nodeType: 'question',
  title: '',
  messageText: '',
  keywords: '',
  fallbackMessage: '',
  fallbackAttempts: 2,
  fallbackAreaId: '',
  areaId: '',
};

const closeDefaultMessage = 'Perfeito, vou encerrar por aqui. Se precisar de algo mais, é só chamar novamente.';

function nodeTypeLabel(type) {
  if (type === 'greeting') return 'Saudação';
  if (type === 'agent') return 'Enviar para agente';
  if (type === 'close') return 'Encerrar pelo bot';
  return 'Pergunta';
}

function splitKeywords(value) {
  return String(value || '')
    .split(',')
    .map((keyword) => keyword.trim())
    .filter(Boolean);
}

function collectPublishWarnings(node, warnings = []) {
  if (!node) return warnings;
  const children = node.children || [];
  const isTerminal = node.node_type === 'agent' || node.node_type === 'close';
  if (!isTerminal && children.length === 0) {
    warnings.push(`"${node.title}" precisa ter pelo menos um filho.`);
  }
  if (node.node_type === 'agent' && !node.area_id) {
    warnings.push(`"${node.title}" precisa de uma especialidade.`);
  }
  children.forEach((child) => collectPublishWarnings(child, warnings));
  return warnings;
}

function getFlowNodeWidth(level) {
  return level >= 2 ? 260 : 300;
}

function getFlowChildGap(level) {
  return level >= 2 ? 56 : 40;
}

function getFlowSubtreeWidth(node, level = 0) {
  if (!node) return getFlowNodeWidth(level);
  const children = node.children || [];
  const nodeWidth = getFlowNodeWidth(level);
  const horizontalPadding = level >= 2 ? 56 : 72;

  if (!children.length) {
    return nodeWidth + horizontalPadding;
  }

  const gap = getFlowChildGap(level);
  const childrenWidth =
    children.reduce((total, child) => total + getFlowSubtreeWidth(child, level + 1), 0) +
    Math.max(0, children.length - 1) * gap;

  return Math.max(nodeWidth + horizontalPadding, childrenWidth);
}

function WhatsAppPreview({ message }) {
  return (
    <div
      style={{
        background: '#e7f5ef',
        borderRadius: 18,
        padding: '0.85rem',
        display: 'grid',
        gap: '0.45rem',
      }}
    >
      <span style={{ color: 'var(--color-text-soft)', fontSize: '0.78rem', fontWeight: 800 }}>Preview WhatsApp</span>
      <div
        style={{
          justifySelf: 'start',
          maxWidth: 420,
          borderRadius: '0 14px 14px 14px',
          background: '#fff',
          padding: '0.75rem 0.85rem',
          boxShadow: '0 8px 22px rgba(0, 49, 80, 0.08)',
          whiteSpace: 'pre-wrap',
          lineHeight: 1.45,
        }}
      >
        {message || 'Digite a mensagem para visualizar aqui.'}
      </div>
    </div>
  );
}

function FlowNode({ node, areasById, onAdd, onEdit, onDelete, level = 0, parentTitle = '' }) {
  const keywords = splitKeywords(node.keywords);
  const isRoot = node.node_type === 'greeting';
  const isAgent = node.node_type === 'agent';
  const isClose = node.node_type === 'close';
  const isDeep = level >= 2;
  const nodeWidth = getFlowNodeWidth(level);
  const visibleKeywordLimit = isDeep ? 4 : 8;
  const childGap = getFlowChildGap(level);
  const subtreeWidth = getFlowSubtreeWidth(node, level);
  const firstChildWidth = node.children?.length ? getFlowSubtreeWidth(node.children[0], level + 1) : 0;
  const lastChildWidth = node.children?.length
    ? getFlowSubtreeWidth(node.children[node.children.length - 1], level + 1)
    : 0;
  const accentColor = isRoot
    ? 'var(--color-primary)'
    : isAgent
      ? '#3260b3'
      : isClose
        ? '#0f8f77'
        : 'var(--color-highlight)';
  const nodeMessage = node.message_text || (isAgent ? '' : 'Sem mensagem configurada.');

  return (
    <div
      style={{
        display: 'grid',
        justifyItems: 'center',
        gap: '0.95rem',
        minWidth: subtreeWidth,
        width: subtreeWidth,
      }}
    >
      <article
        style={{
          width: nodeWidth,
          border: '1px solid var(--color-border)',
          borderTop: `5px solid ${accentColor}`,
          borderRadius: 18,
          background: isRoot
            ? 'linear-gradient(180deg, #fff, rgba(0,164,183,0.09))'
            : isAgent
              ? 'linear-gradient(180deg, #fff, rgba(50,96,179,0.09))'
              : isClose
                ? 'linear-gradient(180deg, #fff, rgba(0,164,183,0.1))'
                : '#fff',
          boxShadow: '0 12px 28px rgba(0, 49, 80, 0.08)',
          padding: isDeep ? '0.8rem' : '0.95rem',
          display: 'grid',
          gap: '0.7rem',
        }}
      >
        <div style={{ display: 'flex', justifyContent: 'space-between', gap: '0.7rem', alignItems: 'start' }}>
          <div style={{ minWidth: 0 }}>
            <div style={{ display: 'flex', gap: '0.4rem', alignItems: 'center', flexWrap: 'wrap', marginBottom: '0.15rem' }}>
              <span style={{ color: 'var(--color-primary)', fontSize: '0.74rem', fontWeight: 900, textTransform: 'uppercase' }}>
                {nodeTypeLabel(node.node_type)}
              </span>
              <span
                style={{
                  borderRadius: 999,
                  padding: '0.12rem 0.42rem',
                  background: 'rgba(0,49,80,0.06)',
                  color: 'var(--color-text-soft)',
                  fontSize: '0.68rem',
                  fontWeight: 900,
                }}
              >
                Nível {level + 1}
              </span>
            </div>
            <strong style={{ display: 'block', lineHeight: 1.25 }}>{node.title}</strong>
            {!isRoot && parentTitle ? (
              <span style={{ display: 'block', marginTop: '0.22rem', color: 'var(--color-text-soft)', fontSize: '0.78rem', fontWeight: 700 }}>
                abaixo de: {parentTitle}
              </span>
            ) : null}
          </div>
          {!isAgent && !isClose && onAdd ? (
            <button
              type="button"
              onClick={() => onAdd(node)}
              title="Adicionar filho"
              style={{
                width: 34,
                height: 34,
                borderRadius: 12,
                border: 'none',
                background: 'var(--color-highlight)',
                color: '#132534',
                fontWeight: 900,
              }}
            >
              +
            </button>
          ) : null}
        </div>

        {isAgent ? (
          <span style={{ color: 'var(--color-text-soft)', lineHeight: 1.35 }}>
            Fila: {node.area_nome || areasById.get(Number(node.area_id))?.nome || 'não definida'}
          </span>
        ) : isClose ? (
          <span style={{ color: 'var(--color-text-soft)', lineHeight: 1.35, whiteSpace: 'pre-wrap' }}>
            {isDeep && nodeMessage.length > 96 ? `${nodeMessage.slice(0, 96)}...` : nodeMessage}
          </span>
        ) : (
          <span style={{ color: 'var(--color-text-soft)', whiteSpace: isDeep ? 'normal' : 'pre-wrap', lineHeight: 1.35 }}>
            {isDeep && nodeMessage.length > 96 ? `${nodeMessage.slice(0, 96)}...` : nodeMessage}
          </span>
        )}

        {!isRoot && keywords.length ? (
          <div style={{ display: 'grid', gap: '0.35rem' }}>
            <span style={{ color: 'var(--color-text-soft)', fontSize: '0.72rem', fontWeight: 900 }}>
              Respostas que chegam aqui
            </span>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.35rem' }}>
              {keywords.slice(0, visibleKeywordLimit).map((keyword) => (
                <span
                  key={keyword}
                  style={{
                    borderRadius: 999,
                    background: 'rgba(0,49,80,0.07)',
                    padding: '0.22rem 0.5rem',
                    fontSize: '0.75rem',
                    fontWeight: 800,
                  }}
                >
                  {keyword}
                </span>
              ))}
              {keywords.length > visibleKeywordLimit ? (
                <span
                  style={{
                    borderRadius: 999,
                    background: 'rgba(0,49,80,0.04)',
                    padding: '0.22rem 0.5rem',
                    fontSize: '0.75rem',
                    fontWeight: 800,
                    color: 'var(--color-text-soft)',
                  }}
                >
                  +{keywords.length - visibleKeywordLimit}
                </span>
              ) : null}
            </div>
          </div>
        ) : null}

        <div style={{ display: 'flex', gap: '0.45rem', flexWrap: 'wrap' }}>
          {onEdit ? (
            <button type="button" onClick={() => onEdit(node)} style={{ ...ghostButton, padding: '0.55rem 0.7rem' }}>
              Editar
            </button>
          ) : null}
          {!isRoot && onDelete ? (
            <button
              type="button"
              onClick={() => onDelete(node)}
              style={{
                ...ghostButton,
                padding: '0.55rem 0.7rem',
                color: 'var(--color-secondary)',
              }}
            >
              Remover
            </button>
          ) : null}
        </div>
      </article>

      {node.children?.length ? (
        <>
          <div
            style={{
              width: 2,
              height: 38,
              background: 'linear-gradient(180deg, rgba(0,49,80,0.28), rgba(0,49,80,0.1))',
            }}
          />
          <div
            style={{
              display: 'flex',
              gap: childGap,
              alignItems: 'start',
              justifyContent: 'center',
              flexWrap: 'nowrap',
              paddingTop: 34,
              position: 'relative',
              width: '100%',
            }}
          >
            {node.children.length > 1 ? (
              <div
                aria-hidden="true"
                style={{
                  position: 'absolute',
                  top: 0,
                  left: firstChildWidth / 2,
                  right: lastChildWidth / 2,
                  height: 2,
                  background: 'rgba(0,49,80,0.16)',
                }}
              />
            ) : null}
            {node.children.map((child) => {
              const childWidth = getFlowSubtreeWidth(child, level + 1);

              return (
                <div
                  key={child.id}
                  style={{
                    position: 'relative',
                    display: 'grid',
                    justifyItems: 'center',
                    minWidth: childWidth,
                    width: childWidth,
                  }}
                >
                  <div
                    aria-hidden="true"
                    style={{
                      position: 'absolute',
                      top: -34,
                      left: '50%',
                      width: 2,
                      height: 34,
                      background: 'rgba(0,49,80,0.2)',
                      transform: 'translateX(-50%)',
                    }}
                  />
                  <FlowNode
                    node={child}
                    areasById={areasById}
                    onAdd={onAdd}
                    onEdit={onEdit}
                    onDelete={onDelete}
                    level={level + 1}
                    parentTitle={node.title}
                  />
                </div>
              );
            })}
          </div>
        </>
      ) : null}
    </div>
  );
}

function NodeModal({ mode, node, parent, areas, draft, onDraftChange, onClose, onSave }) {
  if (!mode) return null;
  const isEdit = mode === 'edit';
  const isRoot = node?.node_type === 'greeting';
  const isAgent = draft.nodeType === 'agent' || node?.node_type === 'agent';
  const isClose = draft.nodeType === 'close' || node?.node_type === 'close';
  const canChooseType = !isEdit;

  function change(key, value) {
    onDraftChange((current) => ({ ...current, [key]: value }));
  }

  return (
    <div
      style={{
        position: 'fixed',
        inset: 0,
        background: 'rgba(0, 20, 32, 0.42)',
        display: 'grid',
        placeItems: 'center',
        zIndex: 50,
        padding: '1rem',
      }}
    >
      <section
        style={{
          width: 'min(760px, calc(100vw - 2rem))',
          maxHeight: 'calc(100vh - 2rem)',
          overflowY: 'auto',
          borderRadius: 24,
          background: '#fff',
          boxShadow: 'var(--shadow-lg)',
          padding: '1.25rem',
          display: 'grid',
          gap: '1rem',
        }}
      >
        <header style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem', alignItems: 'start' }}>
          <div>
            <h2 style={{ margin: 0, fontSize: '1.25rem' }}>
              {isEdit ? 'Editar nó' : `Adicionar filho em ${parent?.title}`}
            </h2>
            <p style={{ margin: '0.35rem 0 0', color: 'var(--color-text-soft)' }}>
              Configure a mensagem, as palavras que ativam o caminho e o destino quando for terminal.
            </p>
          </div>
          <button type="button" onClick={onClose} style={ghostButton}>Fechar</button>
        </header>

        {canChooseType ? (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
            {[
              ['question', 'Adicionar pergunta'],
              ['agent', 'Enviar para agente'],
              ['close', 'Encerrar pelo bot'],
            ].map(([type, label]) => (
              <button
                key={type}
                type="button"
                onClick={() => change('nodeType', type)}
                style={{
                  border: `1px solid ${draft.nodeType === type ? 'var(--color-primary)' : 'var(--color-border)'}`,
                  borderRadius: 16,
                  padding: '0.9rem',
                  background: draft.nodeType === type ? 'rgba(0,164,183,0.08)' : '#fff',
                  color: 'var(--color-text)',
                  fontWeight: 900,
                }}
              >
                {label}
              </button>
            ))}
          </div>
        ) : null}

        <div style={{ display: 'grid', gap: '0.75rem' }}>
          <label style={{ display: 'grid', gap: '0.35rem' }}>
            <span style={{ fontWeight: 800 }}>Título interno</span>
            <input value={draft.title || ''} onChange={(event) => change('title', event.target.value)} style={fieldStyle} />
          </label>

          {!isRoot ? (
            <label style={{ display: 'grid', gap: '0.35rem' }}>
              <span style={{ fontWeight: 800 }}>Keywords que ativam este nó</span>
              <input
                value={draft.keywords || ''}
                onChange={(event) => change('keywords', event.target.value)}
                placeholder="Ex: 1, colaborador, ativo, funcionário"
                style={fieldStyle}
              />
            </label>
          ) : null}

          {isAgent ? (
            <label style={{ display: 'grid', gap: '0.35rem' }}>
              <span style={{ fontWeight: 800 }}>Especialidade de destino</span>
              <select value={draft.areaId || ''} onChange={(event) => change('areaId', event.target.value)} style={fieldStyle}>
                <option value="">Selecione</option>
                {areas.map((area) => (
                  <option key={area.id} value={area.id}>{area.nome}</option>
                ))}
              </select>
            </label>
          ) : isClose ? (
            <>
              <label style={{ display: 'grid', gap: '0.35rem' }}>
                <span style={{ fontWeight: 800 }}>Mensagem de encerramento</span>
                <textarea
                  rows={4}
                  value={draft.messageText || ''}
                  onChange={(event) => change('messageText', event.target.value)}
                  placeholder="Ex: Perfeito, vou encerrar por aqui. Se precisar de algo mais, é só chamar."
                  style={{ ...fieldStyle, resize: 'vertical' }}
                />
              </label>
              <WhatsAppPreview message={draft.messageText} />
            </>
          ) : (
            <>
              <label style={{ display: 'grid', gap: '0.35rem' }}>
                <span style={{ fontWeight: 800 }}>Mensagem enviada pelo bot</span>
                <textarea
                  rows={5}
                  value={draft.messageText || ''}
                  onChange={(event) => change('messageText', event.target.value)}
                  style={{ ...fieldStyle, resize: 'vertical' }}
                />
              </label>
              <WhatsAppPreview message={draft.messageText} />
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 140px minmax(180px, 0.5fr)', gap: '0.75rem' }}>
                <label style={{ display: 'grid', gap: '0.35rem' }}>
                  <span style={{ fontWeight: 800 }}>Mensagem de fallback</span>
                  <input
                    value={draft.fallbackMessage || ''}
                    onChange={(event) => change('fallbackMessage', event.target.value)}
                    style={fieldStyle}
                  />
                </label>
                <label style={{ display: 'grid', gap: '0.35rem' }}>
                  <span style={{ fontWeight: 800 }}>Tentativas</span>
                  <input
                    type="number"
                    min="1"
                    max="5"
                    value={draft.fallbackAttempts || 2}
                    onChange={(event) => change('fallbackAttempts', event.target.value)}
                    style={fieldStyle}
                  />
                </label>
                <label style={{ display: 'grid', gap: '0.35rem' }}>
                  <span style={{ fontWeight: 800 }}>Fila de fallback</span>
                  <select
                    value={draft.fallbackAreaId || ''}
                    onChange={(event) => change('fallbackAreaId', event.target.value)}
                    style={fieldStyle}
                  >
                    <option value="">Herdar/Suporte</option>
                    {areas.map((area) => (
                      <option key={area.id} value={area.id}>{area.nome}</option>
                    ))}
                  </select>
                </label>
              </div>
            </>
          )}
        </div>

        <footer style={{ display: 'flex', justifyContent: 'flex-end', gap: '0.75rem' }}>
          <button type="button" onClick={onClose} style={ghostButton}>Cancelar</button>
          <button type="button" onClick={onSave} style={primaryButton}>Salvar</button>
        </footer>
      </section>
    </div>
  );
}

export function KnowledgeBasePanel({ areas, mode = 'admin', isMobile = false }) {
  const canEdit = mode === 'admin';
  const [flow, setFlow] = useState(null);
  const [versions, setVersions] = useState([]);
  const [status, setStatus] = useState('');
  const [statusTone, setStatusTone] = useState('info');
  const [isPublishing, setIsPublishing] = useState(false);
  const [zoom, setZoom] = useState(0.92);
  const [modalMode, setModalMode] = useState(null);
  const [selectedNode, setSelectedNode] = useState(null);
  const [parentNode, setParentNode] = useState(null);
  const [draft, setDraft] = useState(emptyDraft);

  const areasById = useMemo(() => new Map(areas.map((area) => [Number(area.id), area])), [areas]);

  async function load() {
    try {
      const [flowData, versionData] = await Promise.all([getBotFlow(), listBotFlowVersions()]);
      setFlow(flowData);
      setVersions(Array.isArray(versionData) ? versionData : []);
    } catch (error) {
      setStatus(error.message);
      setStatusTone('error');
    }
  }

  useEffect(() => {
    load();
  }, []);

  function openAdd(node) {
    setParentNode(node);
    setSelectedNode(null);
    setDraft({ ...emptyDraft });
    setModalMode('add');
  }

  function openEdit(node) {
    setSelectedNode(node);
    setParentNode(null);
    setDraft({
      nodeType: node.node_type,
      title: node.title || '',
      messageText: node.message_text || '',
      keywords: node.keywords || '',
      fallbackMessage: node.fallback_message || '',
      fallbackAttempts: node.fallback_attempts || 2,
      fallbackAreaId: node.fallback_area_id || '',
      areaId: node.area_id || '',
    });
    setModalMode('edit');
  }

  function closeModal() {
    setModalMode(null);
    setSelectedNode(null);
    setParentNode(null);
    setDraft(emptyDraft);
  }

  async function saveNode() {
    try {
      const messageText =
        draft.nodeType === 'close' && !draft.messageText.trim()
          ? closeDefaultMessage
          : draft.messageText;
      const payload = {
        nodeType: draft.nodeType,
        title: draft.title,
        messageText,
        keywords: draft.keywords,
        fallbackMessage: draft.fallbackMessage,
        fallbackAttempts: Number(draft.fallbackAttempts || 2),
        fallbackAreaId: draft.fallbackAreaId ? Number(draft.fallbackAreaId) : null,
        areaId: draft.areaId ? Number(draft.areaId) : null,
      };

      if (modalMode === 'add') {
        await createBotFlowNode({ ...payload, parentId: parentNode.id });
        setStatus('Nó adicionado ao fluxo.');
        setStatusTone('success');
      } else {
        await updateBotFlowNode(selectedNode.id, payload);
        setStatus('Nó atualizado.');
        setStatusTone('success');
      }

      closeModal();
      await load();
    } catch (error) {
      setStatus(error.message);
      setStatusTone('error');
    }
  }

  async function removeNode(node) {
    if (!window.confirm(`Remover "${node.title}" e todos os filhos?`)) return;
    try {
      await deleteBotFlowNode(node.id);
      await load();
      setStatus('Nó removido.');
      setStatusTone('success');
    } catch (error) {
      setStatus(error.message);
      setStatusTone('error');
    }
  }

  async function publish() {
    setIsPublishing(true);
    setStatus('Publicando fluxo...');
    setStatusTone('info');
    try {
      await publishBotFlow();
      await load();
      setStatus('Fluxo publicado. As novas conversas passam a usar esta árvore.');
      setStatusTone('success');
    } catch (error) {
      setStatus(error.message);
      setStatusTone('error');
    } finally {
      setIsPublishing(false);
    }
  }

  const root = flow?.tree;
  const hasPublished = Boolean(flow?.latestPublished);
  const publishWarnings = useMemo(() => collectPublishWarnings(root).slice(0, 5), [root]);
  const treeMinWidth = useMemo(() => Math.max(1100, getFlowSubtreeWidth(root)), [root]);

  return (
    <div style={{ display: 'grid', gap: '1rem' }}>
      <DataPanel
        title="Fluxo do Bot"
        description="Monte a árvore de decisão do Agente Virtual Sothis. O fluxo só entra em produção depois de publicado."
      >
        <div style={{ display: 'grid', gap: '1rem' }}>
          <div
            style={{
              display: 'grid',
              gridTemplateColumns: isMobile ? '1fr' : 'minmax(0, 1fr) auto auto',
              gap: '0.75rem',
              alignItems: 'center',
            }}
          >
            <div style={{ display: 'grid', gap: '0.25rem' }}>
              <strong>{hasPublished ? `Publicado: versão ${flow.latestPublished.version_number}` : 'Nenhum fluxo publicado ainda'}</strong>
              <span style={{ color: 'var(--color-text-soft)' }}>
                Draft atual: edite livremente e publique apenas quando estiver consistente.
              </span>
            </div>
            <label style={{ display: 'flex', alignItems: 'center', gap: '0.6rem', fontWeight: 800 }}>
              Zoom
              <input
                type="range"
                min="0.65"
                max="1.15"
                step="0.05"
                value={zoom}
                onChange={(event) => setZoom(Number(event.target.value))}
              />
            </label>
            {canEdit ? (
              <button
                type="button"
                onClick={publish}
                disabled={isPublishing}
                style={{
                  ...primaryButton,
                  opacity: isPublishing ? 0.72 : 1,
                  cursor: isPublishing ? 'wait' : 'pointer',
                }}
              >
                {isPublishing ? 'Publicando...' : 'Publicar fluxo'}
              </button>
            ) : null}
          </div>

          {publishWarnings.length ? (
            <div
              style={{
                border: '1px solid rgba(241,184,42,0.45)',
                borderRadius: 16,
                background: 'rgba(241,184,42,0.12)',
                padding: '0.85rem 1rem',
                color: 'var(--color-text)',
                display: 'grid',
                gap: '0.35rem',
              }}
            >
              <strong>Antes de publicar</strong>
              {publishWarnings.map((warning) => (
                <span key={warning} style={{ color: 'var(--color-text-soft)', fontWeight: 700 }}>
                  {warning}
                </span>
              ))}
            </div>
          ) : null}

          <div
            style={{
              border: '1px solid var(--color-border)',
              borderRadius: 22,
              background:
                'linear-gradient(180deg, #fff, rgba(0,49,80,0.03)), radial-gradient(circle at 1px 1px, rgba(0,49,80,0.08) 1px, transparent 0)',
              backgroundSize: 'auto, 22px 22px',
              overflow: 'auto',
              minHeight: 520,
              padding: '1.25rem',
            }}
          >
            <div
              style={{
                transform: `scale(${zoom})`,
                transformOrigin: 'top center',
                minWidth: treeMinWidth,
                minHeight: 480,
                display: 'grid',
                justifyContent: 'center',
                alignContent: 'start',
              }}
            >
              {root ? (
                <FlowNode
                  node={root}
                  areasById={areasById}
                  onAdd={canEdit ? openAdd : null}
                  onEdit={canEdit ? openEdit : null}
                  onDelete={canEdit ? removeNode : null}
                />
              ) : (
                <span style={{ color: 'var(--color-text-soft)', fontWeight: 800 }}>Carregando árvore...</span>
              )}
            </div>
          </div>

          {status ? (
            <span
              style={{
                borderRadius: 14,
                padding: '0.75rem 0.85rem',
                background:
                  statusTone === 'error'
                    ? 'rgba(181,31,31,0.08)'
                    : statusTone === 'success'
                      ? 'rgba(0,164,183,0.09)'
                      : 'rgba(0,49,80,0.06)',
                color: statusTone === 'error' ? 'var(--color-secondary)' : 'var(--color-primary)',
                fontWeight: 800,
              }}
            >
              {status}
            </span>
          ) : null}
        </div>
      </DataPanel>

      <DataPanel
        title="Histórico de versões"
        description="Cada publicação gera uma versão. Nesta primeira etapa o histórico é consultivo; restauração pode ser ligada na próxima rodada."
      >
        <div style={{ display: 'grid', gap: '0.55rem', maxHeight: 220, overflowY: 'auto' }}>
          {versions.length ? versions.map((version) => (
            <div
              key={version.id}
              style={{
                border: '1px solid var(--color-border)',
                borderRadius: 14,
                padding: '0.75rem 0.85rem',
                display: 'flex',
                justifyContent: 'space-between',
                gap: '1rem',
              }}
            >
              <strong>Versão {version.version_number}</strong>
              <span style={{ color: 'var(--color-text-soft)' }}>
                {version.published_at ? new Date(version.published_at).toLocaleString('pt-BR') : 'Sem data'}
              </span>
            </div>
          )) : (
            <span style={{ color: 'var(--color-text-soft)' }}>Nenhuma versão publicada.</span>
          )}
        </div>
      </DataPanel>

      <NodeModal
        mode={modalMode}
        node={selectedNode}
        parent={parentNode}
        areas={areas}
        draft={draft}
        onDraftChange={setDraft}
        onClose={closeModal}
        onSave={saveNode}
      />
    </div>
  );
}
