/* COMERCIAL · CLIENTES — conversas Digi↔cliente no WhatsApp.
   3 colunas: lista · thread · contexto (colapsável).
   O comercial observa, pode Assumir, Sugerir à Digi ou Resolver. */

// ============ mock data ============
const CLIENTES_CONVOS = [
  {
    id: 'grafica-norte',
    name: 'João Afonso',
    company: 'Gráfica Norte Lda',
    avatar: 'JA',
    avatarBg: 'oklch(0.58 0.14 28)',
    state: 'urgente', // activa · espera · urgente · resolvida
    lastSnippet: 'Então se calhar marcamos para amanhã de manhã...',
    lastTime: 'há 3 min',
    unread: 2,
    mine: true,
    digiTyping: false,
    messages: [
      { id: 1, from: 'client', text: 'Olá, recebi a proposta mas tenho dúvidas sobre o plano PrintPlan', time: '09:42' },
      { id: 2, from: 'digi', text: 'Bom dia João. Claro — o PrintPlan é uma modalidade onde a Digidelta entrega o equipamento sem custo inicial e cobra um valor fixo por m² impresso. Para o vosso volume (~820 m²/mês) fica em 1,74 €/m².', time: '09:42' },
      { id: 3, from: 'digi', text: 'Posso enviar-vos a simulação completa em PDF?', time: '09:42' },
      { id: 4, from: 'client', text: 'Sim por favor', time: '09:43' },
      { id: 5, from: 'digi', text: '📄 Proposta-UCJV330-GraficaNorte.pdf\n2,1 MB · PrintPlan Care · 60 meses', time: '09:43', attachment: true },
      { id: 6, from: 'client', text: 'Obrigado. Mas tenho uma questão: se quisermos cancelar ao fim de 2 anos, há penalização?', time: '10:14' },
      { id: 7, from: 'digi', text: 'Há sim — no PrintPlan Care existe uma fidelização de 36 meses. Se terminarem antes, há lugar ao pagamento de 40% das mensalidades remanescentes.\n\nSe a preocupação for a duração, posso simular-vos o PrintPlan flexível (24m) — sai 1,92 €/m². Queres que envie?', time: '10:14' },
      { id: 8, from: 'client', text: 'Ok. E o Daniel pode cá vir amanhã explicar melhor?', time: '10:32' },
      { id: 9, from: 'digi', text: 'Com certeza. Ele tem disponibilidade amanhã às 10h30 ou às 14h00. Qual prefere?', time: '10:32' },
      { id: 10, from: 'client', text: 'Então se calhar marcamos para amanhã de manhã, 10h30', time: '10:47' },
    ],
    context: {
      ltv: '487.2k €', lastBuy: '67 dias', openOp: '1 · stage 80',
      health: 'risco', tickets: 0, brands: ['Mimaki', 'Decal', 'PPE100'],
    },
  },
  {
    id: 'signpro',
    name: 'Maria Almeida',
    company: 'SignPro',
    avatar: 'MA',
    avatarBg: 'oklch(0.56 0.16 256)',
    state: 'activa',
    lastSnippet: 'Digi: Envio a ficha do PPE100 agora?',
    lastTime: 'há 8 min',
    unread: 0,
    mine: true,
    digiTyping: true,
  },
  {
    id: 'visualmax',
    name: 'Pedro Costa',
    company: 'Visualmax Publicidade',
    avatar: 'PC',
    avatarBg: 'oklch(0.58 0.14 152)',
    state: 'activa',
    lastSnippet: 'Cliente: quanto custa a versão 160cm?',
    lastTime: 'há 22 min',
    unread: 1,
    mine: true,
  },
  {
    id: 'multiprint',
    name: 'Ana Rocha',
    company: 'Multiprint Lda',
    avatar: 'AR',
    avatarBg: 'oklch(0.58 0.11 60)',
    state: 'espera',
    lastSnippet: 'Digi: pode pagar até 15 de maio?',
    lastTime: 'há 1h',
    unread: 0,
    mine: true,
  },
  {
    id: 'grupo-siena',
    name: 'Ricardo Dias',
    company: 'Grupo Siena',
    avatar: 'RD',
    avatarBg: 'oklch(0.56 0.14 300)',
    state: 'activa',
    lastSnippet: 'Digi: agendei briefing para 6 maio 14h',
    lastTime: 'há 2h',
    unread: 0,
    mine: false,
  },
  {
    id: 'olimpo',
    name: 'Rui Barros',
    company: 'Olimpo Lda',
    avatar: 'RB',
    avatarBg: 'oklch(0.58 0.14 20)',
    state: 'resolvida',
    lastSnippet: '✓ Ticket SAT #2147 resolvido',
    lastTime: 'ontem',
    unread: 0,
    mine: false,
  },
];

const CLIENTE_FILTERS = [
  { id: 'todas', label: 'Todas', count: 6 },
  { id: 'activas', label: 'Activas', count: 3 },
  { id: 'urgentes', label: 'Urgentes', count: 1, highlight: 'var(--danger)' },
  { id: 'minhas', label: 'Minhas', count: 4 },
  { id: 'equipa', label: 'Equipa', count: 2 },
];

const stateMeta = {
  activa:    { color: 'var(--success)', label: '🟢 Activa' },
  espera:    { color: 'var(--warning)', label: '🟡 Espera' },
  urgente:   { color: 'var(--danger)',  label: '🔴 Urgente' },
  resolvida: { color: 'var(--text-dim)', label: '✓ Resolvida' },
};

// ============ column 1 — lista ============
const ConvoListItem = ({ c, active, onClick }) => {
  const st = stateMeta[c.state];
  return (
    <button onClick={onClick} style={{
      width: '100%', display: 'flex', gap: 10,
      padding: '11px 14px',
      background: active ? 'var(--bg-elev)' : 'transparent',
      borderLeft: `2px solid ${active ? 'var(--ai-500)' : 'transparent'}`,
      borderBottom: '1px solid var(--border)',
      textAlign: 'left', transition: 'background 0.12s',
      position: 'relative',
    }}
      onMouseEnter={e => { if (!active) e.currentTarget.style.background = 'var(--bg-hover)'; }}
      onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'transparent'; }}
    >
      <div style={{ position: 'relative', flexShrink: 0 }}>
        <div style={{
          width: 38, height: 38, borderRadius: 19,
          background: c.avatarBg, color: '#fff',
          display: 'grid', placeItems: 'center',
          fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 13,
        }}>{c.avatar}</div>
        <span style={{
          position: 'absolute', bottom: -1, right: -1,
          width: 11, height: 11, borderRadius: '50%',
          background: st.color,
          border: '2px solid var(--bg-sunken)',
        }} />
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
          <div style={{ fontSize: 13, fontWeight: 600, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.name}</div>
          <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', flexShrink: 0 }}>{c.lastTime}</div>
        </div>
        <div style={{ fontSize: 11, color: 'var(--text-muted)', fontWeight: 500, marginTop: 1, marginBottom: 2 }}>{c.company}</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <div style={{
            fontSize: 11.5, color: c.digiTyping ? 'var(--ai-500)' : 'var(--text-muted)',
            fontStyle: c.digiTyping ? 'italic' : 'normal',
            flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            lineHeight: 1.3,
          }}>
            {c.digiTyping ? 'Digi a escrever…' : c.lastSnippet}
          </div>
          {c.unread > 0 && (
            <span style={{
              padding: '0 6px', minWidth: 18, height: 16,
              borderRadius: 8, background: 'var(--ai-500)', color: '#fff',
              fontSize: 10, fontWeight: 700, fontFamily: 'var(--font-display)',
              display: 'inline-grid', placeItems: 'center',
            }}>{c.unread}</span>
          )}
        </div>
      </div>
    </button>
  );
};

const ConvoList = ({ active, onSelect }) => {
  const [filter, setFilter] = React.useState('todas');
  const [search, setSearch] = React.useState('');
  const filtered = CLIENTES_CONVOS.filter(c => {
    if (search && !(c.name.toLowerCase() + ' ' + c.company.toLowerCase()).includes(search.toLowerCase())) return false;
    if (filter === 'activas') return c.state === 'activa';
    if (filter === 'urgentes') return c.state === 'urgente';
    if (filter === 'minhas') return c.mine;
    if (filter === 'equipa') return !c.mine;
    return true;
  });
  return (
    <aside style={{
      width: 340, flexShrink: 0,
      background: 'var(--bg-sunken)',
      borderRight: '1px solid var(--border)',
      display: 'flex', flexDirection: 'column', minHeight: 0,
    }}>
      <div style={{ padding: '14px 14px 10px', borderBottom: '1px solid var(--border)' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
          <div className="font-display" style={{ fontWeight: 700, fontSize: 14, letterSpacing: '0.04em' }}>Clientes em conversa</div>
          <span style={{ flex: 1 }} />
          <span className="font-mono" style={{ fontSize: 10, color: 'var(--text-dim)', padding: '2px 6px', background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 4 }}>{CLIENTES_CONVOS.length}</span>
        </div>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 8,
          padding: '6px 10px', background: 'var(--bg-elev)',
          border: '1px solid var(--border)', borderRadius: 8,
        }}>
          <Icon name="search" size={12} style={{ color: 'var(--text-dim)' }} />
          <input
            value={search} onChange={e => setSearch(e.target.value)}
            placeholder="Procurar cliente…"
            style={{ flex: 1, border: 'none', outline: 'none', background: 'transparent', color: 'var(--text)', fontSize: 12 }}
          />
        </div>
      </div>
      <div style={{
        padding: '8px 8px', borderBottom: '1px solid var(--border)',
        display: 'flex', gap: 4, overflowX: 'auto',
      }}>
        {CLIENTE_FILTERS.map(f => (
          <button key={f.id} onClick={() => setFilter(f.id)} style={{
            display: 'inline-flex', alignItems: 'center', gap: 5,
            padding: '4px 9px', borderRadius: 999,
            fontSize: 11, fontWeight: 500, flexShrink: 0,
            background: filter === f.id ? 'var(--bg-elev)' : 'transparent',
            color: filter === f.id ? 'var(--text)' : 'var(--text-muted)',
            border: `1px solid ${filter === f.id ? 'var(--border)' : 'transparent'}`,
          }}>
            {f.label}
            <span style={{
              fontSize: 10, padding: '0 5px', borderRadius: 8,
              background: f.highlight ? `color-mix(in oklch, ${f.highlight} 18%, transparent)` : 'var(--bg-sunken)',
              color: f.highlight || 'var(--text-dim)',
              fontFamily: 'var(--font-mono)', fontWeight: 600,
            }}>{f.count}</span>
          </button>
        ))}
      </div>
      <div style={{ flex: 1, overflowY: 'auto' }} className="scrollbar">
        {filtered.map(c => (
          <ConvoListItem key={c.id} c={c} active={c.id === active} onClick={() => onSelect(c.id)} />
        ))}
        {filtered.length === 0 && (
          <div style={{ padding: 30, textAlign: 'center', fontSize: 12, color: 'var(--text-muted)' }}>
            Nenhuma conversa nesse filtro.
          </div>
        )}
      </div>
    </aside>
  );
};

// ============ column 2 — thread ============
const ThreadHeader = ({ convo, onToggleContext, contextOpen, onAssume, onSuggest, onResolve, assumed }) => {
  const st = stateMeta[convo.state];
  return (
    <div style={{
      borderBottom: '1px solid var(--border)', background: 'var(--bg-elev)',
      padding: '10px 16px', display: 'flex', alignItems: 'center', gap: 12,
      flexShrink: 0, minHeight: 56,
    }}>
      <div style={{
        width: 36, height: 36, borderRadius: 18,
        background: convo.avatarBg, color: '#fff',
        display: 'grid', placeItems: 'center',
        fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 13,
      }}>{convo.avatar}</div>
      <div style={{ flex: 1, minWidth: 0, lineHeight: 1.25 }}>
        <div style={{ fontWeight: 600, fontSize: 14 }}>{convo.name} <span style={{ color: 'var(--text-muted)', fontWeight: 400 }}>· {convo.company}</span></div>
        <div style={{ fontSize: 11, color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 6 }}>
          <Icon name="sparkle" size={10} style={{ color: 'var(--ai-500)' }} />
          {assumed
            ? <span style={{ color: 'var(--warning)' }}>Tu estás a responder · Digi pausada</span>
            : convo.digiTyping
              ? <span style={{ color: 'var(--ai-500)' }}>Digi a escrever resposta…</span>
              : <span>Digi a conduzir · {st.label}</span>
          }
        </div>
      </div>
      <div style={{ display: 'flex', gap: 6 }}>
        <button onClick={onAssume} className="btn btn-sm" style={{
          background: assumed ? 'var(--warning)' : 'var(--surface-muted)',
          color: assumed ? '#fff' : 'var(--text)',
          borderColor: assumed ? 'transparent' : 'var(--border)',
          fontSize: 11.5,
        }}>
          <Icon name="user" size={12} />
          {assumed ? 'A responder' : 'Assumir'}
        </button>
        <button onClick={onSuggest} className="btn btn-sm" style={{ fontSize: 11.5 }}>
          <Icon name="sparkle" size={12} style={{ color: 'var(--ai-500)' }} />
          Sugerir à Digi
        </button>
        <button onClick={onResolve} className="btn btn-sm" style={{ fontSize: 11.5 }}>
          <Icon name="check" size={12} />
          Resolver
        </button>
        <div style={{ width: 1, background: 'var(--border)', margin: '0 2px' }} />
        <button onClick={onToggleContext} className="btn btn-sm btn-ghost" title="Ver contexto" style={{
          background: contextOpen ? 'var(--bg-hover)' : 'transparent',
        }}>
          <Icon name="info" size={12} />
        </button>
      </div>
    </div>
  );
};

const WAMessage = ({ m, showAvatar, avatar, avatarBg }) => {
  const isClient = m.from === 'client';
  const isDigi = m.from === 'digi';
  const isUser = m.from === 'user';
  const isLight = document.documentElement.dataset.theme !== 'dark';
  const side = isClient ? 'right' : 'left';
  const bubbleBg = isClient ? 'var(--wa-client)' : (isUser ? 'var(--warning)' : 'var(--bg-elev)');
  const bubbleColor = isClient ? (isLight ? 'var(--text)' : '#fff') : (isUser ? '#fff' : 'var(--text)');
  return (
    <div style={{
      display: 'flex', gap: 8,
      flexDirection: side === 'right' ? 'row-reverse' : 'row',
      marginBottom: 4, alignItems: 'flex-end',
    }}>
      {/* avatar pocket - 24px reserved always for alignment stability */}
      <div style={{ width: 24, flexShrink: 0 }}>
        {showAvatar && isDigi && (
          <div style={{
            width: 24, height: 24, borderRadius: 12,
            background: 'linear-gradient(135deg, var(--ai-500), var(--ai-700))',
            display: 'grid', placeItems: 'center',
          }}>
            <Icon name="sparkle" size={12} style={{ color: '#fff' }} />
          </div>
        )}
        {showAvatar && isClient && (
          <div style={{
            width: 24, height: 24, borderRadius: 12, background: avatarBg,
            color: '#fff', display: 'grid', placeItems: 'center',
            fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 10,
          }}>{avatar}</div>
        )}
        {showAvatar && isUser && (
          <div style={{
            width: 24, height: 24, borderRadius: 12, background: 'var(--brand-900)',
            color: '#fff', display: 'grid', placeItems: 'center',
            fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 10,
          }}>DM</div>
        )}
      </div>
      <div style={{
        maxWidth: '72%',
        padding: m.attachment ? '10px 12px' : '7px 11px',
        background: bubbleBg, color: bubbleColor,
        borderRadius: 10,
        borderBottomLeftRadius: side === 'left' ? 3 : 10,
        borderBottomRightRadius: side === 'right' ? 3 : 10,
        fontSize: 13.5, lineHeight: 1.45,
        boxShadow: '0 1px 1px rgba(0,0,0,0.08)',
        border: (isDigi) ? '1px solid var(--border)' : 'none',
        whiteSpace: 'pre-wrap', wordBreak: 'break-word',
        position: 'relative',
      }}>
        {m.text}
        <div style={{
          fontSize: 9.5, opacity: 0.7, marginTop: 3,
          textAlign: 'right', fontFamily: 'var(--font-mono)',
          display: 'flex', alignItems: 'center', gap: 3, justifyContent: 'flex-end',
        }}>
          {m.time} {isClient && <span style={{ color: '#53bdeb' }}>✓✓</span>}
        </div>
      </div>
    </div>
  );
};

const TypingBubble = () => (
  <div style={{ display: 'flex', gap: 8, marginBottom: 4, alignItems: 'flex-end' }}>
    <div style={{ width: 24 }} />
    <div style={{
      padding: '10px 14px', background: 'var(--bg-elev)',
      border: '1px solid var(--border)', borderRadius: 10, borderBottomLeftRadius: 3,
      display: 'flex', gap: 4,
    }}>
      {[0,1,2].map(i => (
        <span key={i} style={{
          width: 6, height: 6, borderRadius: 3, background: 'var(--text-dim)',
          animation: `digi-typing 1.4s ease-in-out ${i * 0.16}s infinite`,
        }} />
      ))}
    </div>
  </div>
);

const ThreadComposer = ({ active, onSend, assumed, onOpenSuggest }) => {
  const [text, setText] = React.useState('');
  if (!active) {
    return (
      <div style={{
        borderTop: '1px solid var(--border)', background: 'var(--bg-sunken)',
        padding: '14px 16px', fontSize: 12, color: 'var(--text-muted)',
        display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <Icon name="sparkle" size={14} style={{ color: 'var(--ai-500)' }} />
        <span style={{ flex: 1 }}>A Digi está a conduzir esta conversa. Assume para responder directamente, ou sugere uma abordagem à Digi.</span>
        <button onClick={onOpenSuggest} className="btn btn-xs">Sugerir</button>
      </div>
    );
  }
  return (
    <div style={{ borderTop: '1px solid var(--border)', background: 'var(--bg-elev)', padding: '10px 12px' }}>
      {assumed && (
        <div style={{ marginBottom: 8, padding: '6px 10px', background: 'color-mix(in oklch, var(--warning) 12%, transparent)', border: '1px solid color-mix(in oklch, var(--warning) 32%, var(--border))', borderRadius: 6, fontSize: 11, color: 'var(--warning)' }}>
          Tu estás a responder · mensagens vão directas ao WhatsApp do cliente
        </div>
      )}
      <div style={{
        display: 'flex', alignItems: 'flex-end', gap: 8,
        padding: '8px 10px', background: 'var(--bg-sunken)',
        border: '1px solid var(--border)', borderRadius: 22,
      }}>
        <button className="btn btn-sm btn-ghost" style={{ padding: 6 }}><Icon name="plus" size={16} /></button>
        <textarea
          value={text} onChange={e => setText(e.target.value)}
          onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); if (text.trim()) { onSend(text.trim()); setText(''); } } }}
          rows={1} placeholder="Escreve uma mensagem ao cliente…"
          style={{ flex: 1, resize: 'none', border: 'none', outline: 'none', background: 'transparent', color: 'var(--text)', fontSize: 13.5, lineHeight: 1.4, padding: '4px 2px', fontFamily: 'inherit' }}
        />
        <button onClick={() => { if (text.trim()) { onSend(text.trim()); setText(''); } }} disabled={!text.trim()} style={{
          width: 32, height: 32, borderRadius: 16,
          background: text.trim() ? 'var(--ai-500)' : 'var(--surface-muted)',
          color: text.trim() ? '#fff' : 'var(--text-dim)',
          display: 'grid', placeItems: 'center', border: 'none',
        }}>
          <Icon name="send" size={13} />
        </button>
      </div>
    </div>
  );
};

const SuggestModal = ({ open, onClose, onSubmit }) => {
  const [text, setText] = React.useState('');
  if (!open) return null;
  return (
    <div style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.4)',
      display: 'grid', placeItems: 'center', zIndex: 100,
    }} onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{
        width: 480, maxWidth: 'calc(100vw - 40px)',
        background: 'var(--bg-elev)', border: '1px solid var(--border)',
        borderRadius: 12, padding: 20,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
          <Icon name="sparkle" size={14} style={{ color: 'var(--ai-500)' }} />
          <div className="font-display" style={{ fontWeight: 700, fontSize: 14 }}>Sugerir à Digi</div>
        </div>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', marginBottom: 12, lineHeight: 1.5 }}>
          Diz à Digi o que estás a pensar. Ela ajusta o tom, a abordagem ou traz contexto adicional. <strong style={{ color: 'var(--text)' }}>Não vai ao cliente.</strong>
        </div>
        <textarea
          value={text} onChange={e => setText(e.target.value)}
          placeholder="Ex: Este cliente já teve problemas de pagamento. Sê mais firme com prazos e pede confirmação por escrito."
          rows={5}
          style={{
            width: '100%', resize: 'vertical',
            padding: 10, background: 'var(--bg-sunken)',
            border: '1px solid var(--border)', borderRadius: 8,
            color: 'var(--text)', fontSize: 13, lineHeight: 1.5,
            fontFamily: 'inherit', outline: 'none',
          }}
        />
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 12 }}>
          <button onClick={onClose} className="btn btn-sm">Cancelar</button>
          <button onClick={() => { if (text.trim()) { onSubmit(text.trim()); setText(''); } }} disabled={!text.trim()} className="btn btn-sm" style={{ background: 'var(--ai-500)', color: '#fff', borderColor: 'transparent' }}>
            Enviar à Digi
          </button>
        </div>
      </div>
    </div>
  );
};

const ThreadView = ({ convo, contextOpen, onToggleContext, onGoToCarteira }) => {
  const [assumed, setAssumed] = React.useState(false);
  const [messages, setMessages] = React.useState(convo.messages || []);
  const [suggestOpen, setSuggestOpen] = React.useState(false);
  const [toast, setToast] = React.useState(null);
  const scrollRef = React.useRef(null);

  React.useEffect(() => {
    setMessages(convo.messages || []);
    setAssumed(false);
  }, [convo.id]);

  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages, convo.id]);

  const showToast = (text) => {
    setToast(text);
    setTimeout(() => setToast(null), 2500);
  };

  const sendMessage = (text) => {
    const t = timeNow ? timeNow() : new Date().toTimeString().slice(0,5);
    setMessages(prev => [...prev, { id: Date.now(), from: 'user', text, time: t }]);
  };

  return (
    <div style={{ flex: 1, minWidth: 0, minHeight: 0, display: 'flex', flexDirection: 'column', background: 'var(--wa-bg)' }}>
      <ThreadHeader
        convo={convo}
        contextOpen={contextOpen}
        onToggleContext={onToggleContext}
        onAssume={() => { setAssumed(v => !v); showToast(assumed ? 'Digi retomou a conversa' : 'Assumiste a conversa · Digi pausada'); }}
        onSuggest={() => setSuggestOpen(true)}
        onResolve={() => showToast('Conversa marcada como resolvida')}
        assumed={assumed}
      />
      <div ref={scrollRef} style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '14px 18px' }} className="scrollbar">
        {messages.length === 0 ? (
          <div style={{ textAlign: 'center', padding: 40, color: 'var(--text-muted)', fontSize: 12 }}>
            Selecciona uma conversa para a ler
          </div>
        ) : (
          messages.map((m, i) => {
            const prev = messages[i - 1];
            const showAvatar = !prev || prev.from !== m.from;
            return <WAMessage key={m.id} m={m} showAvatar={showAvatar} avatar={convo.avatar} avatarBg={convo.avatarBg} />;
          })
        )}
        {convo.digiTyping && <TypingBubble />}
      </div>
      <ThreadComposer active={assumed} assumed={assumed} onSend={sendMessage} onOpenSuggest={() => setSuggestOpen(true)} />
      <SuggestModal
        open={suggestOpen}
        onClose={() => setSuggestOpen(false)}
        onSubmit={(t) => { setSuggestOpen(false); showToast('Sugestão enviada · Digi a reformular abordagem'); }}
      />
      {toast && (
        <div style={{
          position: 'absolute', bottom: 80, left: '50%', transform: 'translateX(-50%)',
          padding: '8px 14px', background: 'var(--text)', color: 'var(--bg)',
          borderRadius: 20, fontSize: 12, boxShadow: 'var(--shadow-md)',
          animation: 'digi-toast 0.24s ease-out', zIndex: 10,
        }}>{toast}</div>
      )}
    </div>
  );
};

// ============ column 3 — context ============
const ClientContext = ({ convo, open, onClose, onGoToCarteira }) => {
  if (!open) return null;
  const ctx = convo.context;
  return (
    <aside style={{
      width: 300, flexShrink: 0,
      borderLeft: '1px solid var(--border)',
      background: 'var(--bg-sunken)',
      display: 'flex', flexDirection: 'column', minHeight: 0,
    }}>
      <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 8 }}>
        <div style={{ flex: 1, fontSize: 12, fontWeight: 600, letterSpacing: '0.04em' }}>Contexto do cliente</div>
        <button onClick={onClose} className="btn btn-xs btn-ghost" style={{ padding: 4 }}>
          <Icon name="close" size={12} />
        </button>
      </div>
      <div style={{ padding: 16, overflowY: 'auto', flex: 1 }} className="scrollbar">
        {ctx ? (
          <>
            <div style={{ padding: 14, background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 10, marginBottom: 12 }}>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 2 }}>{convo.company}</div>
              <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 10 }}>{convo.name}</div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
                <div>
                  <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em' }}>LTV</div>
                  <div className="font-display" style={{ fontSize: 15, fontWeight: 700 }}>{ctx.ltv}</div>
                </div>
                <div>
                  <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em' }}>ÚLT. COMPRA</div>
                  <div className="font-display" style={{ fontSize: 13.5, fontWeight: 600 }}>{ctx.lastBuy}</div>
                </div>
                <div>
                  <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em' }}>OP ACTIVA</div>
                  <div className="font-display" style={{ fontSize: 13, fontWeight: 600, color: 'var(--warning)' }}>{ctx.openOp}</div>
                </div>
                <div>
                  <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em' }}>TICKETS</div>
                  <div className="font-display" style={{ fontSize: 13, fontWeight: 600, color: ctx.tickets ? 'var(--danger)' : 'var(--success)' }}>{ctx.tickets} abertos</div>
                </div>
              </div>
              <div style={{ marginTop: 12, padding: '8px 10px', background: `color-mix(in oklch, ${stateMeta[convo.state].color} 10%, transparent)`, border: `1px solid color-mix(in oklch, ${stateMeta[convo.state].color} 30%, var(--border))`, borderRadius: 6, fontSize: 11, fontWeight: 600, color: stateMeta[convo.state].color }}>
                {ctx.health === 'risco' && '🔴 Saúde em risco · 67d sem compra'}
                {ctx.health === 'saudavel' && '🟢 Saúde normal'}
                {ctx.health === 'recompra' && '⚡ Pronto para recompra'}
              </div>
            </div>
            <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em', marginBottom: 6 }}>MARCAS QUE COMPRA</div>
            <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap', marginBottom: 14 }}>
              {ctx.brands.map(b => (
                <span key={b} style={{ padding: '3px 9px', fontSize: 11, background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 999 }}>{b}</span>
              ))}
            </div>
            <div style={{ fontSize: 10, color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', letterSpacing: '0.06em', marginBottom: 6 }}>O QUE A DIGI ESTÁ A VER</div>
            <div style={{ padding: 10, background: 'var(--bg-elev)', border: '1px solid var(--border)', borderRadius: 8, fontSize: 11.5, color: 'var(--text-muted)', lineHeight: 1.55, marginBottom: 14 }}>
              Cliente está em negociação activa sobre PrintPlan. Perguntou sobre penalização — sinal de dúvida, não de preço. Propôs visita presencial.
            </div>
            <button onClick={onGoToCarteira} className="btn btn-sm" style={{ width: '100%', justifyContent: 'center' }}>
              <Icon name="external" size={12} />
              Abrir ficha na Carteira
            </button>
          </>
        ) : (
          <div style={{ fontSize: 12, color: 'var(--text-muted)', padding: '20px 0', lineHeight: 1.6 }}>
            Sem contexto estruturado para esta conversa. A Digi vai buscar dados ao Primavera em tempo real quando responde.
          </div>
        )}
      </div>
    </aside>
  );
};

// ============ main ============
const ComercialClientesScreen = ({ onNavigateSub }) => {
  const [activeId, setActiveId] = React.useState('grafica-norte');
  const [contextOpen, setContextOpen] = React.useState(true);
  const active = CLIENTES_CONVOS.find(c => c.id === activeId) || CLIENTES_CONVOS[0];

  return (
    <div style={{ display: 'flex', height: '100%', minHeight: 0, background: 'var(--bg)', position: 'relative' }}>
      <ConvoList active={activeId} onSelect={setActiveId} />
      <ThreadView convo={active} contextOpen={contextOpen} onToggleContext={() => setContextOpen(v => !v)} onGoToCarteira={() => onNavigateSub && onNavigateSub('carteira')} />
      <ClientContext convo={active} open={contextOpen} onClose={() => setContextOpen(false)} onGoToCarteira={() => onNavigateSub && onNavigateSub('carteira')} />
      <style>{`
        :root {
          --wa-bg: oklch(0.18 0.01 260);
          --wa-client: #056162;
        }
        :root[data-theme="light"] {
          --wa-bg: #efeae2;
          --wa-client: #d9fdd3;
        }
        :root[data-theme="light"] .wa-client-bubble { color: var(--text) !important; }
        @keyframes digi-toast {
          from { opacity: 0; transform: translate(-50%, 8px); }
          to { opacity: 1; transform: translate(-50%, 0); }
        }
      `}</style>
    </div>
  );
};

// Fix client bubble color in light mode (WA uses dark text on light green)
window.ComercialClientesScreen = ComercialClientesScreen;
