﻿// KPI Cards + Kanban + AI Panel + Clients Table

const KANBAN_PAGE_SIZE = 100;

// ── KPI computation from live leads data ──────────────────────────────────────
function computeKPIs(leads) {
  const now = Date.now();
  const DAY = 86400000;
  const msAgo = d => now - d * DAY;
  const ts = l => l.created_at ? new Date(l.created_at).getTime() : 0;

  // 14-point sparkline: daily new-lead counts, index 0 = 13 days ago
  function spark(filterFn) {
    const counts = Array(14).fill(0);
    leads.filter(filterFn).forEach(l => {
      const d = Math.floor((now - ts(l)) / DAY);
      if (d >= 0 && d < 14) counts[13 - d]++;
    });
    return counts;
  }

  // % change last 7d vs previous 7d (based on creation date)
  function delta(filterFn) {
    const recent = leads.filter(l => filterFn(l) && ts(l) >= msAgo(7)).length;
    const prev   = leads.filter(l => filterFn(l) && ts(l) >= msAgo(14) && ts(l) < msAgo(7)).length;
    if (prev === 0) return recent > 0 ? 100 : 0;
    return Math.round((recent - prev) / prev * 100);
  }

  const isNew    = l => ts(l) >= msAgo(30);
  const isHot    = l => l.temp === 'hot';
  const isActive = l => !ARCHIVED_COLS.has(l.col) && l.col !== 'fechado';
  const isClosed = l => l.col === 'fechado';

  const newCount    = leads.filter(isNew).length;
  const hotCount    = leads.filter(isHot).length;
  const activeCount = leads.filter(isActive).length;
  const closedCount = leads.filter(isClosed).length;
  const hotToday    = leads.filter(l => isHot(l) && ts(l) >= msAgo(1)).length;
  const needAction  = leads.filter(l => isActive(l) && l.temp === 'hot').length;
  const closedVal   = leads.filter(isClosed).reduce((s, l) => s + (l.value || 0), 0);
  const revStr = closedVal >= 1e6 ? `R$ ${(closedVal/1e6).toFixed(1)}M em vendas`
    : closedVal > 0 ? `R$ ${(closedVal/1e3).toFixed(0)}k em vendas`
    : closedCount > 0 ? `${closedCount} negócio${closedCount !== 1 ? 's' : ''} fechado${closedCount !== 1 ? 's' : ''}`
    : 'Sem negócios fechados ainda';

  return [
    { key:'newLeads', label:'Novos Leads',       value:newCount,    delta:delta(isNew),    sub:'últimos 30 dias',               color:'#7EC8FF', glow:'rgba(31,147,255,0.22)',  spark:spark(isNew)    },
    { key:'hotLeads', label:'Leads Quentes',     value:hotCount,    delta:delta(isHot),    sub:`${hotToday} nas últimas 24h`,   color:'#ff8a7a', glow:'rgba(255,90,78,0.18)',   spark:spark(isHot)    },
    { key:'convs',    label:'Conversas Ativas',  value:activeCount, delta:delta(isActive), sub:`${needAction} aguardando ação`, color:'#7dd3fc', glow:'rgba(0,125,255,0.18)',   spark:spark(isActive) },
    { key:'won',      label:'Negócios Fechados', value:closedCount, delta:delta(isClosed), sub:revStr,                          color:'#86efac', glow:'rgba(52,211,153,0.18)',  spark:spark(isClosed) },
  ];
}

function KPICards() {
  const [cards, setCards] = React.useState(() => computeKPIs(window.LEADS || []));

  React.useEffect(() => {
    const handler = (e) => {
      if (e.detail && window.LEADS && !window.LEADS.find(l => l.id === e.detail.id)) {
        window.LEADS = [e.detail, ...window.LEADS];
      }
      setCards(computeKPIs(window.LEADS || []));
    };
    const onBatch = () => setCards(computeKPIs(window.LEADS || []));
    window.addEventListener('horos:lead-created', handler);
    window.addEventListener('horos:batch-imported', onBatch);
    const onArchived = (e) => { const ids = new Set(e.detail?.ids || []); if (ids.size) { if (Array.isArray(window.LEADS)) window.LEADS = window.LEADS.filter(l => !ids.has(l.id)); setCards(computeKPIs(window.LEADS || [])); } };
    window.addEventListener('horos:lead-archived', onArchived);
    window.addEventListener('horos:leads-refreshed', onBatch);
    return () => {
      window.removeEventListener('horos:lead-created', handler);
      window.removeEventListener('horos:batch-imported', onBatch);
      window.removeEventListener('horos:lead-archived', onArchived);
      window.removeEventListener('horos:leads-refreshed', onBatch);
    };
  }, []);

  return (
    <div className="kpi-grid">
      {cards.map((c, i) => (
        <div key={c.key} className="kpi fade-up"
             style={{ '--kpi-color': c.color, '--kpi-glow': c.glow, animationDelay: `${i * 60}ms` }}>
          <div className="kpi-row">
            <div className="kpi-label">{c.label}</div>
            
          </div>
          <div className="kpi-value">{c.value}</div>
          <div className="kpi-foot">
            <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
              <span className={`delta ${c.delta >= 0 ? 'up' : 'down'}`}>
                <svg className="arr" viewBox="0 0 12 12" fill="none">
                  <path d={c.delta >= 0 ? "m3 7 3-3 3 3" : "m3 5 3 3 3-3"} stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
                {c.delta >= 0 ? '+' : ''}{c.delta}%
              </span>
              <span className="kpi-sub">{c.sub}</span>
            </div>
            <div className="sparkwrap">
              <Sparkline data={c.spark} color={c.color} />
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

const TempBadge = ({ t }) => {
  const map = {
    hot: { cls: 'hot', icon: 'flame', label: 'Quente' },
    warm: { cls: 'warm', icon: 'drop', label: 'Morno' },
    cold: { cls: 'cold', icon: 'snow', label: 'Frio' },
  };
  const m = map[t];
  return <span className={`temp ${m.cls}`} title={m.label}><Icon name={m.icon} size={10} stroke={1.8} /></span>;
};

const tempMap = {
  hot:  { cls: 'hot',  icon: 'flame', label: 'Quente' },
  warm: { cls: 'warm', icon: 'drop',  label: 'Morno'  },
  cold: { cls: 'cold', icon: 'snow',  label: 'Frio'   },
};

const TEMP_COLORS_DB = { hot: '#ff5a4e', warm: '#f5b544', cold: '#59c8ff' };

function daysInStageDash(lead) {
  if (!lead.updated_at) return 0;
  return Math.max(0, Math.floor((Date.now() - new Date(lead.updated_at)) / 86400000));
}

function daysBadgeStyleDash(days) {
  if (days >= 7) return { color: '#ef4444', bg: 'rgba(239,68,68,0.12)', border: 'rgba(239,68,68,0.3)' };
  if (days >= 4) return { color: '#f97316', bg: 'rgba(249,115,22,0.12)', border: 'rgba(249,115,22,0.3)' };
  if (days >= 2) return { color: '#f5b544', bg: 'rgba(245,181,68,0.12)', border: 'rgba(245,181,68,0.3)' };
  return null;
}

function LeadCard({ lead, onCardPointerDown, onClick, onDelete, onEdit, selectMode, selected, onToggleSelect }) {
  const [hovered, setHovered] = React.useState(false);
  const [confirming, setConfirming] = React.useState(false);
  const progress = lead.progress ?? COL_PROGRESS[lead.col] ?? 0;

  const handleDeleteClick = (e) => {
    e.stopPropagation();
    onDelete(lead.id);   // abre a janela do motivo (horosArchiveLeads)
  };

  React.useEffect(() => {
    if (!hovered && confirming) {
      const t = setTimeout(() => setConfirming(false), 1500);
      return () => clearTimeout(t);
    }
  }, [hovered, confirming]);

  return (
    <div
      className={`crm-lead kbx-card${selectMode ? ' kb-selectable' : ''}${selected ? ' kb-selected' : ''}`}
      data-lead-id={lead.id}
      style={{ position: 'relative' }}
      onPointerDown={selectMode ? undefined : (e) => onCardPointerDown(e, lead)}
      onClick={selectMode ? (e) => onToggleSelect(lead.id, e.shiftKey) : () => { if (!kbDragJustEnded()) onClick(); }}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
    >
      {selectMode && (
        <span className={`kb-check${selected ? ' on' : ''}`} aria-hidden="true">
          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg>
        </span>
      )}
      {/* Edit / Delete overlay */}
      {!selectMode && (hovered || confirming) && (
        <div className="kbx-actions">
          <button className="kbx-act" onClick={(e) => { e.stopPropagation(); onEdit(lead); }} title="Editar">
            <Icon name="pencil" size={12} stroke={1.8} />
          </button>
          <button className="kbx-act" onClick={handleDeleteClick} title="Arquivar">
            <Icon name="archive" size={12} stroke={1.8} />
          </button>
        </div>
      )}

      <KbLeadCardBody lead={{ ...lead, progress }} money={fmtCurrency} selectMode={selectMode} />
    </div>
  );
}

function EditLeadModal({ lead, onClose, onSaved }) {
  const [form, setForm] = React.useState({ name: lead.name, phone: lead.phone || '', temp: lead.temp });
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState('');

  const set = (k, v) => setForm(prev => ({ ...prev, [k]: v }));

  const maskPhone = (v) => {
    let d = v.replace(/\D/g, '');
    if (d.length > 11) {
      const take = d.length === 12 ? 10 : 11;
      d = d.slice(d.length - take);
    }
    d = d.slice(0, 11);
    if (d.length <= 2) return d.length ? `(${d}` : '';
    if (d.length <= 6) return `(${d.slice(0,2)}) ${d.slice(2)}`;
    if (d.length <= 10) return `(${d.slice(0,2)}) ${d.slice(2,6)}-${d.slice(6)}`;
    return `(${d.slice(0,2)}) ${d.slice(2,7)}-${d.slice(7)}`;
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!form.name.trim()) { setError('Nome é obrigatório'); return; }
    if (!form.phone.trim()) { setError('Telefone é obrigatório'); return; }
    setSaving(true);
    setError('');
    try {
      const initials = window.initials(form.name) || '?';
      const updates = { name: form.name.trim(), initials, phone: form.phone.trim(), temp: form.temp };
      if (window.HOROS_SB) {
        const { data: r, error: dbErr } = await window.HOROS_SB.rpc('update_lead_basic', { p_id: lead.id, p_name: updates.name, p_phone: updates.phone, p_temp: updates.temp });
        if (dbErr) throw dbErr;
        if (r?.error === 'duplicate') { setError(`Já existe um lead com este telefone: ${r.name}`); setSaving(false); return; }
        if (r?.error) { setError('Você não tem permissão para editar este lead.'); setSaving(false); return; }
      }
      onSaved({ ...lead, ...updates });
      onClose();
    } catch (err) {
      setError('Ocorreu um erro ao salvar. Tente novamente ou fale com o suporte.');
      setSaving(false);
    }
  };

  const F = {
    label: { fontSize:12, fontWeight:600, color:'var(--fg)', display:'block', marginBottom:6 },
    input: { width:'100%', boxSizing:'border-box', background:'var(--bg-1)', border:'1.5px solid var(--line-strong)', borderRadius:8, padding:'9px 12px', fontSize:13, color:'var(--fg)', outline:'none', fontFamily:'inherit', transition:'border-color .15s' },
  };

  const temps = [['hot','Quente','#ff5a4e','flame'],['warm','Morno','#f5b544','sun'],['cold','Frio','#59c8ff','snow']];

  return (
    <div style={{ position:'fixed', inset:0, zIndex:1000, display:'flex', alignItems:'center', justifyContent:'center' }}>
      <div onClick={onClose} style={{ position:'absolute', inset:0, background:'rgba(0,0,0,0.6)', backdropFilter:'blur(6px)' }} />
      <div style={{ position:'relative', background:'var(--card)', border:'1px solid var(--line-strong)', borderRadius:20, width:440, maxWidth:'92vw', boxShadow:'0 24px 60px rgba(0,0,0,0.35)' }}>
        <div style={{ padding:'22px 24px 18px', borderBottom:'1px solid #ebebef' }}>
          <div style={{ display:'flex', alignItems:'center', gap:10 }}>
            <div style={{ width:32, height:32, borderRadius:9, background:'#1F93FF', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
              <Icon name="pencil" size={14} stroke={2} style={{ color:'#fff' }} />
            </div>
            <div>
              <div style={{ fontSize:15, fontWeight:700, color:'var(--fg)', lineHeight:1.2 }}>Editar Lead</div>
              <div style={{ fontSize:11, color:'var(--fg-3)', marginTop:2 }}>{lead.name}</div>
            </div>
            <button onClick={onClose} style={{ marginLeft:'auto', background:'var(--bg-1)', border:'1px solid var(--line-strong)', cursor:'pointer', color:'var(--fg-2)', width:30, height:30, borderRadius:8, display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
              <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="m2 2 10 10M12 2 2 12" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/></svg>
            </button>
          </div>
        </div>
        <form onSubmit={handleSubmit} style={{ padding:'20px 24px 24px', display:'flex', flexDirection:'column', gap:18, background:'var(--card)', borderRadius:'0 0 20px 20px' }}>
          <div>
            <label style={F.label}>Nome completo *</label>
            <input style={F.input} type="text" value={form.name} onChange={e => set('name', e.target.value)} autoFocus />
          </div>
          <div>
            <label style={F.label}>Telefone *</label>
            <input style={F.input} type="tel" placeholder="(11) 99999-9999"
              value={form.phone} onChange={e => set('phone', maskPhone(e.target.value))} />
          </div>
          <div>
            <label style={F.label}>Temperatura</label>
            <div style={{ display:'flex', gap:8 }}>
              {temps.map(([v, label, color]) => (
                <button key={v} type="button" onClick={() => set('temp', v)} style={{
                  flex:1, padding:'10px 8px', borderRadius:10,
                  border:`1.5px solid ${form.temp === v ? color : 'var(--line-strong)'}`,
                  background: form.temp === v ? color + '18' : 'var(--bg-1)',
                  color: form.temp === v ? color : 'var(--fg-2)',
                  fontSize:12, fontWeight:600, cursor:'pointer', transition:'all .15s',
                  display:'flex', flexDirection:'column', alignItems:'center', gap:4,
                }}>
                  <Icon name={v === 'hot' ? 'flame' : v === 'warm' ? 'sun' : 'snow'} size={16} style={{ color: v === 'hot' ? '#ff5a4e' : v === 'warm' ? '#f5b544' : '#59c8ff' }} />
                  {label}
                </button>
              ))}
            </div>
          </div>
          {error && (
            <div style={{ background:'rgba(255,90,78,0.1)', border:'1px solid rgba(255,90,78,0.3)', borderRadius:8, padding:'8px 12px', fontSize:12, color:'#ff5a4e' }}>
              {error}
            </div>
          )}
          <div style={{ display:'flex', gap:8, justifyContent:'space-between', alignItems:'center', paddingTop:4, borderTop:'1px solid #ebebef', marginTop:2 }}>
            <a href={`client.html?id=${lead.id}`} onClick={e => { e.preventDefault(); onClose && onClose(); window.horosOpenLeadSheet(lead.id); }}
              style={{ display:'flex', alignItems:'center', gap:5, padding:'8px 12px', borderRadius:8, background:'var(--bg-1)', border:'1.5px solid var(--line-strong)', fontSize:12, fontWeight:600, color:'#1F93FF', textDecoration:'none', flexShrink:0 }}>
              <Icon name="sheet" size={12} />
              Abrir ficha
            </a>
            <div style={{ display:'flex', gap:8 }}>
              <button type="button" onClick={onClose}
                style={{ background:'var(--bg-1)', border:'1.5px solid var(--line-strong)', borderRadius:8, padding:'8px 16px', fontSize:13, fontWeight:500, color:'var(--fg)', cursor:'pointer' }}>
                Cancelar
              </button>
              <button type="submit" disabled={saving}
                style={{ background: saving ? '#4f52c8' : '#1F93FF', color:'#fff', border:'none', borderRadius:8, padding:'8px 20px', fontSize:13, fontWeight:600, cursor: saving ? 'not-allowed' : 'pointer', display:'flex', alignItems:'center', gap:6 }}>
                {saving ? (
                  <><svg style={{ animation:'spin 1s linear infinite' }} width="13" height="13" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="rgba(255,255,255,0.3)" strokeWidth="3"/><path d="M12 2a10 10 0 0 1 10 10" stroke="#fff" strokeWidth="3" strokeLinecap="round"/></svg>Salvando…</>
                ) : 'Salvar'}
              </button>
            </div>
          </div>
        </form>
      </div>
    </div>
  );
}

function Kanban({ segment }) {
  const [leads, setLeads] = React.useState(() =>
    (window.LEADS || []).map(normalizeLead)
  );
  // Leads atualizados do banco chegando depois da abertura (db.jsx abre com o cache)
  React.useEffect(() => {
    const on = () => setLeads((window.LEADS || []).map(normalizeLead));
    window.addEventListener('horos:leads-refreshed', on);
    return () => window.removeEventListener('horos:leads-refreshed', on);
  }, []);
  const [columns, setColumns] = React.useState(() => loadKanbanCols());
  const [editOpen, setEditOpen] = React.useState(false);
  const [selectedLead, setSelectedLead] = React.useState(null);
  const [editingLead, setEditingLead] = React.useState(null);
  const [colPages, setColPages] = React.useState({});
  const [bulkBusy, setBulkBusy] = React.useState(false);
  // Busca por etapa: { [colId]: texto } e quais colunas estão com a lupa aberta
  const [colSearch, setColSearch] = React.useState({});
  const [colSearchOpen, setColSearchOpen] = React.useState({});
  const closeColSearch = (id) => { setColSearch(p => ({ ...p, [id]: '' })); setColSearchOpen(p => ({ ...p, [id]: false })); };
  const kanbanRef = React.useRef(null);
  const topBarRef = React.useRef(null);
  const syncing = React.useRef(false);
  const [phantomW, setPhantomW] = React.useState(9999);
  React.useEffect(() => { if (kanbanRef.current) setPhantomW(kanbanRef.current.scrollWidth); }, [leads]);

  const { selectMode, setSelectMode, selectedIds, setSelectedIds, toggleSelect, exitSelect, visRef: kbVisRef } = useKanbanSelection(undefined);
  const bulkMove = async (colId) => {
    const ids = [...selectedIds];
    if (!ids.length) return;
    setBulkBusy(true);
    const ok = new Set(await runBulkLeadRpc(ids, 'move_lead', { p_col: colId }));
    const now = new Date().toISOString();
    setLeads(prev => prev.map(l => ok.has(l.id) ? { ...l, col: colId, updated_at: now, progress: COL_PROGRESS[colId] ?? l.progress } : l));
    if (Array.isArray(window.LEADS)) window.LEADS = window.LEADS.map(l => ok.has(l.id) ? { ...l, col: colId, updated_at: now } : l);
    setBulkBusy(false);
    if (ok.size < ids.length) window.HorosNotif?.notify({ title: 'Alguns leads não foram movidos', body: `${ids.length - ok.size} lead(s) sem permissão para mover.`, module: 'system', type: 'info', priority: 'low' });
    exitSelect();
  };
  const bulkArchive = async () => {
    const ids = [...selectedIds];
    if (!ids.length) return;
    const names = leads.filter(l => ids.includes(l.id)).map(l => l.name);
    const ok = new Set(await horosArchiveLeads(ids, { names }));
    if (!ok.size) return;
    setBulkBusy(true);
    setLeads(prev => prev.filter(l => !ok.has(l.id)));
    if (Array.isArray(window.LEADS)) window.LEADS = window.LEADS.filter(l => !ok.has(l.id));
    setBulkBusy(false);
    exitSelect();
  };
  const bulkTransfer = async (toUserId, restart) => {
    const ids = [...selectedIds];
    if (!ids.length) return;
    setBulkBusy(true);
    const { data, error } = await window.HOROS_SB.rpc('transfer_leads', { p_ids: ids, p_to: toUserId, p_restart: restart });
    setBulkBusy(false);
    if (error) { window.HorosNotif?.notify({ title: 'Não foi possível passar os leads', body: error.message, module: 'system', type: 'info', priority: 'low' }); return; }
    exitSelect();
    await handleRefreshRef.current?.();
    window.HorosNotif?.notify({ title: 'Leads passados', body: `${data || 0} lead(s) transferidos.`, module: 'system', type: 'info', priority: 'low' });
  };
  const handleRefreshRef = React.useRef(null);

  const onKanbanScroll = (e) => { if (!syncing.current && topBarRef.current) { syncing.current = true; topBarRef.current.scrollLeft = e.target.scrollLeft; syncing.current = false; } };
  const onTopBarScroll = (e) => { if (!syncing.current && kanbanRef.current) { syncing.current = true; kanbanRef.current.scrollLeft = e.target.scrollLeft; syncing.current = false; } };

  const handleLeadClick = (lead) => {
    const allClients = window.CLIENTS || [];
    const client = allClients.find(c => c.name === lead.name);
    if (client) {
      setSelectedLead(client);
    } else {
      setSelectedLead({
        ...lead,
        email: lead.email || null,
        phone: lead.phone || '—',
        status: COL_TO_STATUS[lead.col] || 'qualifying',
        messages: [],
        visits: [],
        timeline: [],
        creditScore: null,
        creditTier: null,
      });
    }
  };

  React.useEffect(() => {
    const onCreate = (e) => setLeads(prev => prev.some(l => l.id === e.detail.id) ? prev : [normalizeLead(e.detail), ...prev]);
    const onUpdate = (e) => {
      const upd = e.detail;
      setLeads(prev => prev.map(l => l.id === upd.id ? normalizeLead({ ...l, ...upd }) : l));
      setSelectedLead(prev => prev && prev.id === upd.id ? normalizeLead({ ...prev, ...upd }) : prev);
    };
    const onColsUpdated = (e) => setColumns(e.detail);
    const onBatch = (e) => {
      const byId = new Map((e.detail || []).map(l => [l.id, l]));
      setLeads(prev => [
        ...[...byId.values()].map(l => normalizeLead({ ...(prev.find(p => p.id === l.id) || {}), ...l })),
        ...prev.filter(l => !byId.has(l.id)),
      ]);
    };
    window.addEventListener('horos:lead-created', onCreate);
    window.addEventListener('horos:lead-updated', onUpdate);
    window.addEventListener('horos:columns-updated', onColsUpdated);
    window.addEventListener('horos:batch-imported', onBatch);
    return () => {
      window.removeEventListener('horos:lead-created', onCreate);
      window.removeEventListener('horos:lead-updated', onUpdate);
      window.removeEventListener('horos:columns-updated', onColsUpdated);
      window.removeEventListener('horos:batch-imported', onBatch);
    };
  }, []);

  const handleEditSaved = (updatedLead) => {
    setLeads(prev => prev.map(l => l.id === updatedLead.id ? updatedLead : l));
  };

  // Lixeira do card: pede o motivo antes de arquivar
  const handleDelete = async (leadId) => {
    const lead = leads.find(l => l.id === leadId);
    const ok = await horosArchiveLeads([leadId], { names: [lead?.name] });
    if (ok.length) setLeads(prev => prev.filter(l => l.id !== leadId));
  };

  // Arrastar: o lead vai para o topo da nova coluna (onde o Kanban abriu o espaço)
  const dnd = useKbDrag(async (id, colId) => {
    setLeads(prev => {
      const cur = prev.find(l => l.id === id);
      if (!cur) return prev;
      return [{ ...cur, col: colId, progress: COL_PROGRESS[colId] ?? cur.progress }, ...prev.filter(l => l.id !== id)];
    });
    if (window.HOROS_SB) await window.HOROS_SB.rpc('move_lead', { p_id: id, p_col: colId });
  });

  const [refreshing, setRefreshing] = React.useState(false);
  const [filterOpen, setFilterOpen] = React.useState(false);
  const [kanbanFilter, setKanbanFilter] = React.useState({ temp: 'all', score: 'all' });
  const filterBtnRef = React.useRef(null);

  const handleRefresh = async () => {
    if (refreshing) return;
    setRefreshing(true);
    const sb = window.HOROS_SB;
    if (sb && window.reloadLeads) {
      // Todos os leads (paginado) já com as etapas do rodízio
      const fresh = await window.reloadLeads();
      setLeads(fresh.map(normalizeLead));
    } else if (sb) {
      const { data } = await sb.from('leads').select('*').eq('archived', false).order('created_at');
      if (data) {
        const mapped = await enrichLeadStages(data.map(l => { const b = l.col === 'aprovado' ? { ...l, col: 'aprovado_final' } : l; return { ...b, broker: b.data?.corretor || b.broker || '' }; }));
        window.LEADS = mapped;
        setLeads(mapped.map(normalizeLead));
      }
    }
    setRefreshing(false);
  };

  handleRefreshRef.current = handleRefresh;

  React.useEffect(() => {
    if (!filterOpen) return;
    const close = (e) => { if (filterBtnRef.current && !filterBtnRef.current.closest('.kanban-filter-wrap')?.contains(e.target)) setFilterOpen(false); };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, [filterOpen]);

  const activeFilters = (kanbanFilter.temp !== 'all' ? 1 : 0) + (kanbanFilter.score !== 'all' ? 1 : 0);

  const filtered = React.useMemo(() => {
    let list = segment === 'all' ? leads : leads.filter(l => l.seg === segment);
    if (kanbanFilter.temp !== 'all') list = list.filter(l => l.temp === kanbanFilter.temp);
    if (kanbanFilter.score === 'high')     list = list.filter(l => (l.score || 0) >= 80);
    else if (kanbanFilter.score === 'mid') list = list.filter(l => (l.score || 0) >= 50 && (l.score || 0) < 80);
    else if (kanbanFilter.score === 'low') list = list.filter(l => (l.score || 0) < 50);
    return list;
  }, [leads, segment, kanbanFilter]);

  kbVisRef.current = filtered; // lista visível para Shift+clique / Ctrl+A

  const setColPage = (colId, fn) => setColPages(prev => {
    const cur = prev[colId] || 1;
    return { ...prev, [colId]: fn(cur) };
  });

  // Clique num cliente do Dashboard (leads esquecidos, assistente, últimos clientes) → vai até o card aqui.
  // Tira filtro/busca que o escondem e abre a página da coluna em que ele está.
  const focusRef = React.useRef(null);
  focusRef.current = (id) => {
    const lead = leads.find(l => l.id === id);
    if (!lead || !columns.some(c => c.id === lead.col)) return false;
    if (segment !== 'all' && lead.seg !== segment) return false;
    let list = filtered;
    if (!filtered.some(l => l.id === id)) {
      setKanbanFilter({ temp: 'all', score: 'all' });
      list = segment === 'all' ? leads : leads.filter(l => l.seg === segment);
    }
    if (selectMode) exitSelect();
    closeColSearch(lead.col);
    setColPages(p => ({ ...p, [lead.col]: kbLeadPage(list, lead, KANBAN_PAGE_SIZE) }));
    return kbScrollToCard(id);
  };
  React.useEffect(() => {
    const fn = (id) => focusRef.current(id);
    window.horosKanbanFocus = fn;
    return () => { if (window.horosKanbanFocus === fn) delete window.horosKanbanFocus; };
  }, []);

  const handleKanbanSave = async (newCols) => {
    const deletedIds = new Set(columns.filter(c => !newCols.find(n => n.id === c.id)).map(c => c.id));
    const fallback = newCols[0]?.id || 'inbox';
    if (deletedIds.size > 0) {
      setLeads(prev => prev.map(l => deletedIds.has(l.col) ? { ...l, col: fallback } : l));
      if (window.HOROS_SB) {
        for (const colId of deletedIds) {
          await window.HOROS_SB.rpc('move_lead_col', { p_from_col: colId, p_to_col: fallback });
        }
      }
    }
    setColumns(newCols);
    saveKanbanCols(newCols);
    setEditOpen(false);
  };

  return (
    <div className="panel">
      <div className="panel-head">
        <h3 className="panel-title">
          Funil de Vendas
          <span className="count">{filtered.length} leads</span>
        </h3>
        <div className="panel-actions">
          <button className="ghost-btn" onClick={() => setEditOpen(true)}><Icon name="pencil" size={13} /> Editar Funil</button>
          <button className={`ghost-btn${selectMode ? ' kb-select-on' : ''}`} onClick={() => selectMode ? exitSelect() : setSelectMode(true)}
            title="Selecionar vários leads para mover ou arquivar">
            {selectMode
              ? <><Icon name="close" size={13} stroke={2.2} /> Cancelar seleção</>
              : <><span className="kb-hbtn-box"><svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg></span> Selecionar</>}
          </button>
          <div className="kanban-filter-wrap" style={{ position:'relative' }}>
            <button ref={filterBtnRef} className="ghost-btn" onClick={() => setFilterOpen(o => !o)}
              style={{ position:'relative' }}>
              <Icon name="filter" size={13} /> Filtrar
              {activeFilters > 0 && <span style={{ position:'absolute', top:-4, right:-4, background:'#1F93FF', color:'#fff', borderRadius:99, fontSize:9, fontWeight:700, width:14, height:14, display:'flex', alignItems:'center', justifyContent:'center' }}>{activeFilters}</span>}
            </button>
            {filterOpen && (
              <div style={{ position:'absolute', top:'calc(100% + 6px)', right:0, zIndex:200, background:'var(--card)', color:'var(--fg)', border:'1px solid var(--line-strong)', borderRadius:12, padding:16, boxShadow:'0 8px 24px rgba(0,0,0,0.12)', minWidth:290 }}>
                <div style={{ fontSize:11, fontWeight:600, color:'var(--fg-3)', marginBottom:8, textTransform:'uppercase', letterSpacing:'.05em' }}>Temperatura</div>
                <div style={{ display:'flex', flexWrap:'wrap', gap:6, marginBottom:14 }}>
                  {[{v:'all',l:'Todos'},{v:'hot',l:'Quente',i:'flame'},{v:'warm',l:'Morno',i:'sun'},{v:'cold',l:'Frio',i:'snow'}].map(o => (
                    <button key={o.v} onClick={() => setKanbanFilter(f => ({...f, temp:o.v}))}
                      style={{ padding:'4px 10px', borderRadius:20, border:'1px solid', borderColor:kanbanFilter.temp===o.v?'#1F93FF':'var(--line-strong)', background:kanbanFilter.temp===o.v?'#1F93FF':'transparent', color:kanbanFilter.temp===o.v?'#fff':'var(--fg-2)', fontSize:12, cursor:'pointer', fontWeight:kanbanFilter.temp===o.v?600:400, display:'flex', alignItems:'center', gap:4 }}>
                      {o.i && <Icon name={o.i} size={11} />}{o.l}
                    </button>
                  ))}
                </div>
                <div style={{ fontSize:11, fontWeight:600, color:'var(--fg-3)', marginBottom:8, textTransform:'uppercase', letterSpacing:'.05em' }}>Score IA</div>
                <div style={{ display:'flex', flexWrap:'wrap', gap:6, marginBottom: activeFilters > 0 ? 14 : 0 }}>
                  {[{v:'all',l:'Todos'},{v:'high',l:'★ Alto ≥80'},{v:'mid',l:'Médio 50–79'},{v:'low',l:'Baixo <50'}].map(o => (
                    <button key={o.v} onClick={() => setKanbanFilter(f => ({...f, score:o.v}))}
                      style={{ padding:'4px 10px', borderRadius:20, border:'1px solid', borderColor:kanbanFilter.score===o.v?'#1F93FF':'var(--line-strong)', background:kanbanFilter.score===o.v?'#1F93FF':'transparent', color:kanbanFilter.score===o.v?'#fff':'var(--fg-2)', fontSize:12, cursor:'pointer', fontWeight:kanbanFilter.score===o.v?600:400 }}>
                      {o.l}
                    </button>
                  ))}
                </div>
                {activeFilters > 0 && (
                  <button onClick={() => { setKanbanFilter({temp:'all',score:'all'}); setFilterOpen(false); }}
                    style={{ background:'none', border:'none', color:'#ef4444', fontSize:12, cursor:'pointer', padding:0 }}>
                    Limpar filtros
                  </button>
                )}
              </div>
            )}
          </div>
          <button className="ghost-btn" onClick={handleRefresh} disabled={refreshing}
            style={{ opacity: refreshing ? 0.6 : 1 }}>
            <span style={{ display:'inline-block', animation: refreshing ? 'spin .7s linear infinite' : 'none' }}><Icon name="refresh" size={13} /></span>
            {refreshing ? ' Atualizando…' : ' Atualizar'}
          </button>
          <button onClick={() => window.dispatchEvent(new CustomEvent('horos:new-lead'))}
            style={{ background:'var(--accent)', color:'#fff', border:'none', borderRadius:8, padding:'6px 12px', fontSize:12, fontWeight:600, cursor:'pointer', display:'flex', alignItems:'center', gap:5 }}>
            <svg width="11" height="11" viewBox="0 0 12 12" fill="none"><path d="M6 1v10M1 6h10" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></svg>
            Novo Lead
          </button>
        </div>
      </div>
      <KbMobileStages columns={columns} scrollRef={kanbanRef}
        counts={filtered.reduce((m, l) => { m[l.col] = (m[l.col] || 0) + 1; return m; }, {})} />
      <div ref={topBarRef} onScroll={onTopBarScroll} className="kb-topscroll"
        style={{ overflowX:'auto', height:10, margin:'4px 8px 0', borderRadius:4, cursor:'ew-resize' }}>
        <div style={{ height:1, width: phantomW }} />
      </div>
      <div ref={kanbanRef} className="kanban" onScroll={onKanbanScroll}>
        <KbDragOverlay dnd={dnd} render={(l) => (
          <div className="crm-lead kbx-card kbx-floating"><KbLeadCardBody lead={l} money={fmtCurrency} selectMode /></div>
        )} />
        <div className="kanban-cols crm-cols">
          {columns.map(col => {
            const colAll = filtered.filter(l => l.col === col.id);
            const colQ = colSearch[col.id] || '';
            const allItems = colQ.trim() ? colAll.filter(l => kbLeadMatches(l, colQ)) : colAll;
            const colPage = colPages[col.id] || 1;
            const colTotalPages = Math.max(1, Math.ceil(allItems.length / KANBAN_PAGE_SIZE));
            const items = allItems.slice((colPage - 1) * KANBAN_PAGE_SIZE, colPage * KANBAN_PAGE_SIZE);
            const total = isArchivedCol(col.id) ? 0 : allItems.reduce((s, l) => s + leadMoney(l), 0);
            const glow = col.color + '2e';
            return (
              <div key={col.id} data-col={col.id}
                   className={`kcol crm-kcol ${dnd.drag && dnd.over === col.id ? 'drag-over' : ''}`}
                   style={{ '--col-color': col.color, '--col-glow': glow }}>
                <div className="kcol-head crm-kcol-head">
                  <span className="kcol-dot" />
                  <span className="kcol-title">{col.title}</span>
                  <span className="kcol-count">{colQ.trim() ? `${allItems.length}/${colAll.length}` : allItems.length}</span>
                  {!selectMode && colAll.length > 0 && (
                    <KbColSearchBtn open={!!colSearchOpen[col.id]} active={!!colQ.trim()}
                      onToggle={() => colSearchOpen[col.id] ? closeColSearch(col.id) : setColSearchOpen(p => ({ ...p, [col.id]: true }))} />
                  )}
                  {selectMode && allItems.length > 0 && <KbColCheck items={allItems} selectedIds={selectedIds} setSelectedIds={setSelectedIds} />}
                </div>
                {colSearchOpen[col.id] && (
                  <KbColSearchInput value={colQ} shown={allItems.length} total={colAll.length}
                    onChange={v => { setColSearch(p => ({ ...p, [col.id]: v })); setColPages(p => ({ ...p, [col.id]: 1 })); }}
                    onClose={() => closeColSearch(col.id)} />
                )}
                <div className="kcol-sub">
                  {!isArchivedCol(col.id) && <span className="kcol-total"><span className="cur">R$</span>{fmtCurrency(total)}</span>}
                  <span className="kcol-leads-label">{allItems.length === 1 ? 'lead' : 'leads'}</span>
                </div>
                <div className="kcol-body">
                  <KbColCards dnd={dnd} colId={col.id} items={items}
                    empty={<div className="kcol-empty">{colQ.trim() ? 'Nenhum lead encontrado nesta etapa' : 'Arraste leads aqui'}</div>}
                    renderCard={(l) => (
                      <LeadCard lead={l}
                                onCardPointerDown={dnd.onCardPointerDown}
                                onClick={() => handleLeadClick(l)}
                                onDelete={handleDelete}
                                onEdit={setEditingLead}
                                selectMode={selectMode}
                                selected={selectedIds.has(l.id)}
                                onToggleSelect={toggleSelect} />
                    )} />
                </div>
                {colTotalPages > 1 && (
                  <div className="kbx-pager">
                    <button onClick={() => setColPage(col.id, p => Math.max(1, p - 1))} disabled={colPage === 1} aria-label="Página anterior" title="Página anterior">
                      <Icon name="arrLeft" size={14} stroke={2} />
                    </button>
                    <span><b>{colPage}</b> de {colTotalPages}</span>
                    <button onClick={() => setColPage(col.id, p => Math.min(colTotalPages, p + 1))} disabled={colPage === colTotalPages} aria-label="Próxima página" title="Próxima página">
                      <Icon name="arrRight" size={14} stroke={2} />
                    </button>
                  </div>
                )}
              </div>
            );
          })}
        </div>
      </div>
      {selectMode && (
        <KanbanBulkBar count={selectedIds.size} total={filtered.length} columns={columns} busy={bulkBusy}
          selectedLeads={filtered.filter(l => selectedIds.has(l.id))}
          onMove={bulkMove} onArchive={bulkArchive} onTransfer={bulkTransfer}
          onSelectAll={() => setSelectedIds(new Set(filtered.map(l => l.id)))}
          onClearSel={() => setSelectedIds(new Set())}
          onExit={exitSelect} />
      )}
      {editOpen && <KanbanEditModal columns={columns} leads={filtered} onSave={handleKanbanSave} onClose={() => setEditOpen(false)} />}
      {selectedLead && <Customer360 lead={selectedLead} onClose={() => setSelectedLead(null)} />}
{editingLead && <EditLeadModal lead={editingLead} onClose={() => setEditingLead(null)} onSaved={handleEditSaved} />}
    </div>
  );
}

// Converte um lead plano do Supabase em linha compatível com a tabela de clientes
function normalizeLeadAsClient(l) {
  const hash = [...(l.id || l.name || '')].reduce((a, c) => a + c.charCodeAt(0), 0);
  const palette = AVATAR_PALETTES[hash % AVATAR_PALETTES.length];
  const ts = l.updated_at || l.created_at;
  const colMeta = pipelineCols(leadPipeline(l)).find(c => c.id === l.col) || loadKanbanCols().find(c => c.id === l.col) || COLUMNS.find(c => c.id === l.col);
  const d = l.data || {};
  let last = '—';
  if (ts) {
    const diff = Math.floor((Date.now() - new Date(ts)) / 60000);
    if (diff < 60) last = `há ${diff}min`;
    else if (diff < 1440) last = `há ${Math.floor(diff / 60)}h`;
    else last = `há ${Math.floor(diff / 1440)}d`;
  }
  return {
    id: l.id,
    name: l.name || '—',
    initials: l.initials || (l.name || '?').split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase(),
    email: l.email || '—',
    phone: l.phone || '—',
    seg: l.seg || '—',
    cat: l.cat || '—',
    status: COL_TO_STATUS[l.col] || 'qualifying',
    score: l.score || 0,
    palette,
    action: colMeta ? colMeta.title : 'Em atendimento',
    when: ts ? new Date(ts).toLocaleDateString('pt-BR') : '—',
    urgency: l.temp === 'hot' ? 'asap' : '',
    // Campos extras para o Customer360
    temp: l.temp, col: l.col, value: l.value,
    progress: COL_PROGRESS[l.col] ?? 0,
    last,
    messages: [], visits: [], timeline: [],
    creditScore: null, creditTier: null,
    creditDocs: window.buildCreditDocs ? window.buildCreditDocs(l.docs) : null,
    broker:      d.corretor           || l.broker || '',
    renda:       d.rendaIndividual    ? `R$ ${d.rendaIndividual}/mês` : null,
    region:      d.regiaoDesejada     || (l.cat && l.cat !== l.name ? l.cat : null),
    interesse:   d.categoriaInteresse || l.cat || null,
    observacoes: d.obsInteresses      || null,
  };
}

function buildClientRows(q) {
  const leads = (window.LEADS || []).filter(l => !q || window.kbLeadMatches(l, q));
  return [...leads]
    .sort((a, b) => new Date(b.updated_at || b.created_at || 0) - new Date(a.updated_at || a.created_at || 0))
    .slice(0, 10)
    .map(normalizeLeadAsClient);
}

const STATUS_LABEL = {
  qualifying: 'Qualificando',
  engaged: 'Engajado',
  proposal: 'Em proposta',
  won: 'Ganho',
  lost: 'Perdido',
};

function ClientsTable({ segment }) {
  const [selected, setSelected] = React.useState(null);
  const [rows, setRows] = React.useState(() => buildClientRows());
  // "Filtrar": busca em TODOS os leads (nome, telefone, e-mail, região) e mostra os 10 mais recentes
  const [q, setQ] = React.useState('');
  const [searchOpen, setSearchOpen] = React.useState(false);
  const qRef = React.useRef('');
  qRef.current = q;
  React.useEffect(() => { setRows(buildClientRows(q)); }, [q]);
  const [menu, setMenu] = React.useState(null); // { lead, top, left }
  React.useEffect(() => {
    if (!menu) return;
    const close = (e) => { if (e.type !== 'keydown' || e.key === 'Escape') setMenu(null); };
    const t = setTimeout(() => document.addEventListener('mousedown', close), 0);
    document.addEventListener('keydown', close);
    window.addEventListener('scroll', close, true);
    return () => { clearTimeout(t); document.removeEventListener('mousedown', close); document.removeEventListener('keydown', close); window.removeEventListener('scroll', close, true); };
  }, [menu]);
  const openMenu = (e, lead) => {
    e.stopPropagation();
    const r = e.currentTarget.getBoundingClientRect();
    setMenu(m => (m && m.lead.id === lead.id) ? null : { lead, top: r.bottom + 4, left: Math.max(8, r.right - 200) });
  };
  const goCRM = (lead) => {
    try { sessionStorage.setItem('horos:highlight-lead', lead.id); } catch {}
    window.location.href = 'crm.html';
  };

  React.useEffect(() => {
    const handler = () => setRows(buildClientRows(qRef.current));
    window.addEventListener('horos:lead-created', handler);
    window.addEventListener('horos:lead-updated', handler);
    window.addEventListener('horos:batch-imported', handler);
    return () => {
      window.removeEventListener('horos:lead-created', handler);
      window.removeEventListener('horos:lead-updated', handler);
      window.removeEventListener('horos:batch-imported', handler);
    };
  }, []);

  const filtered = segment === 'all'
    ? rows
    : rows.filter(c => (c.seg || '').toLowerCase().includes(segment.slice(0, 5)));

  return (
    <div className="panel">
      <div className="panel-head">
        <h3 className="panel-title">
          Últimos clientes
          <span className="count">{filtered.length}</span>
        </h3>
        <div className="panel-actions">
          {searchOpen ? (
            <input className="dash-cli-search" autoFocus value={q} placeholder="Nome, telefone, e-mail…"
              onChange={e => setQ(e.target.value)}
              onKeyDown={e => { if (e.key === 'Escape') { setQ(''); setSearchOpen(false); } }}
              onBlur={() => { if (!q) setSearchOpen(false); }} />
          ) : (
            <button className="ghost-btn" onClick={() => setSearchOpen(true)}><Icon name="filter" size={13} /> Filtrar</button>
          )}
          <a href="clients.html" className="ghost-btn" style={{ textDecoration:'none', display:'inline-flex', alignItems:'center', gap:4 }}>
            Ver todos <Icon name="arrRight" size={13} />
          </a>
        </div>
      </div>

      {filtered.length === 0 ? (
        <div style={{ padding:'48px 24px', textAlign:'center', color:'var(--fg-4)', fontSize:13 }}>
          {q ? <>Nenhum lead encontrado para "{q}". </> : <>Nenhum lead cadastrado ainda.{' '}</>}
          <button onClick={() => window.dispatchEvent(new CustomEvent('horos:new-lead'))}
            style={{ background:'none', border:'none', color:'var(--accent)', cursor:'pointer', fontSize:13, textDecoration:'underline', padding:0 }}>
            Criar o primeiro lead
          </button>
        </div>
      ) : (
        <table className="table">
          <thead>
            <tr>
              <th style={{ paddingLeft: 18 }}>Nome</th>
              <th>Telefone</th>
              <th>Categoria</th>
              <th>Status</th>
              <th>Score</th>
              <th>Última atividade</th>
              <th style={{ width: 60 }}></th>
            </tr>
          </thead>
          <tbody>
            {filtered.map((c, i) => (
              <tr key={c.id || i} onClick={() => c.id ? window.horosGoToLead(c.id) : setSelected(c)} style={{ cursor: 'pointer' }} title="Ver no funil">
                <td style={{ paddingLeft: 18 }}>
                  <div className="cell-name">
                    <div className="avatar" style={{ background: `linear-gradient(135deg, ${c.palette[0]}, ${c.palette[1]})`, width: 30, height: 30 }}>
                      {c.initials}
                    </div>
                    <div className="meta-stack">
                      <span className="name">{c.name}</span>
                      <span className="email">{c.email}</span>
                    </div>
                  </div>
                </td>
                <td><span className="phone">{fmtPhone(c.phone)}</span></td>
                <td><span className="tag">{c.seg} · {c.cat}</span></td>
                <td><span className={`status-pill ${c.status}`}>{STATUS_LABEL[c.status] || c.status}</span></td>
                <td>
                  <div className="score-cell">
                    <ScoreRing score={c.score} />
                    <span className="score-num">{c.score}</span>
                  </div>
                </td>
                <td>
                  <div className="next-action">
                    <span className="action-name">{c.action}</span>
                    <span className={`action-when ${c.urgency || ''}`}>{c.when}</span>
                  </div>
                </td>
                <td>
                  <div className="row-actions">
                    <button className="icon-btn" style={{ width: 28, height: 28 }} title="Conversar no WhatsApp (Horos 360)"
                      onClick={e => { e.stopPropagation(); setSelected(c); }}>
                      <Icon name="message" size={13} />
                    </button>
                    <button className="icon-btn" style={{ width: 28, height: 28 }} title="Mais opções"
                      onClick={e => openMenu(e, c)}>
                      <Icon name="dots" size={13} />
                    </button>
                  </div>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      )}

      {selected && <Customer360 lead={selected} onClose={() => setSelected(null)} />}
      {menu && ReactDOM.createPortal(
        <div className="dash-row-menu" style={{ top: menu.top, left: menu.left }} onMouseDown={e => e.stopPropagation()}>
          <button onClick={() => { setSelected(menu.lead); setMenu(null); }}><Icon name="user" size={13} /> Abrir Horos 360</button>
          <button onClick={() => { const id = menu.lead.id; setMenu(null); window.horosOpenLeadSheet(id); }}><Icon name="sheet" size={13} /> Abrir ficha</button>
          <button onClick={() => goCRM(menu.lead)}><Icon name="arrRight" size={13} /> Ver no CRM</button>
        </div>,
        document.body
      )}
    </div>
  );
}

window.KPICards = KPICards;
window.Kanban = Kanban;
window.ClientsTable = ClientsTable;
