/**
 * WhatsAppInbox — clone visual do motor NewWhats
 *
 * Layout idêntico ao newwhats.local:
 *   [ThinSidebar 60px] [Painel Esquerdo 400px] [Área de Chat flex-1]
 *
 * Paleta exata do WhatsApp Web:
 *   bg sidebar/header: #f0f2f5 | border: #d1d7db
 *   text primary: #111b21 | text secondary: #667781
 *   green: #00a884 | incoming bubble: white | outgoing: #d9fdd3
 *   status read: #53bdeb | muted/icons: #8696a0
 */
import React, {
  useState, useEffect, useRef, useCallback, useMemo,
} from 'react';
import ReactDOM from 'react-dom';
import {
  MessageCircle, Smartphone, Settings,
  ChevronDown, RefreshCw, MoreVertical, Search,
  ArrowLeft, Phone, Wifi, WifiOff, QrCode,
  Pin, PinOff, Archive, ArchiveRestore,
  Check, CheckCheck, Clock, AlertCircle,
  Mic, FileText, Video, Image as ImageIcon, Star, StarOff,
  Smile, Paperclip, Send, X,
  MessageSquare, Sparkles, MailOpen,
  Plus, Edit2, Trash2, ShieldCheck,
  Bot, Brain, CalendarDays, MessagesSquare, KeyRound, User,
  Save, Loader2, ToggleLeft, ToggleRight,
  UserCheck, FlaskConical, AlertTriangle, Users, Inbox,
  ArrowRightCircle, Siren, BarChart3,
  BookOpen, LayoutTemplate,
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { EscalationService, AdminMeService } from '../services/api';
import { NwService, type NwSession, type NwChat, type NwMessage, type NwNumber, type NwTemplateType, type NwTemplate } from '../services/api';
import EquipeTab from './EquipeTab';
import InboxInternaTab from './InboxInternaTab';
import MetricasTab from './MetricasTab';
import RichMessageComposer from '../components/RichMessageComposer';
import TemplateLibrary from '../components/TemplateLibrary';
import ScheduleMessageModal from '../components/ScheduleMessageModal';

// ─── WS envelope ──────────────────────────────────────────────────────────────
interface WsEnvelope { event: string; data: any; timestamp: number }

// ─── Avatar helpers ───────────────────────────────────────────────────────────
const AVATAR_COLORS = [
  '#00a884','#25d366','#128c7e','#34b7f1',
  '#7b68ee','#ff6b6b','#f59e0b','#10b981',
];
function avatarColor(str: string): string {
  let h = 0;
  for (let i = 0; i < str.length; i++) h = str.charCodeAt(i) + ((h << 5) - h);
  return AVATAR_COLORS[Math.abs(h) % AVATAR_COLORS.length];
}
function avatarInitials(name?: string | null): string {
  if (!name) return '?';
  const parts = name.trim().split(/\s+/);
  if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
  return name.trim().charAt(0).toUpperCase();
}

// ─── Timestamp helper ─────────────────────────────────────────────────────────
function fmtTime(ts: string | null | undefined): string {
  if (!ts) return '';
  const d = new Date(ts);
  if (isNaN(d.getTime())) return '';
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const msgDay = new Date(d); msgDay.setHours(0, 0, 0, 0);
  const diff = Math.round((today.getTime() - msgDay.getTime()) / 86400000);
  if (diff === 0) return d.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
  if (diff === 1) return 'Ontem';
  if (diff < 7) return d.toLocaleDateString('pt-BR', { weekday: 'short' }).replace('.', '').replace(/^\w/, c => c.toUpperCase());
  return d.toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit', year: '2-digit' });
}
function fmtFullTime(ts: string | null | undefined): string {
  if (!ts) return '';
  const d = new Date(ts);
  if (isNaN(d.getTime())) return '';
  return d.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
}
function dateSeparator(ts: string): string {
  const d = new Date(ts);
  if (isNaN(d.getTime())) return '';
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const msgDay = new Date(d); msgDay.setHours(0, 0, 0, 0);
  const diff = Math.round((today.getTime() - msgDay.getTime()) / 86400000);
  if (diff === 0) return 'Hoje';
  if (diff === 1) return 'Ontem';
  return d.toLocaleDateString('pt-BR', { day: '2-digit', month: 'long', year: 'numeric' });
}
function isSameCalDay(a: string, b: string): boolean {
  const da = new Date(a); const db = new Date(b);
  return da.getFullYear() === db.getFullYear() && da.getMonth() === db.getMonth() && da.getDate() === db.getDate();
}

// ═════════════════════════════════════════════════════════════════════════════
// Sub-components
// ═════════════════════════════════════════════════════════════════════════════

// ─── AvatarEl ─────────────────────────────────────────────────────────────────
function AvatarEl({
  src, name, size = 40, className = '',
}: { src?: string | null; name?: string | null; size?: number; className?: string }) {
  const [err, setErr] = useState(false);
  useEffect(() => setErr(false), [src]);
  const bg = avatarColor(name || '?');
  const initials = avatarInitials(name);
  return (
    <div
      className={`rounded-full overflow-hidden flex-shrink-0 flex items-center justify-center border border-black/5 ${className}`}
      style={{ width: size, height: size, backgroundColor: err || !src ? bg : 'transparent' }}
    >
      {src && !err
        ? <img src={src} alt={name ?? ''} className="w-full h-full object-cover" onError={() => setErr(true)} />
        : <span className="font-semibold text-white select-none" style={{ fontSize: size * 0.38 }}>{initials}</span>
      }
    </div>
  );
}

// ─── StatusBadge (sessão) ──────────────────────────────────────────────────────
const SESSION_STATUS: Record<NwSession['status'], { label: string; bg: string; dot: string }> = {
  CONNECTED:    { label: 'Conectado',    bg: 'bg-[#00a884]/10 text-[#00a884] border-[#00a884]/20', dot: 'bg-[#00a884] animate-pulse' },
  QR_PENDING:   { label: 'Aguard. QR',  bg: 'bg-amber-500/10 text-amber-600 border-amber-500/20', dot: 'bg-amber-500 animate-pulse' },
  CONNECTING:   { label: 'Conectando',  bg: 'bg-blue-500/10  text-blue-600  border-blue-500/20',  dot: 'bg-blue-500  animate-pulse' },
  DISCONNECTED: { label: 'Desconect.',  bg: 'bg-[#f0f2f5]    text-[#667781] border-[#d1d7db]',   dot: 'bg-[#8696a0]' },
  BANNED:       { label: 'Banido',      bg: 'bg-red-50       text-red-600   border-red-200',      dot: 'bg-red-500' },
};
function SessionBadge({ status }: { status: NwSession['status'] }) {
  const { label, bg, dot } = SESSION_STATUS[status] ?? SESSION_STATUS.DISCONNECTED;
  return (
    <span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[11px] font-semibold border ${bg}`}>
      <span className={`w-1.5 h-1.5 rounded-full ${dot}`} />
      {label}
    </span>
  );
}

// ─── MsgStatusIcon (lista de chats + mensagens) ───────────────────────────────
function MsgStatusIcon({ status, size = 14 }: { status: string; size?: number }) {
  if (status === 'READ')      return <CheckCheck size={size} className="text-[#53bdeb] flex-shrink-0" />;
  if (status === 'DELIVERED') return <CheckCheck size={size} className="text-[#8696a0] flex-shrink-0" />;
  if (status === 'SENT')      return <Check      size={size} className="text-[#8696a0] flex-shrink-0" />;
  if (status === 'PENDING')   return <Clock      size={size} className="text-[#8696a0] flex-shrink-0" />;
  if (status === 'FAILED')    return <AlertCircle size={size} className="text-red-500 flex-shrink-0" />;
  return null;
}

// ─── LastMsgSnippet ────────────────────────────────────────────────────────────
function LastMsgSnippet({ chat }: { chat: NwChat }) {
  const lm = chat.lastMessage;
  if (!lm) return <span className="italic">Sem mensagens</span>;
  const icon = (() => {
    const t = lm.type?.toUpperCase();
    if (t === 'IMAGE' || t === 'STICKER') return <ImageIcon size={13} className="text-[#8696a0] flex-shrink-0" />;
    if (t === 'VIDEO')    return <Video    size={13} className="text-[#8696a0] flex-shrink-0" />;
    if (t === 'AUDIO' || t === 'PTT') return <Mic size={13} className="text-[#8696a0] flex-shrink-0" />;
    if (t === 'DOCUMENT') return <FileText size={13} className="text-[#8696a0] flex-shrink-0" />;
    return null;
  })();
  const text = lm.body || (lm.type !== 'TEXT' ? lm.type : '');
  return (
    <span className="flex items-center gap-1 truncate">
      {icon}
      {text || <span className="italic text-[#8696a0]">[mídia]</span>}
    </span>
  );
}

// ─── ChatListItem ──────────────────────────────────────────────────────────────
const CHAT_MENU_H = 244; // 6 itens × ~38px + 16px padding
const CHAT_MENU_W = 224;

function ChatListItem({
  chat, isActive, onSelect, onArchive, onPin, onMarkRead, onDelete,
}: {
  chat: NwChat; isActive: boolean; onSelect: () => void;
  onArchive:  (archived: boolean) => void;
  onPin:      (pinned: boolean)   => void;
  onMarkRead: () => void;
  onDelete:   () => void;
}) {
  const name = chat.displayName ?? chat.phone;
  const [menuPos, setMenuPos] = useState<{ top: number; left: number } | null>(null);
  const [favorite, setFavorite] = useState(false);
  const chevronRef = useRef<HTMLButtonElement>(null);

  const openMenu = (anchorX: number, anchorY: number, anchorBottom?: number) => {
    const triggerBottom = anchorBottom ?? anchorY;
    const spaceBelow = window.innerHeight - triggerBottom;
    const top  = spaceBelow >= CHAT_MENU_H + 8 ? triggerBottom + 4 : anchorY - CHAT_MENU_H;
    const left = Math.min(anchorX, window.innerWidth - CHAT_MENU_W - 8);
    setMenuPos({ top: Math.max(8, top), left: Math.max(8, left) });
  };

  const menuItems = [
    { key: 'favorite', label: favorite ? 'Remover favorito' : 'Favoritar',         icon: favorite ? <StarOff size={15}/> : <Star size={15}/> },
    { key: 'archive',  label: chat.isArchived ? 'Desarquivar' : 'Arquivar',         icon: chat.isArchived ? <ArchiveRestore size={15}/> : <Archive size={15}/> },
    { key: 'pin',      label: chat.isPinned   ? 'Desafixar'   : 'Fixar conversa',   icon: chat.isPinned   ? <PinOff size={15}/>         : <Pin size={15}/> },
    { key: 'read',     label: 'Marcar como lida',                                    icon: <MailOpen size={15}/> },
    { key: 'delete',   label: 'Apagar conversa',                                     icon: <Trash2 size={15}/>, danger: true },
  ];

  const handleMenuAction = (key: string) => {
    setMenuPos(null);
    if (key === 'favorite') setFavorite(f => !f);
    if (key === 'archive')  onArchive(!chat.isArchived);
    if (key === 'pin')      onPin(!chat.isPinned);
    if (key === 'read')     onMarkRead();
    if (key === 'delete')   onDelete();
  };

  return (
    <>
      <div
        role="button"
        tabIndex={0}
        onClick={onSelect}
        onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && onSelect()}
        onContextMenu={e => {
          e.preventDefault();
          const spaceRight = window.innerWidth - e.clientX;
          const x = spaceRight >= CHAT_MENU_W + 8 ? e.clientX : e.clientX - CHAT_MENU_W;
          openMenu(Math.max(8, x), e.clientY, e.clientY);
        }}
        className={`w-full flex items-center gap-3 px-3 py-2.5 transition-all cursor-pointer select-none group
          border-b border-[#f0f2f5] last:border-none focus:outline-none focus-visible:ring-2 focus-visible:ring-[#00a884]/40
          ${isActive ? 'bg-[#f0f2f5]' : 'hover:bg-[#f5f6f6]'}`}
      >
        <AvatarEl src={chat.avatar} name={name} size={49} />
        <div className="flex-1 min-w-0 flex flex-col justify-center py-0.5 pr-1">

          {/* Row 1: nome + timestamp (sempre visível) */}
          <div className="flex items-center justify-between">
            <h3 className="text-[16px] leading-[21px] font-normal text-[#111b21] truncate">{name}</h3>
            <span className={`text-[12px] leading-[14px] flex-shrink-0 ml-2 ${chat.unreadCount > 0 ? 'text-[#00a884] font-medium' : 'text-[#667781]'}`}>
              {fmtTime(chat.lastMessageAt)}
            </span>
          </div>

          {/* Row 2: preview + badges + chevron (hover) */}
          <div className="flex items-center justify-between mt-1 h-5">
            <div className="flex items-center gap-1 flex-1 min-w-0 text-[13px] leading-5 text-[#667781] truncate">
              {chat.lastMessage?.fromMe && <MsgStatusIcon status={chat.lastMessage.status} size={13} />}
              <span className="truncate"><LastMsgSnippet chat={chat} /></span>
            </div>
            <div className="flex items-center gap-1.5 flex-shrink-0 ml-1">
              {chat.isPinned && <Pin size={14} className="text-[#8696a0]" />}
              {chat.unreadCount > 0 && (
                <span className="bg-[#00a884] text-white text-[12px] font-bold px-1.5 min-w-[20px] h-5 rounded-full flex items-center justify-center">
                  {chat.unreadCount > 99 ? '99+' : chat.unreadCount}
                </span>
              )}
              {/* Chevron — visível apenas no hover, posicionado aqui na row 2 como no newwhats */}
              <div className="hidden group-hover:block">
                <button
                  ref={chevronRef}
                  onClick={e => {
                    e.stopPropagation();
                    const r = chevronRef.current?.getBoundingClientRect();
                    if (r) openMenu(r.right - CHAT_MENU_W, r.top, r.bottom);
                  }}
                  className="p-1 rounded-full hover:bg-black/5"
                  title="Opções"
                >
                  <ChevronDown size={16} className="text-[#8696a0]" />
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* Menu via portal para evitar clipping */}
      {menuPos && typeof window !== 'undefined' && ReactDOM.createPortal(
        <>
          <div className="fixed inset-0 z-[1000]" onClick={() => setMenuPos(null)} />
          <div
            className="fixed bg-white py-1.5 rounded-lg shadow-xl border border-gray-100 z-[1001] flex flex-col"
            style={{ top: menuPos.top, left: menuPos.left, width: CHAT_MENU_W }}
            onClick={e => e.stopPropagation()}
          >
            {menuItems.map(item => (
              <button
                key={item.key}
                onClick={() => handleMenuAction(item.key)}
                className={`flex items-center gap-3 px-4 py-2.5 text-sm transition-colors text-left
                  ${item.danger ? 'text-red-600 hover:bg-red-50' : 'text-[#3b4a54] hover:bg-[#f5f6f6]'}`}
              >
                <span className={item.danger ? 'text-red-500' : 'text-[#8696a0]'}>{item.icon}</span>
                {item.label}
              </button>
            ))}
          </div>
        </>,
        document.body
      )}
    </>
  );
}

// ─── nwMediaUrl — constrói URL via proxy do satélite ─────────────────────────
function nwMediaUrl(msg: NwMessage): string | null {
  if (!msg.mediaUrl) return null;
  return `/api/nw/v1/media/${msg.id}`;
}

// ─── ImageBubble — lazy load + skeleton + lightbox ───────────────────────────
function ImageBubble({ msg, TimeEl, TimeRow, Spacer }: {
  msg: NwMessage; TimeEl: React.ReactNode; TimeRow: React.ReactNode; Spacer: React.ReactNode;
}) {
  const [loaded, setLoaded] = useState(false);
  const [err,    setErr]    = useState(false);
  const src = nwMediaUrl(msg);

  if (!src || err) {
    return (
      <div>
        <div className="flex items-center justify-center w-48 h-32 bg-black/5 rounded-lg">
          <ImageIcon size={28} className="text-[#8696a0]" />
        </div>
        {TimeRow}
      </div>
    );
  }

  return (
    <div className="rounded-lg overflow-hidden">
      {!loaded && (
        <div className="w-48 h-32 bg-black/5 animate-pulse rounded-lg" />
      )}
      <img
        src={src}
        alt="Imagem"
        loading="lazy"
        className={`max-w-full max-h-[300px] object-cover block cursor-pointer ${loaded ? '' : 'hidden'}`}
        onLoad={() => setLoaded(true)}
        onError={() => setErr(true)}
        onClick={() => window.open(src, '_blank')}
      />
      {msg.caption && loaded && (
        <div className="relative px-1 pt-1.5 pb-0.5">
          <p className="text-[14.2px] break-words whitespace-pre-wrap leading-[1.6] text-[#111b21]">
            {msg.caption}{Spacer}
          </p>
          <div className="absolute bottom-0.5 right-1">{TimeEl}</div>
        </div>
      )}
      {(!msg.caption && loaded) && <div className="px-1 pb-0.5">{TimeRow}</div>}
    </div>
  );
}

// ─── MessageBubble ─────────────────────────────────────────────────────────────
function MessageBubble({
  msg, showTail, showSender, senderName,
}: {
  msg: NwMessage;
  showTail: boolean;
  showSender: boolean;
  senderName?: string;
}) {
  const isOut = msg.fromMe;
  const timeStr = fmtFullTime(msg.timestamp);

  const spacerW = isOut ? 62 : 42;
  const Spacer = (
    <span
      className="inline-block pointer-events-none select-none opacity-0 align-bottom"
      style={{ width: spacerW, height: 14 }}
      aria-hidden
    />
  );
  const TimeEl = (
    <span className="inline-flex items-center gap-[3px] text-[11px] text-[#667781] leading-none select-none flex-shrink-0">
      {timeStr}
      {isOut && <MsgStatusIcon status={msg.status} size={12} />}
    </span>
  );
  const TimeRow = (
    <div className="flex items-center justify-end gap-[3px] mt-1 pr-0.5">
      {TimeEl}
    </div>
  );

  const renderContent = () => {
    const t = msg.type?.toUpperCase();
    const src = nwMediaUrl(msg);

    if (t === 'IMAGE') {
      return <ImageBubble msg={msg} TimeEl={TimeEl} TimeRow={TimeRow} Spacer={Spacer} />;
    }

    if (t === 'VIDEO') {
      return (
        <div>
          {src ? (
            <video
              src={src}
              controls
              preload="metadata"
              className="max-w-full max-h-[300px] rounded-lg block bg-black/10"
              style={{ minWidth: 240 }}
            />
          ) : (
            <div className="flex items-center justify-center w-60 h-36 bg-black/10 rounded-lg">
              <Video size={28} className="text-[#8696a0]" />
            </div>
          )}
          {TimeRow}
        </div>
      );
    }

    if (t === 'AUDIO' || t === 'PTT') {
      return (
        <div className="min-w-[220px]">
          {src ? (
            <audio controls preload="metadata" className="w-full h-10 rounded-lg">
              <source src={src} type={msg.mimeType || 'audio/ogg'} />
            </audio>
          ) : (
            <div className="flex items-center gap-2 text-[#667781] italic text-[13px]">
              <Mic size={14} /> Áudio indisponível
            </div>
          )}
          {TimeRow}
        </div>
      );
    }

    if (t === 'DOCUMENT') {
      const ext = msg.mimeType?.split('/')[1]?.toUpperCase() || 'FILE';
      return (
        <div>
          <a
            href={src ?? '#'}
            download={msg.fileName ?? 'arquivo'}
            target="_blank"
            rel="noreferrer"
            className="flex items-center gap-3 bg-[#f0f2f5] p-3 rounded-xl border border-black/5 hover:bg-gray-200 transition-all no-underline"
          >
            <div className="w-10 h-10 bg-[#00a884]/10 rounded-lg flex items-center justify-center text-[#00a884] flex-shrink-0">
              <FileText size={22} />
            </div>
            <div className="flex flex-col min-w-0">
              <span className="text-[14px] font-normal truncate text-[#111b21]">{msg.fileName || msg.body || 'Documento'}</span>
              <span className="text-[11px] text-[#667781] uppercase mt-0.5">{ext}</span>
            </div>
          </a>
          {TimeRow}
        </div>
      );
    }

    if (t === 'STICKER') {
      return (
        <div>
          {src
            ? <img src={src} alt="Sticker" loading="lazy" className="max-w-[180px] max-h-[180px]" />
            : <div className="flex items-center gap-2 text-[13px] text-[#667781] italic"><Star size={14} /> Figurinha</div>
          }
          {TimeRow}
        </div>
      );
    }

    // Default: text
    const body = msg.body || msg.caption;
    if (!body) {
      return (
        <div>
          <div className="flex items-center gap-2 text-[12px] text-[#8696a0] italic">
            <AlertCircle size={12} /> Mensagem não disponível
          </div>
          {TimeRow}
        </div>
      );
    }
    return (
      <p className="text-[14.2px] break-words whitespace-pre-wrap leading-[1.6] text-[#111b21]">
        {body}
        <span style={{ float: 'right', marginLeft: 6, position: 'relative', bottom: -3 }}>
          {TimeEl}
        </span>
      </p>
    );
  };

  return (
    <div className={`flex w-full mb-[2px] ${isOut ? 'justify-end pr-4' : 'justify-start pl-4'}`}>
      <div className="flex flex-col max-w-[75%] relative">
        {showSender && senderName && !isOut && (
          <span className="text-[11px] font-bold text-[#00a884] mb-1 ml-2 truncate">{senderName}</span>
        )}
        <div
          className={`px-2 py-1.5 rounded-lg shadow-[0_1px_0.5px_rgba(11,20,26,0.13)] relative overflow-visible
            ${isOut
              ? `bg-[#d9fdd3] ${showTail ? 'rounded-tr-none' : ''}`
              : `bg-white    ${showTail ? 'rounded-tl-none' : ''}`
            }`}
        >
          {showTail && (
            <div
              className="absolute top-0 pointer-events-none"
              style={{
                [isOut ? 'right' : 'left']: -8,
                width: 10, height: 14,
                backgroundColor: isOut ? '#d9fdd3' : '#ffffff',
                clipPath: isOut
                  ? 'polygon(0 0, 100% 0, 0 100%)'
                  : 'polygon(100% 0, 0 0, 100% 100%)',
              }}
            />
          )}
          {renderContent()}
        </div>
      </div>
    </div>
  );
}

// ─── DateSeparator ─────────────────────────────────────────────────────────────
function DateSeparator({ label }: { label: string }) {
  return (
    <div className="flex items-center justify-center my-3">
      <span className="bg-[#e1f3fb] text-[#54656f] text-[12.5px] px-3 py-[3px] rounded-full shadow-sm border border-[#cde9f4]/60 select-none">
        {label}
      </span>
    </div>
  );
}

// ─── NewConversationModal ─────────────────────────────────────────────────────
function normalizePhone(input: string): string {
  const d = input.replace(/\D/g, '');
  if (d.startsWith('55') && (d.length === 12 || d.length === 13)) return d;
  if (d.length === 10 || d.length === 11) return '55' + d;
  return d;
}

interface NewConversationModalProps {
  sessionId: string;
  onClose: () => void;
  onSent: () => void;
}
function NewConversationModal({ sessionId, onClose, onSent }: NewConversationModalProps) {
  const [phone,   setPhone]   = useState('');
  const [text,    setText]    = useState('');
  const [sending, setSending] = useState(false);
  const [sent,    setSent]    = useState(false);
  const [error,   setError]   = useState('');
  const phoneRef = useRef<HTMLInputElement>(null);
  const textRef  = useRef<HTMLTextAreaElement>(null);

  useEffect(() => { setTimeout(() => phoneRef.current?.focus(), 80); }, []);

  const handleSubmit = async () => {
    const normalized = normalizePhone(phone);
    if (normalized.length < 10) {
      setError('Número inválido. Ex: 67 99913-8794');
      phoneRef.current?.focus();
      return;
    }
    if (!text.trim()) {
      setError('Escreva uma mensagem para iniciar');
      textRef.current?.focus();
      return;
    }
    setSending(true); setError('');
    try {
      await NwService.startConversation(sessionId, normalized, text.trim());
      setSent(true);
      setTimeout(() => { onSent(); onClose(); }, 1200);
    } catch (e: any) {
      setError(e?.response?.data?.error ?? e.message ?? 'Erro ao enviar');
      setSending(false);
    }
  };

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm p-4" onClick={!sending ? onClose : undefined}>
      <div className="bg-white rounded-2xl shadow-2xl w-full max-w-sm overflow-hidden" onClick={e => e.stopPropagation()}>
        {/* Header */}
        <div className="flex items-center justify-between px-5 py-4 border-b border-gray-100">
          <div className="flex items-center gap-2">
            <div className="w-8 h-8 rounded-full bg-[#00a884]/10 flex items-center justify-center">
              <MessageSquare size={14} className="text-[#00a884]" />
            </div>
            <h3 className="text-[15px] font-bold text-[#111b21]">Nova Conversa</h3>
          </div>
          <button onClick={onClose} disabled={sending} className="p-1.5 hover:bg-gray-100 rounded-full transition-colors">
            <X size={18} className="text-[#667781]" />
          </button>
        </div>

        {/* Body */}
        <div className="p-5 space-y-4">
          <div>
            <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">Número do WhatsApp</label>
            <input
              ref={phoneRef}
              type="text"
              value={phone}
              onChange={e => { setPhone(e.target.value.replace(/[^\d\s\-()+]/g, '')); setError(''); }}
              onKeyDown={e => e.key === 'Enter' && textRef.current?.focus()}
              placeholder="Ex: 67 99913-8794"
              disabled={sending || sent}
              className="w-full px-3 py-2.5 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] focus:ring-2 focus:ring-[#00a884]/10 transition-all disabled:opacity-50"
            />
          </div>
          <div>
            <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">Primeira mensagem</label>
            <textarea
              ref={textRef}
              value={text}
              onChange={e => { setText(e.target.value); setError(''); }}
              onKeyDown={e => { if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); handleSubmit(); }}}
              rows={3}
              placeholder="Olá! Tudo bem?"
              disabled={sending || sent}
              className="w-full px-3 py-2.5 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] focus:ring-2 focus:ring-[#00a884]/10 resize-none transition-all disabled:opacity-50"
            />
            <p className="text-[11px] text-[#8696a0] mt-1">Ctrl+Enter para enviar</p>
          </div>
          {error && <p className="text-red-500 text-[13px] font-medium">{error}</p>}
        </div>

        {/* Footer */}
        <div className="px-5 pb-5">
          <button
            onClick={handleSubmit}
            disabled={!phone.trim() || !text.trim() || sending || sent}
            className="w-full py-2.5 rounded-xl font-semibold text-[14px] transition-all bg-[#00a884] text-white hover:bg-[#008f6e] disabled:opacity-40 disabled:cursor-not-allowed flex items-center justify-center gap-2"
          >
            {sent ? (
              <><Check size={16} /> Enviado!</>
            ) : sending ? (
              <><div className="w-4 h-4 border-2 border-white/40 border-t-white rounded-full animate-spin" /> Enviando…</>
            ) : (
              <><Send size={15} /> Iniciar Conversa</>
            )}
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── Number role/priority constants ──────────────────────────────────────────
const ROLE_LABELS: Record<string, string> = {
  notificacoes: 'Notificações',
  entregas:     'Entregas',
  suporte:      'Suporte',
  marketing:    'Marketing',
  geral:        'Geral',
};
const ROLE_COLORS: Record<string, string> = {
  notificacoes: 'bg-blue-100 text-blue-700 border-blue-200',
  entregas:     'bg-orange-100 text-orange-700 border-orange-200',
  suporte:      'bg-purple-100 text-purple-700 border-purple-200',
  marketing:    'bg-pink-100 text-pink-700 border-pink-200',
  geral:        'bg-gray-100 text-gray-600 border-gray-200',
};
const PRIORITY_LABELS: Record<number, string> = {
  1: 'Principal',
  2: 'Fallback',
  3: 'Terciário',
  4: '4º',
  5: '5º',
};

// ─── NumberBadge ──────────────────────────────────────────────────────────────
function NumberBadge({ role, priority }: { role: string; priority: number }) {
  const color = ROLE_COLORS[role] ?? ROLE_COLORS.geral;
  const label = ROLE_LABELS[role] ?? role;
  const pLabel = PRIORITY_LABELS[priority] ?? `P${priority}`;
  return (
    <div className="flex items-center gap-1 flex-wrap">
      <span className={`text-[10px] font-semibold px-1.5 py-0.5 rounded border ${color}`}>{label}</span>
      <span className="text-[10px] font-semibold px-1.5 py-0.5 rounded border bg-slate-100 text-slate-600 border-slate-200">{pLabel}</span>
    </div>
  );
}

// ─── AddNumberModal ───────────────────────────────────────────────────────────
function AddNumberModal({ onClose, onCreated }: {
  onClose: () => void;
  onCreated: () => void;
}) {
  const [step, setStep]       = useState<'form' | 'qr'>('form');
  const [label, setLabel]     = useState('');
  const [role, setRole]       = useState('geral');
  const [area, setArea]       = useState('');
  const [priority, setPriority] = useState(1);
  const [notes, setNotes]     = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError]     = useState('');
  const [qrBase64, setQrBase64] = useState('');
  const [polling, setPolling] = useState(false);

  const handleCreate = async () => {
    if (!label.trim()) { setError('Informe um nome/apelido para o número.'); return; }
    setLoading(true); setError('');
    try {
      const sess = await NwService.createSession(label.trim());
      await NwService.saveNumber({
        instance_id: sess.id,
        label:       label.trim(),
        role,
        area:        area.trim() || null,
        priority,
        notes:       notes.trim() || null,
      });
      setStep('qr');
      // Poll QR
      setPolling(true);
      let attempts = 0;
      const poll = setInterval(async () => {
        attempts++;
        try {
          const qr = await NwService.getQr(sess.id);
          setQrBase64(qr.qrBase64);
          clearInterval(poll);
          setPolling(false);
        } catch {
          if (attempts >= 15) { clearInterval(poll); setPolling(false); }
        }
      }, 2000);
    } catch (e: any) {
      setError(e?.response?.data?.error ?? e.message ?? 'Erro ao criar sessão');
    } finally { setLoading(false); }
  };

  const handleDone = () => { onCreated(); onClose(); };

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm p-4">
      <div className="bg-white rounded-2xl shadow-2xl w-full max-w-md overflow-hidden">
        {/* Header */}
        <div className="flex items-center justify-between px-5 py-4 border-b border-gray-100">
          <div className="flex items-center gap-2">
            <div className="w-8 h-8 rounded-full bg-[#00a884]/10 flex items-center justify-center">
              {step === 'form' ? <Plus size={16} className="text-[#00a884]" /> : <QrCode size={16} className="text-[#00a884]" />}
            </div>
            <h3 className="text-[15px] font-bold text-[#111b21]">
              {step === 'form' ? 'Novo Número WhatsApp' : 'Escanear QR Code'}
            </h3>
          </div>
          <button onClick={onClose} className="p-1.5 hover:bg-gray-100 rounded-full transition-colors">
            <X size={18} className="text-[#667781]" />
          </button>
        </div>

        {step === 'form' ? (
          <div className="p-5 space-y-4">
            {/* Label */}
            <div>
              <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">Apelido / Nome</label>
              <input
                type="text"
                value={label}
                onChange={e => setLabel(e.target.value)}
                placeholder="Ex: Atendimento Principal, Entregas, Marketing…"
                className="w-full px-3 py-2.5 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] focus:ring-2 focus:ring-[#00a884]/10 transition-all"
              />
            </div>
            {/* Role */}
            <div>
              <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">Função</label>
              <select
                value={role}
                onChange={e => setRole(e.target.value)}
                className="w-full px-3 py-2.5 pr-8 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] bg-white bg-[url('data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2212%22 height=%2212%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%238696a0%22 stroke-width=%222%22><polyline points=%226 9 12 15 18 9%22/></svg>')] bg-no-repeat bg-[right_12px_center] appearance-none cursor-pointer"
              >
                {Object.entries(ROLE_LABELS).map(([k, v]) => (
                  <option key={k} value={k}>{v}</option>
                ))}
              </select>
            </div>
            {/* Priority + Area */}
            <div className="grid grid-cols-2 gap-3">
              <div>
                <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">Prioridade</label>
                <select
                  value={priority}
                  onChange={e => setPriority(Number(e.target.value))}
                  className="w-full px-3 py-2.5 pr-8 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] bg-white bg-[url('data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2212%22 height=%2212%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%238696a0%22 stroke-width=%222%22><polyline points=%226 9 12 15 18 9%22/></svg>')] bg-no-repeat bg-[right_12px_center] appearance-none cursor-pointer"
                >
                  {[1,2,3,4,5].map(p => (
                    <option key={p} value={p}>{PRIORITY_LABELS[p] ?? `P${p}`}</option>
                  ))}
                </select>
              </div>
              <div>
                <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">Área (opcional)</label>
                <input
                  type="text"
                  value={area}
                  onChange={e => setArea(e.target.value)}
                  placeholder="Ex: Campo Grande"
                  className="w-full px-3 py-2.5 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] transition-all"
                />
              </div>
            </div>
            {/* Notes */}
            <div>
              <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">Observações (opcional)</label>
              <textarea
                value={notes}
                onChange={e => setNotes(e.target.value)}
                rows={2}
                placeholder="Ex: Fallback quando o principal cair"
                className="w-full px-3 py-2.5 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] resize-none transition-all"
              />
            </div>
            {error && <p className="text-red-500 text-[13px] font-medium">{error}</p>}
            <button
              onClick={handleCreate}
              disabled={loading || !label.trim()}
              className="w-full py-3 bg-[#00a884] hover:bg-[#017f67] disabled:opacity-50 text-white font-bold rounded-xl transition-all text-[14px] flex items-center justify-center gap-2"
            >
              {loading
                ? <span className="w-4 h-4 border-2 border-white/40 border-t-white rounded-full animate-spin" />
                : <QrCode size={16} />
              }
              {loading ? 'Criando sessão…' : 'Criar e gerar QR Code'}
            </button>
          </div>
        ) : (
          <div className="p-5 flex flex-col items-center gap-4">
            <p className="text-[13px] text-[#667781] text-center">
              Abra o WhatsApp no celular → Menu → Aparelhos conectados → Conectar aparelho
            </p>
            {polling && !qrBase64 ? (
              <div className="w-52 h-52 rounded-2xl bg-[#f0f2f5] flex flex-col items-center justify-center gap-3">
                <div className="w-8 h-8 border-2 border-[#00a884] border-t-transparent rounded-full animate-spin" />
                <p className="text-[12px] text-[#667781]">Aguardando QR…</p>
              </div>
            ) : qrBase64 ? (
              <img src={qrBase64} alt="QR Code" className="w-52 h-52 rounded-2xl border-2 border-[#00a884]/20 bg-white p-2" />
            ) : (
              <div className="w-52 h-52 rounded-2xl bg-[#f0f2f5] flex items-center justify-center text-[#667781] text-[13px] italic text-center px-4">
                QR não disponível. Verifique a aba Sessões.
              </div>
            )}
            <p className="text-[11px] text-[#8696a0] text-center">
              O QR expira em 60 s. Após conectar, feche este modal.
            </p>
            <button
              onClick={handleDone}
              className="w-full py-2.5 bg-[#00a884] hover:bg-[#017f67] text-white font-bold rounded-xl transition-all text-[14px]"
            >
              Concluído
            </button>
          </div>
        )}
      </div>
    </div>
  );
}

// ─── UpdateSessionModal ───────────────────────────────────────────────────────
// Edita metadados do número E permite reconectar via novo QR na mesma tela.
// Aceita num=null quando a sessão ainda não tem registro em sec_numbers (cria novo).
function UpdateSessionModal({ num, session, onClose, onSaved }: {
  num: NwNumber | null;
  session: NwSession | undefined;
  onClose: () => void;
  onSaved: () => void;
}) {
  const [label, setLabel]       = useState(num?.label ?? session?.name ?? '');
  const [role, setRole]         = useState(num?.role ?? 'geral');
  const [area, setArea]         = useState(num?.area ?? '');
  const [priority, setPriority] = useState(num?.priority ?? 1);
  const [notes, setNotes]       = useState(num?.notes ?? '');
  const [active, setActive]     = useState(num?.active ?? true);
  const [saving, setSaving]     = useState(false);
  const [error, setError]       = useState('');
  const [saved, setSaved]       = useState(false);

  // QR reconexão
  const [qrBase64,   setQrBase64]   = useState<string>(session?.id ? '' : '');
  const [loadingQr,  setLoadingQr]  = useState(false);
  const [qrError,    setQrError]    = useState('');

  // Se sessão já está em QR_PENDING, carrega o QR automaticamente
  useEffect(() => {
    if (session?.status === 'QR_PENDING' && session.id) {
      fetchQr(session.id);
    }
  }, []);

  async function fetchQr(sessionId: string) {
    setLoadingQr(true); setQrError('');
    let attempts = 0;
    const poll = setInterval(async () => {
      attempts++;
      try {
        const d = await NwService.getQr(sessionId);
        setQrBase64(d.qrBase64);
        clearInterval(poll);
        setLoadingQr(false);
      } catch {
        if (attempts >= 15) {
          clearInterval(poll);
          setLoadingQr(false);
          setQrError('QR não disponível. Tente novamente.');
        }
      }
    }, 2000);
  }

  const handleReconnect = async () => {
    if (!session?.id) return;
    setQrBase64(''); setQrError('');
    await fetchQr(session.id);
  };

  const handleSave = async () => {
    if (!label.trim()) { setError('Apelido obrigatório.'); return; }
    setSaving(true); setError('');
    try {
      if (num) {
        // Atualiza registro existente
        await NwService.updateNumber(num.id, {
          label: label.trim(), role,
          area: area.trim() || null, priority,
          notes: notes.trim() || null, active,
        });
      } else {
        // Cria novo registro para sessão existente
        if (!session?.id) throw new Error('Sessão não identificada');
        await NwService.saveNumber({
          instance_id: session.id,
          label: label.trim(), role,
          area: area.trim() || null, priority,
          notes: notes.trim() || null,
        });
      }
      setSaved(true);
      onSaved();
      setTimeout(() => setSaved(false), 2000);
    } catch (e: any) {
      setError(e?.response?.data?.error ?? e.message ?? 'Erro ao salvar');
    } finally { setSaving(false); }
  };

  const isDisconnected = session && session.status !== 'CONNECTED';

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm p-4">
      <div className="bg-white rounded-2xl shadow-2xl w-full max-w-md overflow-hidden max-h-[90vh] flex flex-col">

        {/* Header */}
        <div className="flex items-center justify-between px-5 py-4 border-b border-gray-100 flex-shrink-0">
          <div className="flex items-center gap-2">
            <div className="w-8 h-8 rounded-full bg-[#00a884]/10 flex items-center justify-center">
              <Smartphone size={14} className="text-[#00a884]" />
            </div>
            <div>
              <h3 className="text-[15px] font-bold text-[#111b21] leading-tight">Atualizar Número</h3>
              {session && (
                <p className="text-[11px] text-[#8696a0] leading-tight font-mono">{session.phone ?? session.id}</p>
              )}
            </div>
          </div>
          <button onClick={onClose} className="p-1.5 hover:bg-gray-100 rounded-full transition-colors">
            <X size={18} className="text-[#667781]" />
          </button>
        </div>

        {/* Body — scroll */}
        <div className="flex-1 overflow-y-auto p-5 space-y-4">

          {/* ── Campos ──────────────────────────────────────────────── */}
          <div>
            <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">
              Apelido / Nome
            </label>
            <input
              type="text"
              value={label}
              onChange={e => setLabel(e.target.value)}
              placeholder="Ex: Atendimento Principal, Entregas, Marketing…"
              className="w-full px-3 py-2.5 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] focus:ring-2 focus:ring-[#00a884]/10 transition-all"
            />
          </div>

          <div>
            <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">
              Função
            </label>
            <select
              value={role}
              onChange={e => setRole(e.target.value)}
              className="w-full px-3 py-2.5 pr-8 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] bg-white bg-[url('data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2212%22 height=%2212%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%238696a0%22 stroke-width=%222%22><polyline points=%226 9 12 15 18 9%22/></svg>')] bg-no-repeat bg-[right_12px_center] appearance-none cursor-pointer"
            >
              {Object.entries(ROLE_LABELS).map(([k, v]) => (
                <option key={k} value={k}>{v}</option>
              ))}
            </select>
          </div>

          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">
                Prioridade
              </label>
              <select
                value={priority}
                onChange={e => setPriority(Number(e.target.value))}
                className="w-full px-3 py-2.5 pr-8 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] bg-white bg-[url('data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2212%22 height=%2212%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%238696a0%22 stroke-width=%222%22><polyline points=%226 9 12 15 18 9%22/></svg>')] bg-no-repeat bg-[right_12px_center] appearance-none cursor-pointer"
              >
                {[1,2,3,4,5].map(p => (
                  <option key={p} value={p}>{PRIORITY_LABELS[p] ?? `P${p}`}</option>
                ))}
              </select>
            </div>
            <div>
              <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">
                Área (opcional)
              </label>
              <input
                type="text"
                value={area}
                onChange={e => setArea(e.target.value)}
                placeholder="Ex: Campo Grande"
                className="w-full px-3 py-2.5 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] transition-all"
              />
            </div>
          </div>

          <div>
            <label className="block text-[12px] font-semibold text-[#667781] mb-1.5 uppercase tracking-wide">
              Observações (opcional)
            </label>
            <textarea
              value={notes}
              onChange={e => setNotes(e.target.value)}
              rows={2}
              placeholder="Ex: Fallback quando o principal cair"
              className="w-full px-3 py-2.5 text-[14px] text-[#111b21] border border-gray-200 rounded-xl outline-none focus:border-[#00a884] resize-none transition-all"
            />
          </div>

          {/* Toggle ativo */}
          <label className="flex items-center gap-3 cursor-pointer select-none">
            <div
              onClick={() => setActive(v => !v)}
              className={`relative w-10 h-5 rounded-full transition-colors ${active ? 'bg-[#00a884]' : 'bg-gray-300'}`}
            >
              <div className={`absolute top-0.5 w-4 h-4 bg-white rounded-full shadow transition-transform ${active ? 'translate-x-5' : 'translate-x-0.5'}`} />
            </div>
            <span className="text-[13px] text-[#111b21]">{active ? 'Ativo' : 'Inativo'}</span>
          </label>

          {error && <p className="text-red-500 text-[13px] font-medium">{error}</p>}

          {/* ── Reconexão QR ────────────────────────────────────────── */}
          {session && (
            <div className={`rounded-2xl border p-4 space-y-3 ${
              isDisconnected ? 'border-amber-200 bg-amber-50' : 'border-gray-100 bg-[#f9fafb]'
            }`}>
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-2">
                  <QrCode size={15} className={isDisconnected ? 'text-amber-500' : 'text-[#8696a0]'} />
                  <span className="text-[13px] font-semibold text-[#111b21]">Reconectar número</span>
                </div>
                {session.status && (
                  <SessionBadge status={session.status} />
                )}
              </div>

              {/* QR display */}
              {loadingQr ? (
                <div className="flex flex-col items-center gap-2 py-4">
                  <div className="w-7 h-7 border-2 border-[#00a884] border-t-transparent rounded-full animate-spin" />
                  <p className="text-[12px] text-[#667781]">Gerando QR Code…</p>
                </div>
              ) : qrBase64 ? (
                <div className="flex flex-col items-center gap-2">
                  <img
                    src={qrBase64}
                    alt="QR Code"
                    className="w-44 h-44 rounded-xl border-2 border-[#00a884]/20 bg-white p-2 mx-auto"
                  />
                  <p className="text-[11px] text-[#8696a0] text-center">
                    Abra o WhatsApp → Menu → Aparelhos conectados → Conectar aparelho
                  </p>
                  <p className="text-[10px] text-amber-600 text-center font-semibold">
                    QR expira em ~60s — clique em "Novo QR" se expirar
                  </p>
                </div>
              ) : qrError ? (
                <p className="text-[12px] text-red-500 text-center">{qrError}</p>
              ) : (
                <p className="text-[12px] text-[#8696a0] text-center">
                  {isDisconnected
                    ? 'Sessão desconectada. Gere um QR para reconectar.'
                    : 'Sessão conectada. Gere um novo QR só se precisar reconectar em outro celular.'}
                </p>
              )}

              <button
                onClick={handleReconnect}
                disabled={loadingQr}
                className="w-full py-2 border border-[#00a884] text-[#00a884] hover:bg-[#00a884]/5 disabled:opacity-50 font-semibold rounded-xl transition-all text-[13px] flex items-center justify-center gap-2"
              >
                {loadingQr
                  ? <span className="w-3.5 h-3.5 border border-[#00a884] border-t-transparent rounded-full animate-spin" />
                  : <QrCode size={14} />
                }
                {qrBase64 ? 'Novo QR' : 'Gerar QR Code'}
              </button>
            </div>
          )}
        </div>

        {/* Footer fixo */}
        <div className="px-5 pb-5 pt-3 border-t border-gray-100 flex-shrink-0">
          <button
            onClick={handleSave}
            disabled={saving || !label.trim()}
            className={`w-full py-3 font-bold rounded-xl transition-all text-[14px] flex items-center justify-center gap-2
              ${saved
                ? 'bg-emerald-500 text-white'
                : 'bg-[#00a884] hover:bg-[#017f67] disabled:opacity-50 text-white'
              }`}
          >
            {saving
              ? <span className="w-4 h-4 border-2 border-white/40 border-t-white rounded-full animate-spin" />
              : saved
                ? <ShieldCheck size={16} />
                : <ShieldCheck size={16} />
            }
            {saving ? 'Salvando…' : saved ? 'Salvo ✓' : 'Salvar alterações'}
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── SecretariaTab ────────────────────────────────────────────────────────────
type SecTab = 'agente' | 'cerebro' | 'agenda' | 'conversas' | 'testar' | 'config';

const SEC_TABS: { id: SecTab; Icon: React.ElementType; label: string }[] = [
  { id: 'agente',    Icon: User,            label: 'Agente' },
  { id: 'cerebro',  Icon: Brain,           label: 'Cérebro' },
  { id: 'agenda',   Icon: CalendarDays,    label: 'Agenda' },
  { id: 'conversas',Icon: MessagesSquare,  label: 'Conversas' },
  { id: 'testar',   Icon: FlaskConical,    label: 'Testar' },
  { id: 'config',   Icon: KeyRound,        label: 'Config' },
];

const BRAIN_NODE_TYPES = ['persona','knowledge','rules','calendar','escalation'] as const;
const BRAIN_NODE_COLORS: Record<string, string> = {
  persona: 'bg-purple-100 text-purple-700',
  knowledge: 'bg-blue-100 text-blue-700',
  rules: 'bg-yellow-100 text-yellow-700',
  calendar: 'bg-green-100 text-green-700',
  escalation: 'bg-red-100 text-red-700',
};

function SecretariaTab() {
  const [tab, setTab] = useState<SecTab>('agente');

  // ── Agente state ──────────────────────────────────────────────────────────
  const [agent, setAgent]   = useState<any>(null);
  const [agentForm, setAgentForm] = useState({ name: '', model: 'gpt-4o-mini', provider: 'openai', temperature: 0.7, context_window: 10 });
  const [agentSaving, setAgentSaving] = useState(false);
  const [agentSaved,  setAgentSaved]  = useState(false);

  // ── Cérebro state ─────────────────────────────────────────────────────────
  const [nodes,     setNodes]     = useState<any[]>([]);
  const [nodeForm,  setNodeForm]  = useState({ type: 'persona', title: '', content: '' });
  const [editNode,  setEditNode]  = useState<any>(null);
  const [nodesSaving, setNodesSaving] = useState(false);

  // ── Agenda state ──────────────────────────────────────────────────────────
  const [slots,    setSlots]    = useState<any[]>([]);
  const [slotForm, setSlotForm] = useState({ date: '', time_start: '', time_end: '', attendee: '', notes: '' });
  const [slotsSaving, setSlotsSaving] = useState(false);

  // ── Conversas state ───────────────────────────────────────────────────────
  const [convs,       setConvs]       = useState<any[]>([]);
  const [convFilter,  setConvFilter]  = useState<'all'|'active'|'closed'>('all');
  const [convsLoading,setConvsLoading]= useState(false);
  const [drawerConv,  setDrawerConv]  = useState<any>(null);
  const [drawerMsgs,  setDrawerMsgs]  = useState<any[]>([]);
  const [drawerLoading,setDrawerLoading] = useState(false);
  const [finalizing,  setFinalizing]  = useState(false);

  // ── Testar state ──────────────────────────────────────────────────────────
  const testSessionId = useRef(`test-${Date.now()}`);
  const [testMsg,     setTestMsg]     = useState('');
  const [testHistory, setTestHistory] = useState<{ role: 'user'|'ai'; text: string }[]>([]);
  const [testLoading, setTestLoading] = useState(false);
  const testEndRef = useRef<HTMLDivElement>(null);

  // ── Config state ──────────────────────────────────────────────────────────
  const [cfg, setCfg] = useState({ openai_key: '', gemini_key: '', anthropic_key: '', ollama_url: '', admin_notify_phone: '' });
  const [autoReply, setAutoReply] = useState<'off'|'automatico'>('off');
  const [cfgSaving, setCfgSaving] = useState(false);
  const [cfgSaved,  setCfgSaved]  = useState(false);

  useEffect(() => {
    if (tab === 'agente')     fetchAgent();
    if (tab === 'cerebro')    fetchNodes();
    if (tab === 'agenda')     fetchSlots();
    if (tab === 'conversas')  fetchConvs();
    if (tab === 'config')     fetchConfig();
  }, [tab]);

  useEffect(() => {
    testEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [testHistory]);

  // ── Fetchers ──────────────────────────────────────────────────────────────
  async function fetchAgent() {
    try {
      const d = await NwService.secGetAgent();
      setAgent(d);
      if (d) setAgentForm({ name: d.name, model: d.model, provider: d.provider, temperature: d.temperature, context_window: d.context_window });
    } catch {}
  }
  async function fetchNodes() {
    try { setNodes(await NwService.secGetNodes()); } catch {}
  }
  async function fetchSlots() {
    try { setSlots(await NwService.secGetSlots()); } catch {}
  }
  async function fetchConvs() {
    setConvsLoading(true);
    try { setConvs(await NwService.secGetConversations()); } catch {}
    finally { setConvsLoading(false); }
  }
  async function fetchConfig() {
    try {
      const [keys, mode] = await Promise.all([NwService.secGetKeys(), NwService.getAutoReplyMode()]);
      setCfg(keys);
      setAutoReply(mode.mode);
    } catch {}
  }

  async function openDrawer(conv: any) {
    setDrawerConv(conv);
    setDrawerMsgs([]);
    setDrawerLoading(true);
    try { setDrawerMsgs(await NwService.secGetConvMessages(conv.id)); } catch {}
    finally { setDrawerLoading(false); }
  }

  async function finalizeConv() {
    if (!drawerConv) return;
    setFinalizing(true);
    try {
      await NwService.secFinalizeConv(drawerConv.id);
      setConvs(cs => cs.map(c => c.id === drawerConv.id ? { ...c, status: 'closed' } : c));
      setDrawerConv(null);
    } catch {} finally { setFinalizing(false); }
  }

  async function sendTest(e?: React.FormEvent) {
    e?.preventDefault();
    const text = testMsg.trim();
    if (!text || testLoading) return;
    setTestMsg('');
    setTestHistory(h => [...h, { role: 'user', text }]);
    setTestLoading(true);
    try {
      const res = await NwService.secTestAsk(testSessionId.current, text);
      const reply = res.reply ?? '(sem resposta)';
      setTestHistory(h => [...h, { role: 'ai', text: reply }]);
    } catch (err: any) {
      setTestHistory(h => [...h, { role: 'ai', text: `Erro: ${err?.message ?? 'falha'}` }]);
    } finally { setTestLoading(false); }
  }

  // ── Agente save ───────────────────────────────────────────────────────────
  async function saveAgent(e: React.FormEvent) {
    e.preventDefault();
    setAgentSaving(true);
    try {
      const d = agent
        ? await NwService.secUpdateAgent(agent.id, agentForm)
        : await NwService.secCreateAgent(agentForm);
      setAgent(d);
      setAgentSaved(true);
      setTimeout(() => setAgentSaved(false), 2000);
    } catch {} finally { setAgentSaving(false); }
  }

  // ── Cérebro save/delete ───────────────────────────────────────────────────
  async function saveNode(e: React.FormEvent) {
    e.preventDefault();
    setNodesSaving(true);
    try {
      if (editNode) {
        const d = await NwService.secUpdateNode(editNode.id, { type: editNode.type, title: editNode.title ?? '', content: editNode.content });
        setNodes(ns => ns.map(n => n.id === d.id ? d : n));
      } else {
        const d = await NwService.secCreateNode({ type: nodeForm.type, title: nodeForm.title, content: nodeForm.content });
        setNodes(ns => [...ns, d]);
      }
      setNodeForm({ type: 'persona', title: '', content: '' });
      setEditNode(null);
    } catch {} finally { setNodesSaving(false); }
  }
  async function deleteNode(id: string) {
    try { await NwService.secDeleteNode(id); setNodes(ns => ns.filter(n => n.id !== id)); } catch {}
  }

  // ── Agenda save/delete ────────────────────────────────────────────────────
  async function saveSlot(e: React.FormEvent) {
    e.preventDefault();
    setSlotsSaving(true);
    try {
      const d = await NwService.secCreateSlot(slotForm);
      setSlots(ss => [...ss, d]);
      setSlotForm({ date: '', time_start: '', time_end: '', attendee: '', notes: '' });
    } catch {} finally { setSlotsSaving(false); }
  }
  async function deleteSlot(id: string) {
    try { await NwService.secDeleteSlot(id); setSlots(ss => ss.filter(s => s.id !== id)); } catch {}
  }

  // ── Config save ───────────────────────────────────────────────────────────
  async function saveConfig(e: React.FormEvent) {
    e.preventDefault();
    setCfgSaving(true);
    try {
      await NwService.secSaveKeys(cfg);
      setCfgSaved(true);
      setTimeout(() => setCfgSaved(false), 2000);
    } catch {} finally { setCfgSaving(false); }
  }
  async function toggleAutoReply() {
    const next = autoReply === 'off' ? 'automatico' : 'off';
    try { await NwService.setAutoReplyMode(next); setAutoReply(next); } catch {}
  }

  const inputCls = 'w-full border border-[#d1d7db] rounded-lg px-3 py-2 text-[13px] text-[#111b21] focus:outline-none focus:border-[#00a884] bg-white';
  const labelCls = 'block text-[11px] font-semibold text-[#667781] uppercase tracking-wide mb-1';
  const btnPrimary = 'flex items-center gap-1.5 px-4 py-2 bg-[#00a884] text-white rounded-lg text-[13px] font-semibold hover:bg-[#008f72] transition-colors disabled:opacity-60';

  return (
    <div className="flex flex-col h-full bg-[#f0f2f5]">
      {/* Header */}
      <div className="h-[60px] px-4 flex items-center gap-3 bg-[#f0f2f5] border-b border-[#d1d7db] flex-shrink-0">
        <Bot size={22} className="text-[#00a884]" />
        <h2 className="text-[16px] font-bold text-[#111b21]">Secretária Virtual</h2>
      </div>

      {/* Sub-tab bar */}
      <div className="flex bg-white border-b border-[#d1d7db] flex-shrink-0 overflow-x-auto">
        {SEC_TABS.map(({ id, Icon, label }) => (
          <button key={id} onClick={() => setTab(id)}
            className={`flex items-center gap-1.5 px-4 py-3 text-[13px] font-medium whitespace-nowrap border-b-2 transition-colors
              ${tab === id ? 'border-[#00a884] text-[#00a884]' : 'border-transparent text-[#667781] hover:text-[#111b21] hover:bg-[#f5f6f6]'}`}
          >
            <Icon size={15} /> {label}
          </button>
        ))}
      </div>

      {/* Content */}
      <div className="flex-1 overflow-y-auto p-4">

        {/* ── Agente ─────────────────────────────────────────────────────── */}
        {tab === 'agente' && (
          <form onSubmit={saveAgent} className="flex flex-col gap-4">
            <p className="text-[12px] text-[#667781]">
              Configure a identidade e o modelo de IA da secretária.
            </p>
            <div>
              <label className={labelCls}>Nome do agente</label>
              <input className={inputCls} value={agentForm.name} onChange={e => setAgentForm(f => ({ ...f, name: e.target.value }))} placeholder="Ex: Secretária Alemão" required />
            </div>
            <div className="grid grid-cols-2 gap-3">
              <div>
                <label className={labelCls}>Provider</label>
                <select className={inputCls} value={agentForm.provider} onChange={e => setAgentForm(f => ({ ...f, provider: e.target.value }))}>
                  <option value="openai">OpenAI</option>
                  <option value="gemini">Gemini</option>
                  <option value="anthropic">Anthropic</option>
                  <option value="ollama">Ollama</option>
                </select>
              </div>
              <div>
                <label className={labelCls}>Modelo</label>
                <input className={inputCls} value={agentForm.model} onChange={e => setAgentForm(f => ({ ...f, model: e.target.value }))} placeholder="gpt-4o-mini" />
              </div>
            </div>
            <div className="grid grid-cols-2 gap-3">
              <div>
                <label className={labelCls}>Temperatura ({agentForm.temperature})</label>
                <input type="range" min="0" max="1" step="0.1" value={agentForm.temperature}
                  onChange={e => setAgentForm(f => ({ ...f, temperature: parseFloat(e.target.value) }))}
                  className="w-full accent-[#00a884]" />
              </div>
              <div>
                <label className={labelCls}>Janela de contexto</label>
                <input type="number" min="5" max="50" className={inputCls} value={agentForm.context_window}
                  onChange={e => setAgentForm(f => ({ ...f, context_window: parseInt(e.target.value) }))} />
              </div>
            </div>
            <button type="submit" className={btnPrimary} disabled={agentSaving}>
              {agentSaving ? <Loader2 size={14} className="animate-spin" /> : <Save size={14} />}
              {agentSaved ? 'Salvo ✓' : 'Salvar agente'}
            </button>
          </form>
        )}

        {/* ── Cérebro ────────────────────────────────────────────────────── */}
        {tab === 'cerebro' && (
          <div className="flex flex-col gap-4">
            <p className="text-[12px] text-[#667781]">
              Nodes de conhecimento que moldam as respostas da secretária.
            </p>
            {/* Form */}
            <form onSubmit={saveNode} className="bg-white rounded-xl border border-[#d1d7db] p-4 flex flex-col gap-3">
              <div className="flex gap-2">
                <div className="flex-1">
                  <label className={labelCls}>Tipo</label>
                  <select className={inputCls} value={editNode ? editNode.type : nodeForm.type}
                    onChange={e => editNode
                      ? setEditNode((n: any) => ({ ...n, type: e.target.value }))
                      : setNodeForm(f => ({ ...f, type: e.target.value }))}>
                    {BRAIN_NODE_TYPES.map(t => <option key={t} value={t}>{t}</option>)}
                  </select>
                </div>
              </div>
              <div>
                <label className={labelCls}>Título</label>
                <input type="text" className={inputCls}
                  value={editNode ? (editNode.title ?? '') : nodeForm.title}
                  onChange={e => editNode
                    ? setEditNode((n: any) => ({ ...n, title: e.target.value }))
                    : setNodeForm(f => ({ ...f, title: e.target.value }))}
                  placeholder="Ex: Política de Troca, Horário de Funcionamento..." required />
              </div>
              <div>
                <label className={labelCls}>Conteúdo</label>
                <textarea rows={4} className={`${inputCls} resize-none`}
                  value={editNode ? editNode.content : nodeForm.content}
                  onChange={e => editNode
                    ? setEditNode((n: any) => ({ ...n, content: e.target.value }))
                    : setNodeForm(f => ({ ...f, content: e.target.value }))}
                  placeholder="Descreva o comportamento, conhecimento ou regra..." required />
              </div>
              <div className="flex gap-2">
                <button type="submit" className={btnPrimary} disabled={nodesSaving}>
                  {nodesSaving ? <Loader2 size={14} className="animate-spin" /> : <Save size={14} />}
                  {editNode ? 'Atualizar' : 'Adicionar node'}
                </button>
                {editNode && (
                  <button type="button" onClick={() => { setEditNode(null); setNodeForm({ type: 'persona', title: '', content: '' }); }}
                    className="px-4 py-2 border border-[#d1d7db] rounded-lg text-[13px] text-[#667781] hover:bg-[#f5f6f6]">
                    Cancelar
                  </button>
                )}
              </div>
            </form>
            {/* List */}
            <div className="flex flex-col gap-2">
              {nodes.length === 0 && <p className="text-[12px] text-[#667781] text-center py-4">Nenhum node configurado.</p>}
              {nodes.map(n => (
                <div key={n.id} className="bg-white rounded-xl border border-[#d1d7db] p-3 flex gap-3">
                  <span className={`text-[10px] font-bold px-2 py-0.5 rounded-full self-start mt-0.5 ${BRAIN_NODE_COLORS[n.type] ?? 'bg-gray-100 text-gray-600'}`}>
                    {n.type}
                  </span>
                  <p className="flex-1 text-[13px] text-[#111b21] whitespace-pre-wrap line-clamp-3">{n.content}</p>
                  <div className="flex flex-col gap-1">
                    <button onClick={() => { setEditNode({ ...n }); }} className="p-1 hover:bg-[#f0f2f5] rounded">
                      <Edit2 size={13} className="text-[#667781]" />
                    </button>
                    <button onClick={() => deleteNode(n.id)} className="p-1 hover:bg-red-50 rounded">
                      <Trash2 size={13} className="text-red-500" />
                    </button>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* ── Agenda ─────────────────────────────────────────────────────── */}
        {tab === 'agenda' && (
          <div className="flex flex-col gap-4">
            <p className="text-[12px] text-[#667781]">Slots de atendimento disponíveis para agendamento.</p>
            <form onSubmit={saveSlot} className="bg-white rounded-xl border border-[#d1d7db] p-4 flex flex-col gap-3">
              <div className="grid grid-cols-2 gap-3">
                <div>
                  <label className={labelCls}>Data</label>
                  <input type="date" className={inputCls} value={slotForm.date} onChange={e => setSlotForm(f => ({ ...f, date: e.target.value }))} required />
                </div>
                <div>
                  <label className={labelCls}>Responsável</label>
                  <input className={inputCls} value={slotForm.attendee} onChange={e => setSlotForm(f => ({ ...f, attendee: e.target.value }))} placeholder="Nome ou setor" />
                </div>
              </div>
              <div className="grid grid-cols-2 gap-3">
                <div>
                  <label className={labelCls}>Início</label>
                  <input type="time" className={inputCls} value={slotForm.time_start} onChange={e => setSlotForm(f => ({ ...f, time_start: e.target.value }))} required />
                </div>
                <div>
                  <label className={labelCls}>Fim</label>
                  <input type="time" className={inputCls} value={slotForm.time_end} onChange={e => setSlotForm(f => ({ ...f, time_end: e.target.value }))} required />
                </div>
              </div>
              <div>
                <label className={labelCls}>Observações</label>
                <input className={inputCls} value={slotForm.notes} onChange={e => setSlotForm(f => ({ ...f, notes: e.target.value }))} placeholder="Opcional" />
              </div>
              <button type="submit" className={btnPrimary} disabled={slotsSaving}>
                {slotsSaving ? <Loader2 size={14} className="animate-spin" /> : <Plus size={14} />}
                Adicionar slot
              </button>
            </form>
            <div className="flex flex-col gap-2">
              {slots.length === 0 && <p className="text-[12px] text-[#667781] text-center py-4">Nenhum slot cadastrado.</p>}
              {slots.map(s => (
                <div key={s.id} className="bg-white rounded-xl border border-[#d1d7db] px-4 py-3 flex items-center gap-3">
                  <CalendarDays size={18} className="text-[#00a884] flex-shrink-0" />
                  <div className="flex-1 min-w-0">
                    <p className="text-[13px] font-semibold text-[#111b21]">{s.date} · {s.time_start}–{s.time_end}</p>
                    {s.attendee && <p className="text-[12px] text-[#667781] truncate">{s.attendee}</p>}
                  </div>
                  <span className={`text-[10px] font-bold px-2 py-0.5 rounded-full ${s.status === 'booked' ? 'bg-red-100 text-red-600' : 'bg-green-100 text-green-700'}`}>
                    {s.status === 'booked' ? 'Ocupado' : 'Livre'}
                  </span>
                  <button onClick={() => deleteSlot(s.id)} className="p-1 hover:bg-red-50 rounded">
                    <Trash2 size={13} className="text-red-500" />
                  </button>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* ── Conversas ──────────────────────────────────────────────────── */}
        {tab === 'conversas' && (
          <div className="flex flex-col gap-3">
            <div className="flex gap-2">
              {(['all','active','closed'] as const).map(f => (
                <button key={f} onClick={() => setConvFilter(f)}
                  className={`px-3 py-1.5 rounded-full text-[12px] font-medium transition-colors
                    ${convFilter === f ? 'bg-[#00a884] text-white' : 'bg-white border border-[#d1d7db] text-[#667781] hover:bg-[#f5f6f6]'}`}>
                  {f === 'all' ? 'Todas' : f === 'active' ? 'Ativas' : 'Encerradas'}
                </button>
              ))}
              <button onClick={fetchConvs} className="ml-auto p-1.5 hover:bg-[#f0f2f5] rounded-full transition-colors">
                <RefreshCw size={14} className={`text-[#667781] ${convsLoading ? 'animate-spin' : ''}`} />
              </button>
            </div>
            {convsLoading && <div className="flex justify-center py-8"><Loader2 size={24} className="animate-spin text-[#00a884]" /></div>}
            {!convsLoading && convs.length === 0 && <p className="text-[12px] text-[#667781] text-center py-8">Nenhuma conversa registrada.</p>}
            <div className="flex flex-col gap-2">
              {convs
                .filter(c => convFilter === 'all' || c.status === (convFilter === 'active' ? 'active' : 'closed'))
                .map(c => (
                  <button key={c.id} onClick={() => openDrawer(c)}
                    className="bg-white rounded-xl border border-[#d1d7db] px-4 py-3 text-left hover:border-[#00a884] hover:shadow-sm transition-all">
                    <div className="flex items-center justify-between mb-1 gap-2 flex-wrap">
                      <span className="text-[12px] font-bold text-[#667781] font-mono">{c.protocol_number ?? c.id}</span>
                      <div className="flex items-center gap-1.5">
                        {c.handoff_mode === 'humano' && (
                          <span className="text-[10px] font-bold px-2 py-0.5 rounded-full bg-orange-100 text-orange-600 flex items-center gap-1">
                            <UserCheck size={9} /> Humano
                          </span>
                        )}
                        {c.status === 'escalated' && (
                          <span className="text-[10px] font-bold px-2 py-0.5 rounded-full bg-red-100 text-red-600 flex items-center gap-1">
                            <AlertTriangle size={9} /> Escalada
                          </span>
                        )}
                        <span className={`text-[10px] font-bold px-2 py-0.5 rounded-full ${c.status === 'active' ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'}`}>
                          {c.status === 'active' ? 'Ativa' : 'Encerrada'}
                        </span>
                      </div>
                    </div>
                    {c.summary && <p className="text-[12px] text-[#111b21] line-clamp-2">{c.summary}</p>}
                    {c.created_at && <p className="text-[11px] text-[#8696a0] mt-1">{new Date(c.created_at).toLocaleString('pt-BR')}</p>}
                  </button>
                ))}
            </div>
          </div>
        )}

        {/* ── Testar ─────────────────────────────────────────────────────── */}
        {tab === 'testar' && (
          <div className="flex flex-col h-full gap-0" style={{ minHeight: '400px' }}>
            <p className="text-[12px] text-[#667781] mb-3">
              Teste a secretária sem precisar de celular conectado. Cada sessão é isolada.
            </p>
            {/* Message area */}
            <div className="flex-1 bg-white rounded-xl border border-[#d1d7db] p-3 overflow-y-auto flex flex-col gap-2 mb-3" style={{ minHeight: '280px', maxHeight: '380px' }}>
              {testHistory.length === 0 && (
                <p className="text-[12px] text-[#8696a0] text-center m-auto">Digite uma mensagem para começar o teste.</p>
              )}
              {testHistory.map((m, i) => (
                <div key={i} className={`flex ${m.role === 'user' ? 'justify-end' : 'justify-start'}`}>
                  <div className={`max-w-[85%] px-3 py-2 rounded-xl text-[13px] whitespace-pre-wrap leading-[1.4]
                    ${m.role === 'user' ? 'bg-[#d9fdd3] text-[#111b21]' : 'bg-white border border-[#d1d7db] text-[#111b21]'}`}>
                    {m.text}
                  </div>
                </div>
              ))}
              {testLoading && (
                <div className="flex justify-start">
                  <div className="px-4 py-2 bg-white border border-[#d1d7db] rounded-xl flex items-center gap-1.5">
                    <Loader2 size={12} className="animate-spin text-[#00a884]" />
                    <span className="text-[12px] text-[#667781]">Secretária digitando…</span>
                  </div>
                </div>
              )}
              <div ref={testEndRef} />
            </div>
            {/* Input */}
            <form onSubmit={sendTest} className="flex gap-2">
              <input
                className="flex-1 border border-[#d1d7db] rounded-lg px-3 py-2 text-[13px] text-[#111b21] focus:outline-none focus:border-[#00a884] bg-white"
                value={testMsg}
                onChange={e => setTestMsg(e.target.value)}
                placeholder="Mensagem de teste..."
                disabled={testLoading}
              />
              <button type="submit" disabled={testLoading || !testMsg.trim()}
                className="flex items-center gap-1.5 px-4 py-2 bg-[#00a884] text-white rounded-lg text-[13px] font-semibold hover:bg-[#008f72] transition-colors disabled:opacity-60">
                <Send size={14} />
              </button>
              <button type="button" onClick={() => { setTestHistory([]); testSessionId.current = `test-${Date.now()}`; }}
                className="px-3 py-2 border border-[#d1d7db] rounded-lg text-[12px] text-[#667781] hover:bg-[#f5f6f6] transition-colors" title="Reiniciar sessão">
                <RefreshCw size={14} />
              </button>
            </form>
          </div>
        )}

        {/* ── Config ─────────────────────────────────────────────────────── */}
        {tab === 'config' && (
          <form onSubmit={saveConfig} className="flex flex-col gap-4">
            <p className="text-[12px] text-[#667781]">Chaves de API e modo de resposta automática.</p>
            <div className="bg-white rounded-xl border border-[#d1d7db] p-4 flex flex-col gap-3">
              <p className="text-[12px] font-semibold text-[#111b21]">Provedores de IA</p>
              {([
                ['openai_key',    'OpenAI API Key',      'sk-...'],
                ['gemini_key',    'Gemini API Key',      'AIza...'],
                ['anthropic_key', 'Anthropic API Key',   'sk-ant-...'],
                ['ollama_url',    'Ollama URL',          'http://localhost:11434'],
              ] as const).map(([key, label, ph]) => {
                const val = (cfg as any)[key] as string;
                const isMasked = val.endsWith('****');
                return (
                  <div key={key}>
                    <label className={labelCls}>
                      {label}
                      {isMasked && <span className="ml-2 text-[10px] font-normal text-green-600 normal-case tracking-normal">já configurado</span>}
                    </label>
                    <input type={key === 'ollama_url' ? 'url' : 'password'} className={inputCls}
                      value={isMasked ? '' : val}
                      placeholder={isMasked ? '••••••••  (deixe em branco para manter)' : ph}
                      onChange={e => setCfg(c => ({ ...c, [key]: e.target.value }))} />
                  </div>
                );
              })}
            </div>
            <div className="bg-white rounded-xl border border-[#d1d7db] p-4 flex flex-col gap-3">
              <p className="text-[12px] font-semibold text-[#111b21]">Notificação de escalação</p>
              <div>
                <label className={labelCls}>WhatsApp do administrador <span className="normal-case text-[#667781] font-normal">(sem +55, ex: 67999001122)</span></label>
                <input type="tel" className={inputCls}
                  value={cfg.admin_notify_phone}
                  placeholder="67999001122"
                  onChange={e => setCfg(c => ({ ...c, admin_notify_phone: e.target.value.replace(/\D/g, '') }))} />
                <p className="text-[11px] text-[#8696a0] mt-1">Quando a IA escalar um cliente, este número receberá uma mensagem WA de alerta.</p>
              </div>
            </div>
            <div className="bg-white rounded-xl border border-[#d1d7db] p-4 flex items-center justify-between">
              <div>
                <p className="text-[13px] font-semibold text-[#111b21]">Resposta automática</p>
                <p className="text-[11px] text-[#667781]">Secretária responde automaticamente às mensagens recebidas</p>
              </div>
              <button type="button" onClick={toggleAutoReply} className="flex-shrink-0 ml-4">
                {autoReply === 'automatico'
                  ? <ToggleRight size={36} className="text-[#00a884]" />
                  : <ToggleLeft size={36} className="text-[#8696a0]" />}
              </button>
            </div>
            <button type="submit" className={btnPrimary} disabled={cfgSaving}>
              {cfgSaving ? <Loader2 size={14} className="animate-spin" /> : <Save size={14} />}
              {cfgSaved ? 'Salvo ✓' : 'Salvar configurações'}
            </button>
          </form>
        )}

      </div>

      {/* ── Conversation Drawer ───────────────────────────────────────── */}
      {drawerConv && (
        <div className="absolute inset-0 z-40 flex">
          {/* Backdrop */}
          <div className="flex-1 bg-black/30" onClick={() => setDrawerConv(null)} />
          {/* Drawer */}
          <div className="w-[380px] max-w-full h-full bg-white flex flex-col shadow-2xl">
            {/* Header */}
            <div className="h-[60px] px-4 flex items-center gap-3 border-b border-[#d1d7db] flex-shrink-0">
              <button onClick={() => setDrawerConv(null)} className="p-1.5 hover:bg-[#f0f2f5] rounded-full transition-colors">
                <X size={18} className="text-[#54656f]" />
              </button>
              <div className="flex-1 min-w-0">
                <p className="text-[13px] font-bold text-[#111b21] font-mono truncate">{drawerConv.protocol_number ?? drawerConv.id}</p>
                <p className="text-[11px] text-[#667781]">{new Date(drawerConv.created_at).toLocaleString('pt-BR')}</p>
              </div>
              {drawerConv.status === 'active' && (
                <button onClick={finalizeConv} disabled={finalizing}
                  className="flex items-center gap-1.5 px-3 py-1.5 bg-red-500 text-white rounded-lg text-[12px] font-semibold hover:bg-red-600 transition-colors disabled:opacity-60">
                  {finalizing ? <Loader2 size={12} className="animate-spin" /> : <X size={12} />}
                  Finalizar
                </button>
              )}
            </div>
            {/* Messages */}
            <div className="flex-1 overflow-y-auto p-4 flex flex-col gap-3">
              {drawerLoading && <div className="flex justify-center py-8"><Loader2 size={24} className="animate-spin text-[#00a884]" /></div>}
              {!drawerLoading && drawerMsgs.length === 0 && (
                <p className="text-[12px] text-[#8696a0] text-center py-8">Nenhuma mensagem neste protocolo.</p>
              )}
              {drawerMsgs.map((m: any, i: number) => (
                <div key={m.id ?? i} className={`flex flex-col gap-0.5 ${m.role === 'user' ? 'items-start' : 'items-end'}`}>
                  <span className="text-[10px] text-[#8696a0] px-1">{m.role === 'user' ? 'Cliente' : 'Secretária'}</span>
                  <div className={`max-w-[88%] px-3 py-2 rounded-xl text-[13px] leading-[1.4] whitespace-pre-wrap
                    ${m.role === 'user' ? 'bg-[#f0f2f5] text-[#111b21]' : 'bg-[#d9fdd3] text-[#111b21]'}`}>
                    {m.content}
                  </div>
                  {m.created_at && (
                    <span className="text-[10px] text-[#8696a0] px-1">{new Date(m.created_at).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}</span>
                  )}
                </div>
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── ThinSidebar ──────────────────────────────────────────────────────────────
type TabType = 'chats' | 'sessions' | 'secretaria' | 'equipe' | 'inbox-interna' | 'metricas';
function ThinSidebar({
  activeTab, setActiveTab, session, inboxUnread, teamAccount, onTeamLogout,
}: {
  activeTab: TabType;
  setActiveTab: (t: TabType) => void;
  session: NwSession | null;
  inboxUnread?: number;
  teamAccount?: { id: number; name: string; email: string; role: string } | null;
  onTeamLogout?: () => void;
}) {
  const isConnected = session?.status === 'CONNECTED';
  const role = teamAccount?.role || 'owner';

  // Plantão toggle — só disponível para colaboradores (teamAccount)
  const [onDuty, setOnDuty] = useState<boolean | null>(null);
  const [dutyLoading, setDutyLoading] = useState(false);

  useEffect(() => {
    if (!teamAccount) return;
    fetch('/api/team/me', { credentials: 'include' })
      .then(r => r.json())
      .then(d => {
        const sectors: any[] = d?.account?.sectors || [];
        const first = sectors.find(s => s.on_duty != null);
        if (first) setOnDuty(first.on_duty);
      })
      .catch(() => {});
  }, [teamAccount?.id]);

  async function toggleDuty() {
    if (onDuty === null || dutyLoading) return;
    setDutyLoading(true);
    try {
      const next = !onDuty;
      await fetch('/api/team/me/duty', {
        method: 'PATCH',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ on_duty: next }),
      });
      setOnDuty(next);
    } catch {}
    finally { setDutyLoading(false); }
  }

  // Define quais abas aparecem para cada cargo
  const allTabs: [TabType, React.ElementType, string][] = [
    ['chats',         MessageCircle, 'Conversas'],
    ['sessions',      Smartphone,   'Sessões'],
    ['secretaria',    Bot,           'Secretária Virtual'],
    ['equipe',        Users,         'Equipe'],
    ['inbox-interna', Inbox,         'Inbox Interna'],
    ['metricas',      BarChart3,     'Métricas'],
  ];

  const visibleTabs = allTabs.filter(([id]) => {
    if (id === 'sessions')   return !teamAccount;
    if (id === 'secretaria') return !teamAccount || ['owner','manager','supervisor'].includes(role);
    if (id === 'equipe')     return !teamAccount || EQUIPE_ROLES.has(role);
    if (id === 'metricas')   return !teamAccount || ['owner','manager','supervisor'].includes(role);
    return true;
  });

  return (
    <div className="w-[60px] h-full bg-[#f0f2f5] border-r border-[#d1d7db] flex flex-col items-center py-4 flex-shrink-0 z-30">
      <div className="flex-1 w-full flex flex-col items-center gap-1">
        {visibleTabs.map(([id, Icon, title]) => (
          <button key={id} title={title} onClick={() => setActiveTab(id)}
            className={`relative w-10 h-10 rounded-full flex items-center justify-center transition-colors
              ${activeTab === id ? 'bg-[#d9dbdf]' : 'hover:bg-[#d9dbdf]/60'}`}
          >
            <Icon size={22} className={activeTab === id ? 'text-[#111b21]' : 'text-[#54656f]'}
              fill={activeTab === id ? 'currentColor' : 'none'} />
            {id === 'inbox-interna' && inboxUnread && inboxUnread > 0 ? (
              <span className="absolute top-0.5 right-0.5 bg-red-500 text-white text-[9px] font-bold w-4 h-4 rounded-full flex items-center justify-center">
                {inboxUnread > 9 ? '9+' : inboxUnread}
              </span>
            ) : null}
          </button>
        ))}
      </div>
      <div className="w-full flex flex-col items-center gap-1 pb-1">
        {/* Avatar do funcionário logado */}
        {teamAccount ? (
          <div className="flex flex-col items-center gap-1">
            {/* Toggle plantão */}
            {onDuty !== null && (
              <button
                onClick={toggleDuty}
                disabled={dutyLoading}
                title={onDuty ? 'De plantão — clique para sair' : 'Fora de plantão — clique para entrar'}
                className={`w-8 h-8 rounded-full flex items-center justify-center transition-colors border-2 ${
                  onDuty
                    ? 'bg-emerald-500/20 border-emerald-500/60 text-emerald-500 hover:bg-emerald-500/30'
                    : 'bg-slate-300/40 border-slate-400/40 text-slate-500 hover:bg-slate-300/60'
                } ${dutyLoading ? 'opacity-50 cursor-wait' : ''}`}
              >
                {onDuty ? <ToggleRight size={16} /> : <ToggleLeft size={16} />}
              </button>
            )}
            <div className="w-9 h-9 rounded-full bg-purple-600 flex items-center justify-center text-white text-sm font-bold cursor-default"
              title={`${teamAccount.name} (${teamAccount.role})`}>
              {teamAccount.name.charAt(0).toUpperCase()}
            </div>
            {onTeamLogout && (
              <button onClick={onTeamLogout} title="Sair"
                className="w-8 h-8 rounded-full flex items-center justify-center hover:bg-red-100 text-red-400 transition-colors">
                <X size={14} />
              </button>
            )}
          </div>
        ) : (
          <>
            <button title="Configurações"
              className="w-10 h-10 rounded-full flex items-center justify-center hover:bg-[#d9dbdf]/60 transition-colors">
              <Settings size={22} className="text-[#54656f]" fill="none" />
            </button>
            <div className="relative mt-1 p-1 cursor-pointer">
              <AvatarEl src={session?.avatar} name={session?.name} size={32} />
              <div className={`absolute bottom-0.5 right-0.5 w-3 h-3 rounded-full border-2 border-[#f0f2f5]
                ${isConnected ? 'bg-emerald-500' : 'bg-red-500'}`}
                title={isConnected ? 'Conectado' : 'Desconectado'} />
            </div>
          </>
        )}
      </div>
    </div>
  );
}

// ─── ChatHeader ───────────────────────────────────────────────────────────────
function ChatHeader({
  chat, onBack, isMobile, onArchive,
}: { chat: NwChat; onBack: () => void; isMobile: boolean; onArchive: () => void }) {
  const [menuOpen, setMenuOpen] = useState(false);
  const menuRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const fn = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) setMenuOpen(false); };
    document.addEventListener('mousedown', fn);
    return () => document.removeEventListener('mousedown', fn);
  }, []);

  return (
    <header className="h-[60px] px-4 bg-[#f0f2f5] flex items-center justify-between border-b border-[#d1d7db] shrink-0 z-20">
      <div className="flex items-center gap-3 flex-1 min-w-0">
        {isMobile && (
          <button onClick={onBack} className="p-1 -ml-1 mr-1 hover:bg-black/5 rounded-full transition-colors">
            <ArrowLeft size={24} className="text-[#54656f]" />
          </button>
        )}
        <div className="flex items-center gap-3 min-w-0 cursor-pointer group hover:bg-black/5 px-2 py-1 -ml-2 rounded-md transition-all">
          <AvatarEl src={chat.avatar} name={chat.displayName ?? chat.phone} size={40} />
          <div className="flex flex-col min-w-0">
            <h3 className="text-[16px] leading-[21px] font-bold text-[#111b21] truncate group-hover:text-[#00a884] transition-colors">
              {chat.displayName ?? chat.phone}
            </h3>
            <span className="text-[12.5px] text-[#667781] truncate flex items-center gap-1 font-normal">
              <Phone size={10} />{chat.phone}
            </span>
          </div>
        </div>
      </div>
      <div className="flex items-center gap-1" ref={menuRef}>
        <button className="p-2 hover:bg-black/5 rounded-full transition-all text-[#54656f]">
          <Search size={20} />
        </button>
        <div className="relative">
          <button onClick={() => setMenuOpen(v => !v)}
            className={`p-2 rounded-full transition-all ${menuOpen ? 'bg-black/10 text-[#111b21]' : 'hover:bg-black/5 text-[#54656f]'}`}>
            <MoreVertical size={20} />
          </button>
          {menuOpen && (
            <div className="absolute right-0 top-12 w-56 bg-white rounded-lg shadow-2xl border border-gray-100 py-2 z-50">
              <button className="w-full flex items-center gap-3 px-4 py-2.5 text-[14px] text-[#111b21] hover:bg-[#f5f6f6] transition-colors"
                onClick={() => { setMenuOpen(false); onArchive(); }}>
                <RefreshCw size={15} /> Arquivar conversa
              </button>
            </div>
          )}
        </div>
      </div>
    </header>
  );
}

// ─── HandoffButton ────────────────────────────────────────────────────────────
function HandoffButton({
  chat, autoReplyGlobal, refreshKey = 0,
}: { chat: NwChat; autoReplyGlobal: 'off' | 'automatico'; refreshKey?: number }) {
  const [mode, setMode] = useState<'ia' | 'humano'>('ia');
  const [humanAt, setHumanAt] = useState<Date | null>(null);
  const [loading, setLoading] = useState(false);
  const [secsLeft, setSecsLeft] = useState(0);

  // Carrega modo ao abrir o chat ou quando refreshKey muda (ex: envio automático)
  useEffect(() => {
    let cancelled = false;
    NwService.getHandoffMode(chat.id).then(d => {
      if (cancelled) return;
      setMode(d.mode);
      setHumanAt(d.handoffHumanAt ? new Date(d.handoffHumanAt) : null);
    }).catch(() => {});
    return () => { cancelled = true; };
  }, [chat.id, refreshKey]);

  // Contador regressivo — humanAt é o momento de expiração
  useEffect(() => {
    if (mode !== 'humano' || !humanAt) { setSecsLeft(0); return; }
    const tick = () => {
      const remaining = Math.max(0, Math.floor((humanAt.getTime() - Date.now()) / 1000));
      setSecsLeft(remaining);
    };
    tick();
    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, [mode, humanAt]);

  if (autoReplyGlobal === 'off') return null;

  async function toggle() {
    setLoading(true);
    const next = mode === 'ia' ? 'humano' : 'ia';
    try {
      await NwService.setHandoffMode(chat.id, next);
      setMode(next);
      setHumanAt(next === 'humano' ? new Date() : null);
    } catch {} finally { setLoading(false); }
  }

  const fmtTime = (s: number) => `${String(Math.floor(s / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`;
  const isHuman = mode === 'humano';

  return (
    <button
      onClick={toggle}
      disabled={loading}
      title={isHuman ? `Devolver à IA (${fmtTime(secsLeft)} restantes)` : 'Assumir atendimento manualmente'}
      className={`absolute bottom-[76px] right-4 z-20 flex items-center gap-2 px-3 py-2 rounded-full shadow-lg text-[12px] font-semibold transition-all select-none
        ${isHuman
          ? 'bg-orange-500 text-white animate-pulse hover:animate-none hover:bg-orange-600'
          : 'bg-[#00a884] text-white hover:bg-[#008f72]'}
        ${loading ? 'opacity-60 cursor-wait' : 'cursor-pointer'}`}
    >
      {isHuman ? <UserCheck size={14} /> : <Bot size={14} />}
      {isHuman ? (secsLeft > 0 ? `Você (${fmtTime(secsLeft)})` : 'Você') : 'IA'}
    </button>
  );
}

// ─── InputBar ─────────────────────────────────────────────────────────────────
function InputBar({
  value, onChange, onSend, sending, onAskAi, askingAi, chatId,
}: {
  value: string;
  onChange: (v: string) => void;
  onSend: () => void;
  sending: boolean;
  onAskAi: () => void;
  askingAi: boolean;
  chatId: string | null;
}) {
  const textareaRef  = useRef<HTMLTextAreaElement>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const attachRef    = useRef<HTMLDivElement>(null);

  const [showAttachMenu,    setShowAttachMenu]    = useState(false);
  const [showRichComposer,  setShowRichComposer]  = useState(false);
  const [showTemplateLib,   setShowTemplateLib]   = useState(false);
  const [showSchedule,      setShowSchedule]      = useState(false);
  const [schedPayload,      setSchedPayload]      = useState<Record<string, unknown>>({});
  const [schedType,         setSchedType]         = useState<NwTemplateType>('TEXT');
  const [richInitPayload,   setRichInitPayload]   = useState<Record<string, unknown> | undefined>();
  const [richInitType,      setRichInitType]      = useState<NwTemplateType>('TEXT');

  const autoResize = () => {
    const ta = textareaRef.current;
    if (!ta) return;
    ta.style.height = 'auto';
    ta.style.height = Math.min(ta.scrollHeight, 150) + 'px';
  };

  useEffect(() => {
    const handleClickOutside = (e: MouseEvent) => {
      if (attachRef.current && !attachRef.current.contains(e.target as Node)) {
        setShowAttachMenu(false);
      }
    };
    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);

  const handleTemplateSelect = (tmpl: NwTemplate) => {
    setRichInitPayload(tmpl.payload);
    setRichInitType(tmpl.type);
    setShowTemplateLib(false);
    setShowRichComposer(true);
  };

  const handleScheduleFromComposer = (type: NwTemplateType, payload: Record<string, unknown>) => {
    setSchedType(type);
    setSchedPayload(payload);
    setShowRichComposer(false);
    setShowSchedule(true);
  };

  return (
    <>
      <div className="min-h-[62px] px-4 py-[8px] bg-[#f0f2f5] border-t border-[#d1d7db] flex items-end gap-3">
        {/* Emoji */}
        <div className="pb-[7px]">
          <button className="p-2 hover:bg-black/5 rounded-full transition-colors text-[#54656f]" title="Emoji">
            <Smile size={24} />
          </button>
        </div>

        {/* Floating attach group */}
        <div ref={attachRef} className="relative pb-[7px]">
          <motion.button
            onClick={() => setShowAttachMenu(v => !v)}
            className="p-2 hover:bg-black/5 rounded-full transition-colors text-[#54656f]"
            title="Mais opções"
            animate={{ rotate: showAttachMenu ? 45 : 0 }}
            transition={{ duration: 0.2 }}
          >
            <Plus size={22} />
          </motion.button>

          <AnimatePresence>
            {showAttachMenu && (
              <motion.div
                initial={{ opacity: 0, y: 8, scale: 0.92 }}
                animate={{ opacity: 1, y: 0, scale: 1 }}
                exit={{ opacity: 0, y: 8, scale: 0.92 }}
                transition={{ type: 'spring', stiffness: 400, damping: 28 }}
                className="absolute bottom-full left-0 mb-2 flex flex-col gap-1 bg-white rounded-2xl shadow-xl border border-gray-100 p-2 z-30"
              >
                {/* Paperclip */}
                <div className="group relative flex items-center">
                  <button
                    onClick={() => { fileInputRef.current?.click(); setShowAttachMenu(false); }}
                    className="p-2.5 rounded-xl hover:bg-[#f0f2f5] text-[#54656f] transition-colors"
                    title="Anexar arquivo"
                  >
                    <Paperclip size={20} />
                  </button>
                  <span className="absolute left-full ml-2 px-2 py-1 text-[11px] font-medium bg-[#111b21] text-white rounded-lg opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none">
                    Anexar arquivo
                  </span>
                </div>

                {/* Template Library */}
                <div className="group relative flex items-center">
                  <button
                    onClick={() => { setShowTemplateLib(true); setShowAttachMenu(false); }}
                    className="p-2.5 rounded-xl hover:bg-[#e0f2fe] text-[#0ea5e9] transition-colors"
                    title="Biblioteca de templates"
                  >
                    <BookOpen size={20} />
                  </button>
                  <span className="absolute left-full ml-2 px-2 py-1 text-[11px] font-medium bg-[#111b21] text-white rounded-lg opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none">
                    Templates salvos
                  </span>
                </div>

                {/* Rich Composer */}
                <div className="group relative flex items-center">
                  <button
                    onClick={() => { setRichInitPayload(undefined); setRichInitType('TEXT'); setShowRichComposer(true); setShowAttachMenu(false); }}
                    className="p-2.5 rounded-xl hover:bg-[#ede9fe] text-[#8b5cf6] transition-colors"
                    title="Mensagem rica"
                  >
                    <LayoutTemplate size={20} />
                  </button>
                  <span className="absolute left-full ml-2 px-2 py-1 text-[11px] font-medium bg-[#111b21] text-white rounded-lg opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none">
                    Mensagem rica
                  </span>
                </div>
              </motion.div>
            )}
          </AnimatePresence>

          <input type="file" ref={fileInputRef} className="hidden" />
        </div>

        {/* Textarea */}
        <div className="flex-1 bg-white rounded-lg shadow-sm overflow-hidden">
          <textarea
            ref={textareaRef}
            value={value}
            onChange={e => { onChange(e.target.value); autoResize(); }}
            onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); onSend(); } }}
            placeholder="Mensagem"
            rows={1}
            className="w-full px-4 py-[9px] text-[15px] text-[#111b21] placeholder:text-[#8696a0] outline-none resize-none bg-transparent leading-[1.5]"
            style={{ minHeight: 42, maxHeight: 150 }}
          />
        </div>

        {/* IA + Send / Mic */}
        <div className="pb-[7px] flex items-center gap-2">
          {value.trim() && (
            <button onClick={onAskAi} disabled={askingAi || sending} title="Gerar resposta com Secretária IA"
              className="w-10 h-10 bg-[#7c3aed] hover:bg-[#6d28d9] disabled:opacity-50 text-white rounded-full flex items-center justify-center transition-all active:scale-95 shadow-md">
              {askingAi ? <span className="w-4 h-4 border-2 border-white/40 border-t-white rounded-full animate-spin" /> : <Sparkles size={16} />}
            </button>
          )}
          {value.trim()
            ? <button onClick={onSend} disabled={sending}
                className="w-10 h-10 bg-[#00a884] hover:bg-[#017f67] disabled:opacity-50 text-white rounded-full flex items-center justify-center transition-all active:scale-95 shadow-md">
                <Send size={18} />
              </button>
            : <button className="w-10 h-10 text-[#54656f] hover:bg-black/5 rounded-full flex items-center justify-center transition-colors">
                <Mic size={24} />
              </button>
          }
        </div>
      </div>

      <RichMessageComposer
        isOpen={showRichComposer}
        onClose={() => setShowRichComposer(false)}
        chatId={chatId}
        initialPayload={richInitPayload}
        initialType={richInitType}
        onSchedule={handleScheduleFromComposer}
      />
      <TemplateLibrary
        isOpen={showTemplateLib}
        onClose={() => setShowTemplateLib(false)}
        onSelect={handleTemplateSelect}
      />
      <ScheduleMessageModal
        isOpen={showSchedule}
        onClose={() => setShowSchedule(false)}
        payload={schedPayload}
        messageType={schedType}
      />
    </>
  );
}

// ═════════════════════════════════════════════════════════════════════════════
//  Componente principal
// ═════════════════════════════════════════════════════════════════════════════
// Cargos que podem ver a aba Equipe (configurações de RH)
const EQUIPE_ROLES = new Set(['owner', 'manager', 'supervisor']);

interface WhatsAppInboxPageProps {
  teamAccount?: { id: number; name: string; email: string; role: string } | null;
  onTeamLogout?: () => void;
}

export default function WhatsAppInboxPage({ teamAccount, onTeamLogout }: WhatsAppInboxPageProps = {}) {
  // ── State ──────────────────────────────────────────────────────────────────
  const [sessions,        setSessions]        = useState<NwSession[]>([]);
  const [selectedSession, setSelectedSession] = useState<NwSession | null>(null);
  const [qrData,          setQrData]          = useState<Record<string, string>>({});
  const [chats,           setChats]           = useState<NwChat[]>([]);
  const [selectedChat,    setSelectedChat]    = useState<NwChat | null>(null);
  const [messages,        setMessages]        = useState<NwMessage[]>([]);
  const [searchChat,      setSearchChat]      = useState('');
  const [sendText,        setSendText]        = useState('');
  const [sending,         setSending]         = useState(false);
  const [askingAi,        setAskingAi]        = useState(false);
  const [loadingSessions, setLoadingSessions] = useState(true);
  const [loadingChats,    setLoadingChats]    = useState(false);
  const [loadingMessages, setLoadingMessages] = useState(false);
  const [loadingMore,     setLoadingMore]     = useState(false);
  const [hasMore,         setHasMore]         = useState(false);
  const [wsStatus,        setWsStatus]        = useState<'connecting' | 'open' | 'closed'>('connecting');

  // UI state
  const [activeTab,           setActiveTab]           = useState<TabType>('chats');
  const [sessionDropdownOpen, setSessionDropdownOpen] = useState(false);
  const [isMobile,            setIsMobile]            = useState(false);

  // Admin ↔ Account link
  // Quando o admin está logado sem teamAccount (sem segundo login de equipe),
  // buscamos o linkedAccount associado ao seu perfil de admin.
  // Isso permite que o admin acesse a Inbox Interna com sua identidade de
  // colaborador sem precisar fazer login duplo.
  const [adminLinkedAccount, setAdminLinkedAccount] = useState<{ id: number; name: string; email: string; role: string; avatar_url: string | null } | null>(null);
  useEffect(() => {
    if (!teamAccount) {
      // Só busca quando não há login de equipe ativo — evita busca redundante
      AdminMeService.get()
        .then(d => setAdminLinkedAccount(d.linkedAccount ?? null))
        .catch(() => {});
    }
  }, [teamAccount]);

  // accountId efetivo para a Inbox Interna:
  // 1. Se logado como colaborador → usa teamAccount.id (fluxo normal)
  // 2. Se logado como admin com account vinculado → usa linkedAccount.id
  // 3. Caso contrário → undefined (Inbox Interna mostra aviso)
  const inboxAccountId = teamAccount?.id ?? adminLinkedAccount?.id ?? undefined;

  // Badge de não lidas na Inbox Interna (INB-03)
  // Polling a cada 30s para manter o badge do ThinSidebar atualizado.
  // Incrementa também quando chega evento SSE de nova mensagem interna.
  const [inboxUnread, setInboxUnread] = useState(0);
  useEffect(() => {
    if (!inboxAccountId) return;
    const fetchUnread = () => {
      fetch('/api/cotacoes/admin/inbox/contadores', { credentials: 'include' })
        .then(r => r.ok ? r.json() : null)
        .then(d => { if (d?.total != null) setInboxUnread(Number(d.total)); })
        .catch(() => {});
    };
    fetchUnread();
    const id = setInterval(fetchUnread, 30_000);
    return () => clearInterval(id);
  }, [inboxAccountId]);

  // Auto-reply mode (para HandoffButton)
  const [autoReplyMode, setAutoReplyMode] = useState<'off' | 'automatico'>('off');

  // Força HandoffButton a re-buscar o modo quando incrementado
  const [handoffRefreshKey, setHandoffRefreshKey] = useState(0);

  // Toast notifications
  const [toasts, setToasts] = useState<{ id: number; msg: string; type: 'info'|'warning'; action?: { label: string; onClick: () => void } }[]>([]);
  const toastIdRef = useRef(0);
  const dismissToast = useCallback((id: number) => setToasts(t => t.filter(x => x.id !== id)), []);
  const showToast = useCallback((msg: string, type: 'info'|'warning' = 'info', action?: { label: string; onClick: () => void }) => {
    const id = ++toastIdRef.current;
    setToasts(t => [...t, { id, msg, type, action }]);
    if (!action) setTimeout(() => dismissToast(id), 6000);
  }, [dismissToast]);

  // Nova conversa
  const [newConvOpen, setNewConvOpen] = useState(false);

  // Numbers (Frente 1)
  const [numbers,       setNumbers]       = useState<NwNumber[]>([]);
  const [addModalOpen,  setAddModalOpen]  = useState(false);
  const [editTarget,    setEditTarget]    = useState<{ num: NwNumber | null; session?: NwSession } | null>(null);
  const [deletingId,    setDeletingId]    = useState<string | null>(null);

  // Sync knowledge (Frente 3)
  const [syncing,       setSyncing]       = useState(false);
  const [syncOk,        setSyncOk]        = useState(false);

  const wsRef          = useRef<WebSocket | null>(null);
  const msgEndRef      = useRef<HTMLDivElement>(null);
  const msgTopRef      = useRef<HTMLDivElement>(null);
  const msgAreaRef     = useRef<HTMLDivElement>(null);
  const sessionDropRef = useRef<HTMLDivElement>(null);

  // ── Responsive ────────────────────────────────────────────────────────────
  useEffect(() => {
    const fn = () => setIsMobile(window.innerWidth < 768);
    window.addEventListener('resize', fn);
    fn();
    return () => window.removeEventListener('resize', fn);
  }, []);

  // ── Click outside session dropdown ────────────────────────────────────────
  useEffect(() => {
    const fn = (e: MouseEvent) => {
      if (sessionDropRef.current && !sessionDropRef.current.contains(e.target as Node))
        setSessionDropdownOpen(false);
    };
    document.addEventListener('mousedown', fn);
    return () => document.removeEventListener('mousedown', fn);
  }, []);

  // ── Fetch sessions ─────────────────────────────────────────────────────────
  const fetchSessions = useCallback(async () => {
    setLoadingSessions(true);
    try {
      const data = await NwService.getSessions();
      setSessions(data);
      if (!selectedSession && data.length > 0) {
        const savedId = localStorage.getItem('wa_selected_session');
        const restored = savedId ? data.find(s => s.id === savedId) : null;
        setSelectedSession(restored ?? data[0]);
      }
    } catch { /* handled by 401 interceptor */ }
    finally { setLoadingSessions(false); }
  }, [selectedSession]);

  // ── Fetch numbers ──────────────────────────────────────────────────────────
  const fetchNumbers = useCallback(async () => {
    try {
      const data = await NwService.getNumbers();
      setNumbers(data);
    } catch { /* silencioso */ }
  }, []);

  useEffect(() => {
    fetchSessions();
    fetchNumbers();
    NwService.getAutoReplyMode().then(d => setAutoReplyMode(d.mode)).catch(() => {});
  }, []);

  // ── SSE — recebe eventos do servidor ──────────────────────────────────────
  useEffect(() => {
    const es = new EventSource('/api/sse', { withCredentials: true });

    es.addEventListener('handoff.expired', (e: MessageEvent) => {
      try {
        const { chatId } = JSON.parse(e.data);
        setSelectedChat(cur => {
          if (cur?.id === chatId) {
            showToast('IA retomou o atendimento automaticamente (15 min sem resposta)', 'info');
            setHandoffRefreshKey(k => k + 1);
          }
          return cur;
        });
      } catch {}
    });

    es.addEventListener('human_api.new', (e: MessageEvent) => {
      try {
        const { question, sectorName } = JSON.parse(e.data);
        const label = sectorName ? `[${sectorName}]` : '';
        showToast(`🤖 IA precisa de ajuda ${label}: "${String(question).slice(0, 60)}"`, 'warning', {
          label: 'Ver Inbox',
          onClick: () => setActiveTab('inbox-interna'),
        });
      } catch {}
    });

    es.addEventListener('sla.breach', (e: MessageEvent) => {
      try {
        const { sectorName, elapsedMins, slaMins } = JSON.parse(e.data);
        showToast(`⚠ SLA estourado — ${sectorName}: ${elapsedMins}min (limite ${slaMins}min)`, 'warning', {
          label: 'Ver Inbox',
          onClick: () => setActiveTab('inbox-interna'),
        });
      } catch {}
    });

    es.addEventListener('human_api.answered', () => {});

    return () => es.close();
  }, [showToast]);

  // ── Delete session + number ────────────────────────────────────────────────
  const handleDeleteSession = useCallback(async (sessionId: string) => {
    if (!window.confirm('Remover este número? A sessão será desconectada e os dados apagados.')) return;
    setDeletingId(sessionId);
    try {
      const num = numbers.find(n => n.instance_id === sessionId);
      await NwService.deleteSession(sessionId);
      if (num) await NwService.deleteNumber(num.id).catch(() => {});
      if (selectedSession?.id === sessionId) setSelectedSession(null);
      await fetchSessions();
      await fetchNumbers();
    } catch { alert('Erro ao remover sessão.'); }
    finally { setDeletingId(null); }
  }, [numbers, selectedSession, fetchSessions, fetchNumbers]);

  // ── Sync knowledge ─────────────────────────────────────────────────────────
  const handleSyncKnowledge = useCallback(async () => {
    setSyncing(true); setSyncOk(false);
    try {
      await fetch('/api/admin/nw/sync-knowledge', { method: 'POST', credentials: 'include' });
      setSyncOk(true);
      setTimeout(() => setSyncOk(false), 3000);
    } catch { alert('Erro ao sincronizar base de conhecimento.'); }
    finally { setSyncing(false); }
  }, []);

  // ── Fetch QR when QR_PENDING ───────────────────────────────────────────────
  useEffect(() => {
    if (!selectedSession || selectedSession.status !== 'QR_PENDING') return;
    NwService.getQr(selectedSession.id)
      .then(d => setQrData(prev => ({ ...prev, [selectedSession.id]: d.qrBase64 })))
      .catch(() => {});
  }, [selectedSession?.id, selectedSession?.status]);

  // ── Fetch chats ───────────────────────────────────────────────────────────
  useEffect(() => {
    if (!selectedSession || selectedSession.status !== 'CONNECTED') { setChats([]); return; }
    setLoadingChats(true);
    NwService.getInbox(selectedSession.id, undefined, 60)
      .then(setChats).catch(() => {}).finally(() => setLoadingChats(false));
  }, [selectedSession?.id, selectedSession?.status]);

  // ── Fetch messages ────────────────────────────────────────────────────────
  const MSGS_LIMIT = 50;
  useEffect(() => {
    if (!selectedChat) { setMessages([]); setHasMore(false); return; }
    setLoadingMessages(true);
    NwService.getMessages(selectedChat.id, MSGS_LIMIT)
      .then(data => { setMessages(data); setHasMore(data.length === MSGS_LIMIT); })
      .catch(() => {})
      .finally(() => setLoadingMessages(false));
  }, [selectedChat?.id]);

  // ── Load older messages (scroll infinito) ────────────────────────────────
  const loadMore = useCallback(async () => {
    if (!selectedChat || loadingMore || !hasMore || messages.length === 0) return;
    const oldest = messages[0].timestamp;
    setLoadingMore(true);
    try {
      const older = await NwService.getMessages(selectedChat.id, MSGS_LIMIT, oldest);
      if (older.length === 0) { setHasMore(false); return; }
      setHasMore(older.length === MSGS_LIMIT);
      const area = msgAreaRef.current;
      const prevH = area?.scrollHeight ?? 0;
      setMessages(prev => [...older, ...prev]);
      requestAnimationFrame(() => {
        if (area) area.scrollTop = area.scrollHeight - prevH;
      });
    } catch { /* silencioso */ }
    finally { setLoadingMore(false); }
  }, [selectedChat, loadingMore, hasMore, messages]);

  // ── Scroll to bottom on first load ───────────────────────────────────────
  const prevChatIdRef = useRef<string | null>(null);
  useEffect(() => {
    if (!selectedChat) return;
    if (prevChatIdRef.current !== selectedChat.id) {
      prevChatIdRef.current = selectedChat.id;
      msgEndRef.current?.scrollIntoView({ behavior: 'instant' as ScrollBehavior });
    } else {
      msgEndRef.current?.scrollIntoView({ behavior: 'smooth' });
    }
  }, [messages]);

  // ── IntersectionObserver: sentinela no topo → carrega mais ───────────────
  useEffect(() => {
    const el = msgTopRef.current;
    if (!el) return;
    const obs = new IntersectionObserver(entries => {
      if (entries[0].isIntersecting) loadMore();
    }, { threshold: 0.1 });
    obs.observe(el);
    return () => obs.disconnect();
  }, [loadMore]);

  // ── WebSocket ─────────────────────────────────────────────────────────────
  useEffect(() => {
    const wsUrl = `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}/api/nw/v1/stream`;
    let ws: WebSocket;
    let timer: ReturnType<typeof setTimeout>;
    let destroyed = false;
    let delay = 3000;

    function connect() {
      if (destroyed) return;
      ws = new WebSocket(wsUrl);
      wsRef.current = ws;
      setWsStatus('connecting');
      ws.onopen = () => { delay = 3000; setWsStatus('open'); };
      ws.onmessage = (evt) => {
        let env: WsEnvelope;
        try { env = JSON.parse(evt.data); } catch { return; }
        const { event, data } = env;

        if (event === 'session.qr') {
          setQrData(prev => ({ ...prev, [data.instanceId]: data.qrBase64 }));
          setSessions(prev => prev.map(s => s.id === data.instanceId ? { ...s, status: 'QR_PENDING' } : s));
          setSelectedSession(prev => prev?.id === data.instanceId ? { ...prev, status: 'QR_PENDING' as const } as NwSession : prev);
        }
        if (event === 'session.status') {
          const ns: NwSession['status'] = data.status === 'connected' ? 'CONNECTED' : 'DISCONNECTED';
          setSessions(prev => prev.map(s => s.id === data.instanceId ? { ...s, status: ns } : s));
          setSelectedSession(prev => prev?.id === data.instanceId ? { ...prev, status: ns } as NwSession : prev);
          if (data.status === 'connected')
            NwService.getInbox(data.instanceId, undefined, 60).then(setChats).catch(() => {});
        }
        if (event === 'message.update') {
          setMessages(prev => prev.map(m =>
            m.messageId === data.messageId ? { ...m, status: data.status } : m
          ));
        }
        if (event === 'conversation.handoff') {
          if (data.mode === 'ia' && data.reason === 'timeout') {
            showToast('Secretária retomou o atendimento automaticamente (15 min sem resposta)', 'info');
          }
        }
        if (event === 'conversation.escalated') {
          const proto  = data.protocolNumber ? ` #${data.protocolNumber}` : '';
          const motivo = data.motivo ? ` — ${data.motivo}` : '';
          showToast(
            `Escalação${proto}${motivo}: cliente aguarda atendimento humano`,
            'warning',
            {
              label: 'Assumir',
              onClick: async () => {
                try {
                  await EscalationService.assume({
                    chatId:         data.chatId || '',
                    protocolNumber: data.protocolNumber,
                    chatName:       data.chatName,
                  });
                  setActiveTab('inbox-interna');
                } catch { /* silencioso */ }
              },
            }
          );
        }
        if (event === 'message.new') {
          setChats(prev => prev.map(c =>
            c.id === data.chatId
              ? { ...c,
                  unreadCount: c.unreadCount + (data.message?.fromMe ? 0 : 1),
                  lastMessageAt: new Date().toISOString(),
                  lastMessage: { body: data.message?.body, type: data.message?.type || 'TEXT', fromMe: !!data.message?.fromMe, status: 'SENT', timestamp: new Date().toISOString() },
                }
              : c
          ));
          setSelectedChat(cur => {
            if (cur?.id === data.chatId) {
              setMessages(prev => [...prev, {
                id:        data.message?.id || `tmp-${Date.now()}`,
                messageId: data.message?.messageId || '',
                fromMe:    data.message?.fromMe ?? false,
                type:      data.message?.type || 'TEXT',
                body:      data.message?.body ?? null,
                caption:   data.message?.caption ?? null,
                mediaUrl:  data.message?.mediaUrl ?? null,
                mimeType:  data.message?.mimeType ?? null,
                fileName:  data.message?.fileName ?? null,
                status:    'DELIVERED',
                timestamp: new Date().toISOString(),
                pushName:  data.message?.pushName ?? null,
                senderJid: data.message?.senderJid ?? null,
              }]);
            }
            return cur;
          });
        }
      };
      ws.onclose = () => {
        setWsStatus('closed');
        if (!destroyed) {
          timer = setTimeout(connect, delay);
          delay = Math.min(delay * 2, 60000);
        }
      };
      ws.onerror = () => { ws.close(); };
    }

    connect();
    return () => { destroyed = true; clearTimeout(timer); ws?.close(); };
  }, []);

  // ── Archive ───────────────────────────────────────────────────────────────
  const handleArchive = useCallback(async () => {
    if (!selectedChat) return;
    try {
      await NwService.archive(selectedChat.id, true);
      setChats(prev => prev.filter(c => c.id !== selectedChat.id));
      setSelectedChat(null);
    } catch { /* silencioso */ }
  }, [selectedChat]);

  // ── Send ──────────────────────────────────────────────────────────────────
  const handleSend = async () => {
    if (!selectedChat || !sendText.trim() || sending) return;
    const rawText = sendText.trim();
    const text = teamAccount?.name ? `*${teamAccount.name}:*\n${rawText}` : rawText;
    setSendText('');
    setSending(true);
    const opt: NwMessage = {
      id: `opt-${Date.now()}`, messageId: '', fromMe: true, type: 'TEXT',
      body: text, caption: null, mediaUrl: null, mimeType: null, fileName: null,
      status: 'PENDING', timestamp: new Date().toISOString(),
      pushName: null, senderJid: null,
    };
    setMessages(prev => [...prev, opt]);
    try {
      await NwService.send(selectedChat.id, text);
      // Pausa IA automaticamente ao enviar, se auto-reply estiver ativo
      if (autoReplyMode === 'automatico') {
        await NwService.setHandoffMode(selectedChat.id, 'humano').catch(() => {});
        setHandoffRefreshKey(k => k + 1);
      }
    } catch {
      setMessages(prev => prev.filter(m => m.id !== opt.id));
      setSendText(rawText);
    } finally {
      setSending(false);
    }
  };

  // ── Ask Secretária IA ─────────────────────────────────────────────────────
  const handleAskAi = async () => {
    if (!selectedChat || !sendText.trim() || askingAi) return;
    const userMsg = sendText.trim();
    setAskingAi(true);
    try {
      const contactName = selectedChat.displayName ?? selectedChat.phone;
      const result = await NwService.secretariaAsk(selectedChat.id, userMsg, contactName);
      setSendText(result.reply);
    } catch (err: any) {
      alert(`Erro ao consultar Secretária IA: ${err?.response?.data?.error ?? err.message}`);
    } finally {
      setAskingAi(false);
    }
  };

  // ── Filtered chats ────────────────────────────────────────────────────────
  const filteredChats = useMemo(() => {
    if (!searchChat) return chats;
    const q = searchChat.toLowerCase();
    return chats.filter(c => (c.displayName ?? c.phone).toLowerCase().includes(q));
  }, [chats, searchChat]);

  // ── Total unread ──────────────────────────────────────────────────────────
  const totalUnread = useMemo(() => chats.reduce((acc, c) => acc + c.unreadCount, 0), [chats]);

  // ── Messages with date groups ─────────────────────────────────────────────
  const isGroupChat = useMemo(() => selectedChat?.jid?.endsWith('@g.us') ?? false, [selectedChat]);
  type MsgWithMeta = { msg: NwMessage; showTail: boolean; showSeparator: boolean; separatorLabel: string; showSender: boolean };
  const messagesWithMeta = useMemo((): MsgWithMeta[] => {
    return messages.map((msg, i) => {
      const prev = messages[i - 1];
      const showTail = !prev || prev.fromMe !== msg.fromMe;
      const showSeparator = !prev || !isSameCalDay(prev.timestamp, msg.timestamp);
      const separatorLabel = showSeparator ? dateSeparator(msg.timestamp) : '';
      const showSender = isGroupChat && !msg.fromMe && (showTail || prev?.senderJid !== msg.senderJid);
      return { msg, showTail, showSeparator, separatorLabel, showSender };
    });
  }, [messages, isGroupChat]);

  // ─────────────────────────────────────────────────────────────────────────
  //  RENDER
  // ─────────────────────────────────────────────────────────────────────────

  // Left panel visibility on mobile
  const fullScreenTab = activeTab === 'secretaria' || activeTab === 'equipe' || activeTab === 'inbox-interna' || activeTab === 'metricas';
  const showLeft  = !isMobile || !selectedChat;
  const showRight = !fullScreenTab && (!isMobile || !!selectedChat);

  return (
    <>
    {/* ── Toast notifications ──────────────────────────────────────────────── */}
    <div className="fixed top-4 right-4 z-[9999] flex flex-col gap-2 pointer-events-none">
      {toasts.map(t => (
        <div key={t.id}
          className={`flex flex-col gap-2 px-4 py-3 rounded-xl shadow-xl text-[13px] font-medium max-w-[360px] pointer-events-auto
            ${t.type === 'warning' ? 'bg-orange-500 text-white' : 'bg-[#111b21] text-white'}`}>
          <div className="flex items-start gap-2">
            {t.type === 'warning' && <Siren size={15} className="flex-shrink-0 mt-0.5 animate-pulse" />}
            <span className="flex-1">{t.msg}</span>
            <button onClick={() => dismissToast(t.id)} className="ml-1 opacity-70 hover:opacity-100 flex-shrink-0">
              <X size={13} />
            </button>
          </div>
          {t.action && (
            <button
              onClick={() => { t.action!.onClick(); dismissToast(t.id); }}
              className="self-end px-3 py-1 bg-white/20 hover:bg-white/30 rounded-lg text-[12px] font-bold transition-colors flex items-center gap-1.5">
              <ArrowRightCircle size={12} />
              {t.action.label}
            </button>
          )}
        </div>
      ))}
    </div>
    <div className="flex h-screen w-full bg-[#f0f2f5] overflow-hidden select-none font-sans text-[#111b21]">

      {/* ── ThinSidebar ────────────────────────────────────────────────────── */}
      <ThinSidebar
        activeTab={activeTab}
        setActiveTab={(t) => {
          // Zera o badge ao abrir a Inbox Interna
          if (t === 'inbox-interna') setInboxUnread(0);
          setActiveTab(t);
        }}
        session={selectedSession}
        inboxUnread={inboxUnread}
        teamAccount={teamAccount}
        onTeamLogout={onTeamLogout}
      />

      {/* ── Painel Esquerdo ────────────────────────────────────────────────── */}
      {showLeft && (
        <div className={`${fullScreenTab ? 'flex-1' : isMobile ? 'w-full' : 'w-[400px]'} flex flex-col bg-white border-r border-[#d1d7db] flex-shrink-0 z-20`}>

          {/* ───── Tab: Sessions ──────────────────────────────────────────── */}
          {activeTab === 'sessions' && (
            <>
              {/* Header */}
              <div className="px-3 py-2 bg-[#f0f2f5] border-b border-[#d1d7db] flex-shrink-0">
                <div className="flex items-center justify-between">
                  <h2 className="text-[16px] font-bold text-[#111b21]">Sessões WhatsApp</h2>
                  <div className="flex items-center gap-1">
                    {wsStatus === 'open'
                      ? <Wifi size={13} className="text-[#00a884]" />
                      : <WifiOff size={13} className="text-red-500" />
                    }
                    <button onClick={fetchSessions} className="p-1.5 hover:bg-black/5 rounded-full transition-colors" title="Atualizar">
                      <RefreshCw size={14} className={`text-[#54656f] ${loadingSessions ? 'animate-spin' : ''}`} />
                    </button>
                  </div>
                </div>
                {/* Action buttons row */}
                <div className="flex items-center gap-2 mt-2">
                  <button
                    onClick={() => setAddModalOpen(true)}
                    className="flex-1 flex items-center justify-center gap-1.5 py-1.5 bg-[#00a884] hover:bg-[#017f67] text-white text-[12px] font-semibold rounded-lg transition-all"
                  >
                    <Plus size={13} /> Novo Número
                  </button>
                  <button
                    onClick={handleSyncKnowledge}
                    disabled={syncing}
                    title="Sincronizar base de conhecimento da IA com dados do banco"
                    className={`flex-1 flex items-center justify-center gap-1.5 py-1.5 text-[12px] font-semibold rounded-lg border transition-all
                      ${syncOk
                        ? 'bg-emerald-50 border-emerald-300 text-emerald-700'
                        : 'bg-white border-[#d1d7db] text-[#54656f] hover:border-[#00a884] hover:text-[#00a884]'
                      } disabled:opacity-50`}
                  >
                    {syncing
                      ? <><span className="w-3 h-3 border border-current border-t-transparent rounded-full animate-spin" /> Sincronizando…</>
                      : syncOk
                        ? <><Sparkles size={13} /> IA Atualizada ✓</>
                        : <><Sparkles size={13} /> Sincronizar IA</>
                    }
                  </button>
                </div>
              </div>
              {/* Body */}
              <div className="flex-1 overflow-y-auto">
                {loadingSessions
                  ? [1,2].map(i => <div key={i} className="m-3 h-28 rounded-2xl bg-[#f0f2f5] animate-pulse" />)
                  : sessions.length === 0
                    ? (
                      <div className="flex flex-col items-center gap-3 py-16 px-6 text-center">
                        <div className="w-14 h-14 rounded-full bg-[#f0f2f5] flex items-center justify-center">
                          <Smartphone size={24} className="text-[#8696a0]" />
                        </div>
                        <p className="text-[#667781] text-sm">Nenhum número cadastrado.</p>
                        <button onClick={() => setAddModalOpen(true)}
                          className="text-[#00a884] text-sm font-semibold hover:underline flex items-center gap-1">
                          <Plus size={14} /> Adicionar primeiro número
                        </button>
                      </div>
                    )
                    : sessions
                        .slice()
                        .sort((a, b) => {
                          const na = numbers.find(n => n.instance_id === a.id);
                          const nb = numbers.find(n => n.instance_id === b.id);
                          return (na?.priority ?? 99) - (nb?.priority ?? 99);
                        })
                        .map(s => {
                          const numInfo = numbers.find(n => n.instance_id === s.id);
                          return (
                            <div key={s.id}
                              className={`m-3 p-4 rounded-2xl border transition-all
                                ${selectedSession?.id === s.id
                                  ? 'bg-[#00a884]/5 border-[#00a884]/30'
                                  : 'bg-white border-[#d1d7db] hover:border-[#c0c8cf]'
                                }`}
                            >
                              {/* Card header */}
                              <div className="flex items-start gap-3">
                                <div className="cursor-pointer flex-1 flex items-center gap-3 min-w-0"
                                  onClick={() => { setSelectedSession(s); localStorage.setItem('wa_selected_session', s.id); setActiveTab('chats'); }}>
                                  <AvatarEl src={s.avatar} name={s.name} size={42} />
                                  <div className="flex-1 min-w-0">
                                    <p className="text-[15px] font-semibold text-[#111b21] truncate">{s.name}</p>
                                    <p className="text-[12px] text-[#667781] font-mono">{s.phone ?? '—'}</p>
                                    {numInfo?.area && (
                                      <p className="text-[11px] text-[#8696a0] truncate">{numInfo.area}</p>
                                    )}
                                  </div>
                                </div>
                                {/* Action buttons */}
                                <div className="flex items-center gap-1 flex-shrink-0">
                                  <button
                                    onClick={e => { e.stopPropagation(); setEditTarget({ num: numInfo ?? null, session: s }); }}
                                    className="p-1.5 hover:bg-black/5 rounded-full transition-colors text-[#8696a0] hover:text-[#54656f]"
                                    title="Editar / Reconectar"
                                  >
                                    <Edit2 size={14} />
                                  </button>
                                  <button
                                    onClick={e => { e.stopPropagation(); handleDeleteSession(s.id); }}
                                    disabled={deletingId === s.id}
                                    className="p-1.5 hover:bg-red-50 rounded-full transition-colors text-[#8696a0] hover:text-red-500 disabled:opacity-40"
                                    title="Remover número"
                                  >
                                    {deletingId === s.id
                                      ? <span className="w-3.5 h-3.5 border border-red-400 border-t-transparent rounded-full animate-spin block" />
                                      : <Trash2 size={14} />
                                    }
                                  </button>
                                </div>
                              </div>

                              {/* Badges row */}
                              <div className="mt-3 flex items-center gap-2 flex-wrap">
                                <SessionBadge status={s.status} />
                                {numInfo && (
                                  <NumberBadge role={numInfo.role} priority={numInfo.priority} />
                                )}
                                {!numInfo && (
                                  <span className="text-[10px] text-[#8696a0] italic">sem categoria</span>
                                )}
                              </div>

                              {/* Notes */}
                              {numInfo?.notes && (
                                <p className="mt-2 text-[11px] text-[#8696a0] italic truncate">{numInfo.notes}</p>
                              )}

                              {/* QR Code */}
                              {s.status === 'QR_PENDING' && qrData[s.id] && (
                                <div className="mt-3 flex flex-col items-center gap-2">
                                  <img src={qrData[s.id]} alt="QR Code"
                                    className="w-44 h-44 rounded-xl border-2 border-amber-400/30 bg-white p-1.5" />
                                  <p className="text-[11px] text-amber-600 font-bold uppercase tracking-wide text-center">
                                    Escaneie com o WhatsApp
                                  </p>
                                </div>
                              )}
                              {s.status === 'QR_PENDING' && !qrData[s.id] && (
                                <div className="mt-3 flex items-center justify-center gap-2 py-3 bg-amber-50 rounded-xl border border-amber-200">
                                  <QrCode size={15} className="text-amber-500 animate-pulse" />
                                  <span className="text-[11px] text-amber-600 font-semibold">Aguardando QR...</span>
                                </div>
                              )}
                            </div>
                          );
                        })
                }
              </div>
            </>
          )}

          {/* ───── Tab: Chats ─────────────────────────────────────────────── */}
          {activeTab === 'chats' && (
            <>
              {/* Header */}
              <div className="h-[60px] px-4 flex items-center justify-between bg-[#f0f2f5] border-b border-[#d1d7db] flex-shrink-0">
                {/* Left: back + session dropdown */}
                <div className="flex items-center gap-1">
                  {isMobile && selectedChat && (
                    <button onClick={() => setSelectedChat(null)} className="p-2 hover:bg-black/5 rounded-full">
                      <ArrowLeft size={20} className="text-[#54656f]" />
                    </button>
                  )}
                  <div className="relative" ref={sessionDropRef}>
                    <div
                      onClick={() => sessions.length > 1 && setSessionDropdownOpen(v => !v)}
                      className={`flex items-center gap-2 p-1 rounded-md transition-all ${sessions.length > 1 ? 'cursor-pointer hover:bg-black/5' : ''}`}
                    >
                      <AvatarEl src={selectedSession?.avatar} name={selectedSession?.name} size={38} />
                      <div className="min-w-0">
                        <p className="text-[15px] font-semibold text-[#111b21] truncate max-w-[120px] leading-tight">
                          {selectedSession?.name ?? 'Instância'}
                        </p>
                        {selectedSession && (
                          <p className="text-[11px] text-[#667781] leading-tight">
                            {SESSION_STATUS[selectedSession.status]?.label ?? selectedSession.status}
                          </p>
                        )}
                      </div>
                      {sessions.length > 1 && (
                        <ChevronDown size={16} className={`text-[#54656f] transition-transform ${sessionDropdownOpen ? 'rotate-180' : ''}`} />
                      )}
                    </div>
                    {sessionDropdownOpen && (
                      <div className="absolute left-0 top-full mt-1 bg-white shadow-2xl rounded-xl border border-gray-100 w-72 z-50 py-2">
                        {sessions.map(s => (
                          <button key={s.id}
                            onClick={() => { setSelectedSession(s); localStorage.setItem('wa_selected_session', s.id); setSelectedChat(null); setSessionDropdownOpen(false); }}
                            className="w-full px-4 py-3 hover:bg-[#f5f6f6] flex items-center gap-3 transition-colors"
                          >
                            <AvatarEl src={s.avatar} name={s.name} size={34} />
                            <div className="text-left flex-1 min-w-0">
                              <p className="text-[14px] font-semibold text-[#111b21] truncate">{s.name}</p>
                              <p className={`text-[12px] ${s.status === 'CONNECTED' ? 'text-[#00a884]' : 'text-[#667781]'}`}>
                                {SESSION_STATUS[s.status]?.label ?? s.status}
                              </p>
                            </div>
                          </button>
                        ))}
                      </div>
                    )}
                  </div>
                </div>
                {/* Right: unread badge + nova conversa + refresh */}
                <div className="flex items-center gap-1">
                  {totalUnread > 0 && (
                    <span className="bg-[#00a884] text-white text-[11px] font-bold px-1.5 py-0.5 rounded-full min-w-[20px] h-5 flex items-center justify-center">
                      {totalUnread > 99 ? '99+' : totalUnread}
                    </span>
                  )}
                  {selectedSession?.status === 'CONNECTED' && (
                    <button onClick={() => setNewConvOpen(true)} className="p-2 hover:bg-black/5 rounded-full transition-colors" title="Nova conversa">
                      <Edit2 size={16} className="text-[#54656f]" />
                    </button>
                  )}
                  <button onClick={() => {
                    if (selectedSession) {
                      setLoadingChats(true);
                      NwService.getInbox(selectedSession.id, undefined, 60)
                        .then(setChats).catch(() => {}).finally(() => setLoadingChats(false));
                    }
                  }} className="p-2 hover:bg-black/5 rounded-full transition-colors" title="Atualizar chats">
                    <RefreshCw size={16} className={`text-[#54656f] ${loadingChats ? 'animate-spin' : ''}`} />
                  </button>
                </div>
              </div>

              {/* Search */}
              <div className="px-4 py-2 bg-white">
                <div className="relative">
                  <Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-[#8696a0]" />
                  <input
                    type="text"
                    value={searchChat}
                    onChange={e => setSearchChat(e.target.value)}
                    placeholder="Pesquisar ou começar nova conversa"
                    className="w-full bg-[#f0f2f5] h-[35px] pl-9 pr-3 rounded-lg text-[14px] text-[#111b21] placeholder:text-[#8696a0] border-none focus:ring-0 outline-none"
                  />
                  {searchChat && (
                    <button onClick={() => setSearchChat('')} className="absolute right-2 top-1/2 -translate-y-1/2">
                      <X size={14} className="text-[#8696a0]" />
                    </button>
                  )}
                </div>
              </div>

              {/* Chat list */}
              <div className="flex-1 overflow-y-auto">
                {!selectedSession ? (
                  <p className="text-[#667781] text-sm italic text-center py-16 px-6">Selecione uma sessão</p>
                ) : selectedSession.status !== 'CONNECTED' ? (
                  <div className="flex flex-col items-center justify-center h-full gap-4 text-[#667781]">
                    {selectedSession.status === 'QR_PENDING' ? (
                      <>
                        <QrCode size={36} className="opacity-40" />
                        <p className="text-sm italic text-center px-8">Escaneie o QR na aba Sessões para conectar</p>
                        <button onClick={() => setActiveTab('sessions')}
                          className="text-[#00a884] text-sm font-semibold hover:underline">
                          Ver sessões
                        </button>
                      </>
                    ) : (
                      <>
                        <WifiOff size={36} className="opacity-40" />
                        <p className="text-sm italic">Sessão desconectada</p>
                      </>
                    )}
                  </div>
                ) : loadingChats ? (
                  Array.from({ length: 8 }).map((_, i) => (
                    <div key={i} className="flex items-center gap-3 px-3 py-[10px] border-b border-[#f0f2f5] animate-pulse">
                      <div className="w-[49px] h-[49px] rounded-full bg-[#f0f2f5] flex-shrink-0" />
                      <div className="flex-1 space-y-2">
                        <div className="h-[14px] bg-[#f0f2f5] rounded w-3/4" />
                        <div className="h-[12px] bg-[#f0f2f5] rounded w-1/2" />
                      </div>
                    </div>
                  ))
                ) : filteredChats.length === 0 ? (
                  <p className="text-[#667781] text-sm italic text-center py-16 px-6">
                    {searchChat ? 'Nenhuma conversa encontrada.' : 'Nenhuma conversa ainda.'}
                  </p>
                ) : (
                  filteredChats.map(chat => (
                    <ChatListItem
                      key={chat.id}
                      chat={chat}
                      isActive={selectedChat?.id === chat.id}
                      onSelect={() => {
                        setSelectedChat(chat);
                        if (chat.unreadCount > 0) {
                          NwService.markRead(chat.id).catch(() => {});
                          setChats(prev => prev.map(c => c.id === chat.id ? { ...c, unreadCount: 0 } : c));
                        }
                      }}
                      onPin={(pinned) => {
                        NwService.pin(chat.id, pinned).catch(() => {});
                        setChats(prev => prev.map(c => c.id === chat.id ? { ...c, isPinned: pinned } : c));
                      }}
                      onArchive={(archived) => {
                        NwService.archive(chat.id, archived).catch(() => {});
                        setChats(prev => prev.filter(c => c.id !== chat.id));
                        if (selectedChat?.id === chat.id) setSelectedChat(null);
                      }}
                      onMarkRead={() => {
                        NwService.markRead(chat.id).catch(() => {});
                        setChats(prev => prev.map(c => c.id === chat.id ? { ...c, unreadCount: 0 } : c));
                      }}
                      onDelete={() => {
                        NwService.deleteChat(chat.id).catch(() => {});
                        setChats(prev => prev.filter(c => c.id !== chat.id));
                        if (selectedChat?.id === chat.id) setSelectedChat(null);
                      }}
                    />
                  ))
                )}
              </div>
            </>
          )}

          {/* ───── Tab: Secretária ────────────────────────────────────────── */}
          {activeTab === 'secretaria' && <SecretariaTab />}

          {/* ───── Tab: Equipe ────────────────────────────────────────────── */}
          {activeTab === 'equipe' && (
            // flex flex-col é obrigatório: sem ele, h-full dentro do EquipeTab
            // não resolve a altura calculada pelo flexbox do painel esquerdo.
            <div className="flex-1 min-h-0 overflow-hidden bg-slate-900 flex flex-col">
              <EquipeTab />
            </div>
          )}

          {/* ───── Tab: Inbox Interna ─────────────────────────────────────── */}
          {activeTab === 'inbox-interna' && (
            <div className="flex-1 min-h-0 overflow-hidden bg-slate-900 flex flex-col">
              {/* inboxAccountId resolve: teamAccount.id > linkedAccount.id > undefined */}
              <InboxInternaTab
                accountId={inboxAccountId}
                role={teamAccount?.role ?? adminLinkedAccount?.role ?? 'agent'}
              />
            </div>
          )}

          {/* ───── Tab: Métricas ──────────────────────────────────────────── */}
          {activeTab === 'metricas' && (
            <div className="flex-1 min-h-0 overflow-hidden flex flex-col">
              <MetricasTab />
            </div>
          )}

        </div>
      )}

      {/* ── Área principal ─────────────────────────────────────────────────── */}
      {showRight && (
        <div className="flex-1 flex h-full min-w-0 overflow-hidden relative">

          {selectedChat ? (
            <div className="flex-1 flex flex-col h-full overflow-hidden">
              {/* Chat header */}
              <ChatHeader
                chat={selectedChat}
                isMobile={isMobile}
                onBack={() => setSelectedChat(null)}
                onArchive={handleArchive}
              />

              {/* Message area */}
              <div
                ref={msgAreaRef}
                className="flex-1 overflow-y-auto pt-3 pb-2"
                style={{ backgroundColor: '#efeae2' }}
              >
                {loadingMessages ? (
                  <div className="flex items-center justify-center h-full">
                    <div className="w-7 h-7 border-[3px] border-[#00a884] border-t-transparent rounded-full animate-spin" />
                  </div>
                ) : messages.length === 0 ? (
                  <p className="text-[#667781] text-sm italic text-center py-16">Nenhuma mensagem.</p>
                ) : (
                  <>
                    {/* Sentinela no topo — dispara loadMore via IntersectionObserver */}
                    <div ref={msgTopRef} className="h-px" />
                    {loadingMore && (
                      <div className="flex justify-center py-2">
                        <div className="w-5 h-5 border-2 border-[#00a884] border-t-transparent rounded-full animate-spin" />
                      </div>
                    )}
                    {messagesWithMeta.map(({ msg, showTail, showSeparator, separatorLabel, showSender }) => (
                      <div key={msg.id}>
                        {showSeparator && <DateSeparator label={separatorLabel} />}
                        <MessageBubble
                          msg={msg}
                          showTail={showTail}
                          showSender={showSender}
                          senderName={msg.pushName ?? msg.senderJid?.split('@')[0] ?? undefined}
                        />
                      </div>
                    ))}
                  </>
                )}
                <div ref={msgEndRef} />
              </div>

              {/* Handoff button — flutua acima do input bar */}
              <HandoffButton chat={selectedChat} autoReplyGlobal={autoReplyMode} refreshKey={handoffRefreshKey} />

              {/* Input bar */}
              <InputBar
                value={sendText}
                onChange={setSendText}
                onSend={handleSend}
                sending={sending}
                onAskAi={handleAskAi}
                askingAi={askingAi}
                chatId={selectedChat?.id ?? null}
              />
            </div>
          ) : (
            /* Empty state */
            <div
              className="flex-1 flex flex-col items-center justify-center gap-6"
              style={{ backgroundColor: '#f0f2f5' }}
            >
              <div className="flex flex-col items-center gap-4 text-[#41525d]">
                <div className="w-[220px] h-[220px] rounded-full bg-[#dfe5e7]/50 flex items-center justify-center">
                  <MessageSquare size={80} className="opacity-20" />
                </div>
                <div className="text-center">
                  <h1 className="text-[32px] font-light text-[#41525d] mb-3">WhatsApp Inbox</h1>
                  <p className="text-[15px] text-[#667781] max-w-[320px] leading-relaxed">
                    Envie e receba mensagens sem manter o celular conectado. Use o WhatsApp no computador.
                  </p>
                </div>
              </div>
              <div className="flex items-center gap-2 text-[12px] text-[#8696a0]">
                <div className="w-1 h-1 rounded-full bg-[#8696a0]" />
                Suas mensagens pessoais são protegidas com a criptografia de ponta a ponta
                <div className="w-1 h-1 rounded-full bg-[#8696a0]" />
              </div>
            </div>
          )}
        </div>
      )}

    </div>

    {/* ── Modals ───────────────────────────────────────────────────────────── */}
    {addModalOpen && (
      <AddNumberModal
        onClose={() => setAddModalOpen(false)}
        onCreated={async () => { await fetchSessions(); await fetchNumbers(); }}
      />
    )}
    {editTarget && (
      <UpdateSessionModal
        num={editTarget.num}
        session={editTarget.session}
        onClose={() => setEditTarget(null)}
        onSaved={async () => { await fetchNumbers(); }}
      />
    )}
    {newConvOpen && selectedSession && (
      <NewConversationModal
        sessionId={selectedSession.id}
        onClose={() => setNewConvOpen(false)}
        onSent={() => {
          setNewConvOpen(false);
          if (selectedSession) {
            NwService.getInbox(selectedSession.id, undefined, 60).then(setChats).catch(() => {});
          }
        }}
      />
    )}
    </>
  );
}
