/* global React, Icon, Button, Badge, Card, brl,
          ClienteForm, BizForm, RepresentanteForm */

// ============================================================
// CRM — list pages. Click row / pencil → opens full-page form
// (defined in CRM_Forms.jsx). Trash → delete with confirmation.
// ============================================================

const { useState: useCrmState } = React;

// ── Mapeamento IBGE código numérico → sigla UF ────────────────
const IBGE_TO_UF = {
  11:'RO',12:'AC',13:'AM',14:'RR',15:'PA',16:'AP',17:'TO',
  21:'MA',22:'PI',23:'CE',24:'RN',25:'PB',26:'PE',27:'AL',28:'SE',29:'BA',
  31:'MG',32:'ES',33:'RJ',35:'SP',
  41:'PR',42:'SC',43:'RS',
  50:'MS',51:'MT',52:'GO',53:'DF',
};

// Paleta de cores para distribuidores no mapa
const MAP_COLORS = [
  '#C9A36B','#7C5CBF','#2D9CDB','#27AE60','#E74C3C',
  '#F39C12','#1ABC9C','#8E44AD','#3498DB','#D35400',
  '#16A085','#C0392B','#2980B9','#E67E22','#95A5A6',
];

// Constrói mapeamento UF → índices de distribuidores
// Usa `territorio` quando preenchido; caso vazio, cai no `geral_uf` do cadastro
function buildUfToDist(rows) {
  const map = {};
  rows.forEach((d, i) => {
    const ufs = (d.territorio && d.territorio.length > 0)
      ? d.territorio
      : (d.geral_uf ? [d.geral_uf] : []);
    ufs.forEach(uf => {
      if (!map[uf]) map[uf] = [];
      map[uf].push(i);
    });
  });
  return map;
}

// ============================================================
// MAPA INTERATIVO DE DISTRIBUIDORES
// ============================================================
function MapaDistribuidores({ rows, onClose }) {
  const mapDivRef    = React.useRef(null);   // div do DOM
  const leafletMap   = React.useRef(null);   // instância L.map
  const markersGroup = React.useRef(null);   // L.layerGroup para alfinetes
  const [status,       setStatus]       = useCrmState('loading');
  const [showPins,     setShowPins]     = useCrmState(false);
  const [pinsLoading,  setPinsLoading]  = useCrmState(false);

  // ── Effect 1: inicializa o mapa e carrega GeoJSON (roda só uma vez) ──
  React.useEffect(() => {
    if (!mapDivRef.current || !window.L) return;
    const L = window.L;
    const ufToDist = buildUfToDist(rows);

    const map = L.map(mapDivRef.current, {
      center: [-14.5, -51.5], zoom: 4,
      zoomControl: true, attributionControl: false, scrollWheelZoom: true,
    });
    leafletMap.current   = map;
    markersGroup.current = L.layerGroup().addTo(map);

    const styleFn = (uf) => {
      const idxs = ufToDist[uf] || [];
      if (idxs.length === 0) return { fillColor: '#94a3b8', fillOpacity: 0.22, weight: 1,   color: '#fff' };
      if (idxs.length === 1) return { fillColor: MAP_COLORS[idxs[0] % MAP_COLORS.length], fillOpacity: 0.75, weight: 1.5, color: '#fff' };
      return                        { fillColor: '#C9A36B',  fillOpacity: 0.70, weight: 1.5, color: '#fff' };
    };
    const hoverStyle = { fillColor: '#C9A36B', fillOpacity: 0.95, weight: 2.5, color: '#fff' };

    let geoLayer;
    fetch('https://servicodados.ibge.gov.br/api/v3/malhas/paises/BR?intrarregiao=UF&formato=application/vnd.geo+json')
      .then(r => r.json())
      .then(geo => {
        geoLayer = L.geoJSON(geo, {
          style: (f) => styleFn(IBGE_TO_UF[parseInt(f.properties?.codarea ?? f.id ?? 0)]),
          onEachFeature: (f, layer) => {
            const uf   = IBGE_TO_UF[parseInt(f.properties?.codarea ?? f.id ?? 0)] || '?';
            const idxs = ufToDist[uf] || [];
            const here = idxs.map(i => rows[i]);

            let html;
            if (!here.length) {
              html = `<div><b style="font-size:14px">${uf}</b><br><span style="color:#94a3b8;font-size:12px">Sem cobertura</span></div>`;
            } else if (here.length === 1) {
              const d = here[0];
              const isSede = !(d.territorio && d.territorio.length > 0);
              html = `<div>
                <b style="font-size:14px">${uf}</b>${isSede ? '<span style="font-size:11px;color:#C9A36B"> · sede</span>' : ''}<br>
                <span style="font-size:13px;font-weight:500">${d.nome}</span><br>
                <span style="font-size:12px;color:#94a3b8">Tier ${d.status || '—'} · ${d.geral_cidade || d.cidade || ''}</span>
              </div>`;
            } else {
              const linhas = here.map(d => {
                const c = d.geral_cidade || d.cidade || '';
                return `<span style="font-size:12px">• <b>${d.nome}</b>${c ? ' · ' + c : ''}</span>`;
              }).join('<br>');
              html = `<div><b style="font-size:14px">${uf}</b><span style="font-size:11px;color:#C9A36B"> · ${here.length} distribuidores</span><br>${linhas}</div>`;
            }

            layer.bindTooltip(html, { sticky: true, className: 'tm-map-tooltip' });
            layer.on({
              mouseover: (e) => { e.target.setStyle(hoverStyle); e.target.bringToFront(); },
              mouseout:  ()  => geoLayer.resetStyle(layer),
            });
          },
        }).addTo(map);
        setStatus('ready');
      })
      .catch(() => setStatus('error'));

    return () => { map.remove(); leafletMap.current = null; markersGroup.current = null; };
  }, []); // eslint-disable-line

  // ── Effect 2: adiciona/remove alfinetes quando toggle muda ──
  React.useEffect(() => {
    const L     = window.L;
    const map   = leafletMap.current;
    const group = markersGroup.current;
    if (!L || !map || !group) return;

    group.clearLayers();
    if (!showPins) return;

    // Agrupa distribuidores por cidade (mesma cidade = mesmas coords → 1 geocoding por cidade)
    const cityGroups = {};
    rows.forEach((d, rowIdx) => {
      const key = `${(d.geral_cidade || '').toLowerCase().trim()}__${(d.geral_uf || '').toLowerCase().trim()}`;
      if (!cityGroups[key]) {
        cityGroups[key] = {
          localidade: [d.geral_cidade, d.geral_uf, 'Brasil'].filter(Boolean).join(', '),
          dists: [],
        };
      }
      cityGroups[key].dists.push({ d, rowIdx });
    });

    const entries = Object.values(cityGroups).filter(g => g.localidade.replace('Brasil','').trim());
    if (entries.length === 0) { setPinsLoading(false); return; }

    setPinsLoading(true);
    let done = 0;
    const finish = () => { done++; if (done >= entries.length) setPinsLoading(false); };

    entries.forEach(({ localidade, dists }, gi) => {
      setTimeout(() => {
        fetch(`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(localidade)}&format=json&limit=1&countrycodes=br`)
          .then(r => r.json())
          .then(results => {
            if (!results?.length) return;
            const baseLat = parseFloat(results[0].lat);
            const baseLon = parseFloat(results[0].lon);
            const n = dists.length;

            dists.forEach(({ d, rowIdx }, pos) => {
              const color = MAP_COLORS[rowIdx % MAP_COLORS.length];

              // Offset em pixels para evitar sobreposição quando n > 1
              // Distribui em leque semicircular acima do ponto
              let xOff = 0, yOff = 0;
              if (n > 1) {
                const spread = Math.min(60, 30 * n);      // raio em px, cresce com n
                const startAngle = Math.PI + Math.PI / 6; // começa esquerda-baixo
                const sweep      = -Math.PI * 2 / 3;      // arco de 120° para cima
                const angle = startAngle + (pos / (n - 1)) * sweep;
                xOff = Math.cos(angle) * spread;
                yOff = Math.sin(angle) * spread;
              }

              // Extrai iniciais: duas primeiras letras de palavras distintas (ou as 2 primeiras do nome)
              const words   = d.nome.trim().split(/\s+/);
              const initial = words.length >= 2
                ? (words[0][0] + words[words.length - 1][0]).toUpperCase()
                : d.nome.slice(0, 2).toUpperCase();

              const pinHtml = `
                <div class="tm-pin-wrap" style="--pc:${color};transform:translate(calc(-50% + ${xOff}px),calc(-100% + ${yOff}px))">
                  <div class="tm-pin-name">${d.nome}</div>
                  <div class="tm-pin-bubble">${initial}</div>
                  <div class="tm-pin-tip" style="border-top-color:${color}"></div>
                </div>`;

              const icon = L.divIcon({ html: pinHtml, className: 'tm-dist-marker', iconSize: [0,0], iconAnchor: [0,0] });
              const tooltipHtml = `<div>
                <span style="font-size:13px;font-weight:600">${d.nome}</span>${d.status ? ' · ' + d.status : ''}<br>
                <span style="font-size:12px;color:#94a3b8">${d.geral_cidade || d.geral_uf || ''}</span>
              </div>`;

              L.marker([baseLat, baseLon], { icon })
                .bindTooltip(tooltipHtml, { className: 'tm-map-tooltip', offset: [xOff, yOff - 36] })
                .addTo(group);
            });
          })
          .catch(() => {})
          .finally(finish);
      }, gi * 400); // 400 ms entre grupos (Nominatim: máx 1 req/s)
    });
  }, [showPins]); // eslint-disable-line

  // Para o JSX
  const ufToDist         = buildUfToDist(rows);
  const hasCompartilhado = Object.values(ufToDist).some(a => a.length > 1);
  const coveredUFs       = new Set(Object.keys(ufToDist));

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 500, background: 'var(--tm-bg-1)', display: 'flex', flexDirection: 'column' }}>

      {/* ── Cabeçalho ── */}
      <div style={{ display: 'flex', alignItems: 'center', padding: '12px 20px', borderBottom: '1px solid var(--tm-line-1)', gap: 12, flexShrink: 0, background: 'var(--tm-bg-1)' }}>
        <button className="icon-btn" onClick={onClose}><Icon name="arrow-left" size={16} /></button>
        <div style={{ fontWeight: 600, fontSize: 15 }}>Cobertura de Distribuidores</div>
        <span className="muted" style={{ fontSize: 12 }}>
          {rows.length} distribuidor{rows.length !== 1 ? 'es' : ''} · {coveredUFs.size} UF{coveredUFs.size !== 1 ? 's' : ''} cobertas
        </span>
        <div style={{ flex: 1 }} />

        {/* Botão toggle alfinetes */}
        <button
          onClick={() => setShowPins(p => !p)}
          style={{
            display: 'flex', alignItems: 'center', gap: 7,
            padding: '6px 12px', borderRadius: 8, border: '1px solid',
            borderColor: showPins ? 'var(--tm-brand-champagne)' : 'var(--tm-line-1)',
            background: showPins ? 'rgba(201,163,107,.12)' : 'var(--tm-bg-2)',
            color: showPins ? '#C9A36B' : 'var(--tm-fg-2)',
            fontSize: 12, fontWeight: 500, cursor: 'pointer', flexShrink: 0,
            transition: 'all .15s',
          }}
        >
          {pinsLoading
            ? <Icon name="loader" size={13} style={{ animation: 'spin 1s linear infinite' }} />
            : <Icon name="map-pin" size={13} />
          }
          {showPins ? 'Ocultar alfinetes' : 'Mostrar alfinetes'}
        </button>

        {/* Separador */}
        <div style={{ width: 1, height: 18, background: 'var(--tm-line-1)', flexShrink: 0 }} />

        {/* Legenda */}
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
          {rows.map((d, i) => (
            <span key={i} style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 12 }}>
              <span style={{ width: 10, height: 10, borderRadius: 2, background: MAP_COLORS[i % MAP_COLORS.length], flexShrink: 0, display: 'inline-block' }} />
              {d.nome}
            </span>
          ))}
          <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 12, color: 'var(--tm-fg-3)' }}>
            <span style={{ width: 10, height: 10, borderRadius: 2, background: '#94a3b8', opacity: .4, border: '1px solid var(--tm-line-1)', flexShrink: 0, display: 'inline-block' }} />
            Sem cobertura
          </span>
          {hasCompartilhado && (
            <span style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 12, color: 'var(--tm-fg-2)' }}>
              <span style={{ width: 10, height: 10, borderRadius: 2, background: '#C9A36B', flexShrink: 0, display: 'inline-block' }} />
              Múltiplos distribuidores
            </span>
          )}
        </div>
      </div>

      {/* ── Mapa ── */}
      <div ref={mapDivRef} style={{ flex: 1 }} />

      {status === 'loading' && (
        <div style={{ position: 'absolute', inset: 0, top: 53, display: 'flex', alignItems: 'center', justifyContent: 'center', pointerEvents: 'none' }}>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10 }}>
            <Icon name="loader" size={22} style={{ color: 'var(--tm-fg-3)', animation: 'spin 1s linear infinite' }} />
            <span className="muted" style={{ fontSize: 13 }}>Carregando mapa do Brasil…</span>
          </div>
        </div>
      )}
      {status === 'error' && (
        <div style={{ position: 'absolute', inset: 0, top: 53, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ textAlign: 'center' }}>
            <Icon name="wifi-off" size={24} style={{ color: 'var(--tm-fg-4)', marginBottom: 8 }} />
            <div className="muted" style={{ fontSize: 13 }}>Não foi possível carregar o mapa.<br/>Verifique sua conexão e recarregue.</div>
          </div>
        </div>
      )}
      {status === 'ready' && rows.length === 0 && (
        <div style={{ position: 'absolute', inset: 0, top: 53, display: 'flex', alignItems: 'center', justifyContent: 'center', pointerEvents: 'none' }}>
          <div className="muted" style={{ fontSize: 13, textAlign: 'center' }}>
            Nenhum distribuidor cadastrado.<br/>Adicione distribuidores para ver a cobertura.
          </div>
        </div>
      )}
    </div>
  );
}

// Dados demo removidos — listas iniciam vazias
const CLIENTES_SEED    = [];
const SALOES_SEED      = [];
const DISTS_SEED       = [];
const REPS_SEED        = [];

// ── Empty state inline (ícone + título + sub + botão de ação) ─────────────────
function CRMEmpty({ icon, title, sub, action }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '64px 20px', gap: 14, textAlign: 'center' }}>
      <div style={{ width: 52, height: 52, borderRadius: 14, background: 'var(--tm-bg-3)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Icon name={icon} size={24} style={{ color: 'var(--tm-fg-4)' }} />
      </div>
      <div>
        <div style={{ fontSize: 15, fontWeight: 600, color: 'var(--tm-fg-1)' }}>{title}</div>
        <div className="muted" style={{ fontSize: 13, marginTop: 5, lineHeight: 1.6 }}>{sub}</div>
      </div>
      {action && <div style={{ marginTop: 4 }}>{action}</div>}
    </div>
  );
}

// ── Toggle para exibir/ocultar arquivados ────────────────────────────────────
function ArchiveToggle({ show, setShow, archivedCount }) {
  if (archivedCount === 0 && !show) return null;
  return (
    <button
      onClick={() => setShow(!show)}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        padding: '5px 12px', borderRadius: 6, fontSize: 12, fontWeight: 500,
        background: show ? 'var(--tm-warning-bg, rgba(245,166,35,0.12))' : 'var(--tm-bg-3)',
        color: show ? 'var(--tm-warning)' : 'var(--tm-fg-3)',
        border: '1px solid ' + (show ? 'var(--tm-warning)' : 'var(--tm-line-1)'),
        cursor: 'pointer', transition: 'all .15s',
      }}
    >
      <Icon name="archive" size={13} />
      {show ? 'Ocultar arquivados' : `Mostrar arquivados (${archivedCount})`}
    </button>
  );
}

// ============================================================
// Shared list-state hook (rows + edit dispatch)
// ============================================================
function useListState(seed) {
  const [rows, setRows] = useCrmState(seed);
  const [edit, setEdit] = useCrmState(null); // null | { mode: 'new'|'edit', idx, draft }

  const open  = (mode, idx, blank) => {
    const base = idx != null ? rows[idx] : blank;
    setEdit({ mode, idx, draft: { ...base } });
  };
  const close = () => setEdit(null);
  const save  = () => {
    if (edit.mode === "new") setRows([{ ...edit.draft }, ...rows]);
    else setRows(rows.map((r, i) => i === edit.idx ? edit.draft : r));
    setEdit(null);
  };
  const remove = (idx) => {
    if (!confirm(`Excluir "${rows[idx].nome}"? Esta ação não pode ser desfeita.`)) return;
    setRows(rows.filter((_, i) => i !== idx));
    if (edit && edit.idx === idx) setEdit(null);
  };
  const set = (k, v) => {
    if (k && typeof k === 'object') {
      setEdit(prev => ({ ...prev, draft: { ...prev.draft, ...k } }));
    } else {
      setEdit(prev => ({ ...prev, draft: { ...prev.draft, [k]: v } }));
    }
  };

  return { rows, edit, open, close, save, remove, set };
}

// ============================================================
// CLIENTES FINAIS
// ============================================================
function CRMClientes({ onNav, empresaAtual }) {
  const s = useClientesList(CLIENTES_SEED);
  const [showArchived, setShowArchived] = React.useState(false);
  const blank = { nome: "", cpf: "", celular: "", email: "", geral_cidade: "", geral_uf: "", tag: "Novo", total: 0, ult: "—", dataNasc: "", tipoPessoa: "PF", situacao: "Ativo", tiposContato: ["Cliente"], marcas: [] };

  const empresaNome = (empresaAtual && !empresaAtual.principal)
    ? (empresaAtual.nome_fantasia || empresaAtual.razao_social || null)
    : null;

  const allRows = s.rows
    .map((r, origIdx) => ({ ...r, _origIdx: origIdx }))
    .filter(r => !empresaNome
      || !r.marcas || r.marcas.length === 0
      || r.marcas.includes(empresaNome));

  const archivedCount = allRows.filter(r => r.situacao === 'Arquivado').length;
  const filteredRows = showArchived ? allRows : allRows.filter(r => r.situacao !== 'Arquivado');

  if (s.edit) {
    return (
      <ClienteForm
        state={s.edit}
        set={s.set}
        onCancel={s.close}
        onSave={s.save}
        onDelete={() => s.remove(s.edit.idx)}
      />
    );
  }

  return (
    <div className="canvas">
      <PageHead
        title="Clientes Finais"
        sub={empresaNome ? `${empresaNome} · Consumidores que compram diretamente ou via salão parceiro` : "Consumidores que compram diretamente ou via salão parceiro"}
        right={
          <>
            <Button variant="secondary" icon="download" size="sm">Exportar</Button>
            <Button variant="secondary" icon="upload" size="sm">Importar CSV</Button>
            <Button variant="primary" icon="user-plus" size="sm" onClick={() => s.open("new", null, { ...blank, marcas: empresaNome ? [empresaNome] : [] })}>Novo cliente</Button>
          </>
        }
      />
      <CRMTabs active="clientes-finais" onNav={onNav} counts={{ "clientes-finais": allRows.filter(r => r.situacao !== 'Arquivado').length }} />

      <Card>
        {filteredRows.length === 0 && archivedCount === 0 ? (
          <CRMEmpty
            icon="users"
            title="Nenhum cliente cadastrado"
            sub={"Adicione clientes finais para acompanhar compras,\ntags e histórico de contato."}
            action={<Button variant="primary" icon="user-plus" size="sm" onClick={() => s.open("new", null, { ...blank, marcas: empresaNome ? [empresaNome] : [] })}>Novo cliente</Button>}
          />
        ) : (
          <>
            <Toolbar search="Buscar por nome, CPF, telefone…" filters={["Todas as tags", "Cidade", "Última compra", "Mais filtros"]}
              right={<ArchiveToggle show={showArchived} setShow={setShowArchived} archivedCount={archivedCount} />} />
            <table className="tbl">
              <thead><tr>
                <th>Cliente</th><th>CPF</th><th>Contato</th><th>Cidade</th><th>Tag</th>
                <th className="num right">Total compras</th><th>Última</th><th></th>
              </tr></thead>
              <tbody>
                {filteredRows.map((c) => {
                  const isArchived = c.situacao === 'Arquivado';
                  return (
                  <tr key={c._origIdx} className="clickable" onClick={() => s.open("edit", c._origIdx)} style={isArchived ? { opacity: 0.55 } : undefined}>
                    <td>
                      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                        <div className="avatar md">{c.nome[0]}</div>
                        <div>
                          <div style={{ fontWeight: 500 }}>{c.nome} {isArchived && <Badge tone="neutral" style={{ marginLeft: 6 }}>Arquivado</Badge>}</div>
                          <div className="muted" style={{ fontSize: 11 }}>
                            {c.marcas && c.marcas.length > 0 ? c.marcas.join(' · ') : 'cliente final'}
                          </div>
                        </div>
                      </div>
                    </td>
                    <td><span className="ref-mono">{c.cpf}</span></td>
                    <td><span className="ch-chip"><Icon name="phone" size={12} className="ico" />{c.celular || c.whats}</span></td>
                    <td>{c.cidade}</td>
                    <td><Badge tone={c.tag === "VIP" ? "brand" : c.tag === "Risco" ? "danger" : c.tag === "Novo" ? "info" : "success"}>{c.tag}</Badge></td>
                    <td className="num right">R$ {brl(c.total)}</td>
                    <td className="muted">{c.ult}</td>
                    <td><RowActions onEdit={() => s.open("edit", c._origIdx)} onDelete={() => s.remove(c._origIdx)} onArchive={() => s.archive(c._origIdx)} onUnarchive={() => s.unarchive(c._origIdx)} archived={isArchived} /></td>
                  </tr>
                  );
                })}
              </tbody>
            </table>
            <FooterPager total={filteredRows.length} from={1} to={Math.min(filteredRows.length, 8)} />
          </>
        )}
      </Card>
    </div>
  );
}

// ============================================================
// SALÕES / BARBEARIAS
// ============================================================
function CRMSaloes({ onNav, empresaAtual }) {
  const s = useSaloesList(SALOES_SEED);
  const [showArchived, setShowArchived] = React.useState(false);
  const blank = { nome: "", tipoPessoa: "PJ", cnpj: "", cpf: "", geral_cidade: "", geral_uf: "", resp: "", fone: "", celular: "", email: "", ped: 0, fat: 0, status: "Ativo", desde: "", tipoSalao: "Cabelo", situacao: "Ativo", tiposContato: ["Cliente","Salão"], marcas: [] };

  const empresaNome = (empresaAtual && !empresaAtual.principal)
    ? (empresaAtual.nome_fantasia || empresaAtual.razao_social || null)
    : null;

  const allRows = s.rows
    .map((r, origIdx) => ({ ...r, _origIdx: origIdx }))
    .filter(r => !empresaNome
      || !r.marcas || r.marcas.length === 0
      || r.marcas.includes(empresaNome));

  const archivedCount = allRows.filter(r => r.situacao === 'Arquivado').length;
  const filteredRows = showArchived ? allRows : allRows.filter(r => r.situacao !== 'Arquivado');

  if (s.edit) {
    return (
      <BizForm kind="salao" state={s.edit} set={s.set}
        onCancel={s.close} onSave={s.save} onDelete={() => s.remove(s.edit.idx)} />
    );
  }

  return (
    <div className="canvas">
      <PageHead title="Salões / Barbearias" sub={empresaNome ? `${empresaNome} · Estabelecimentos que compram para revenda ao consumidor final` : "Estabelecimentos que compram para revenda ao consumidor final"}
        right={<><Button variant="secondary" icon="download" size="sm">Exportar</Button>
                  <Button variant="primary" icon="plus" size="sm" onClick={() => s.open("new", null, { ...blank, marcas: empresaNome ? [empresaNome] : [] })}>Novo salão</Button></>}/>
      <CRMTabs active="saloes" onNav={onNav} counts={{ saloes: allRows.filter(r => r.situacao !== 'Arquivado').length }} />
      <Card>
        {filteredRows.length === 0 && archivedCount === 0 ? (
          <CRMEmpty
            icon="store"
            title="Nenhum salão cadastrado"
            sub={"Adicione sal��es e barbearias parceiros\npara acompanhar pedidos e faturamento."}
            action={<Button variant="primary" icon="plus" size="sm" onClick={() => s.open("new", null, { ...blank, marcas: empresaNome ? [empresaNome] : [] })}>Novo salão</Button>}
          />
        ) : (
          <>
            <Toolbar search="Buscar por nome, CNPJ, responsável…" filters={["Todas", "Status", "Cidade", "Distribuidor"]}
              right={<ArchiveToggle show={showArchived} setShow={setShowArchived} archivedCount={archivedCount} />} />
            <table className="tbl">
              <thead><tr><th>Salão</th><th>CPF / CNPJ</th><th>Responsável</th><th>Cidade</th><th className="num right">Pedidos</th><th className="num right">Faturado</th><th>Status</th><th></th></tr></thead>
              <tbody>
                {filteredRows.map((row) => {
                  const isArchived = row.situacao === 'Arquivado';
                  return (
                  <tr key={row._origIdx} className="clickable" onClick={() => s.open("edit", row._origIdx)} style={isArchived ? { opacity: 0.55 } : undefined}>
                    <td>
                      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                        <div className="prod-image" style={{ width: 36, height: 36 }}><Icon name="store" size={14} /></div>
                        <div>
                          <div style={{ fontWeight: 500 }}>{row.nome} {isArchived && <Badge tone="neutral">Arquivado</Badge>}</div>
                          {row.marcas && row.marcas.length > 0 && (
                            <div className="muted" style={{ fontSize: 11 }}>{row.marcas.join(' · ')}</div>
                          )}
                        </div>
                      </div>
                    </td>
                    <td><span className="ref-mono">{row.tipoPessoa === "PF" ? row.cpf : row.cnpj}</span></td>
                    <td>{row.resp}</td>
                    <td>{row.cidade}</td>
                    <td className="num right">{row.ped}</td>
                    <td className="num right">R$ {brl(row.fat)}</td>
                    <td><Badge tone={row.status === "VIP" ? "brand" : row.status === "Risco" ? "danger" : "success"}>{row.status}</Badge></td>
                    <td><RowActions onEdit={() => s.open("edit", row._origIdx)} onDelete={() => s.remove(row._origIdx)} onArchive={() => s.archive(row._origIdx)} onUnarchive={() => s.unarchive(row._origIdx)} archived={isArchived} /></td>
                  </tr>
                  );
                })}
              </tbody>
            </table>
            <FooterPager total={filteredRows.length} from={1} to={filteredRows.length} />
          </>
        )}
      </Card>
    </div>
  );
}

// ============================================================
// DISTRIBUIDORES
// ============================================================
function CRMDistribuidores({ onNav, empresaAtual }) {
  const s = useDistribuidoresList(DISTS_SEED);
  const [mapaAberto, setMapaAberto] = useCrmState(false);
  const [showArchived, setShowArchived] = React.useState(false);
  const blank = { nome: "", tipoPessoa: "PJ", cnpj: "", cpf: "", geral_cidade: "", geral_uf: "", resp: "", fone: "", celular: "", email: "", saloes: 0, fat: 0, status: "Bronze", uf: "", desde: "", situacao: "Onboarding", tiposContato: ["Distribuidor"], territorio: [], marcas: [] };

  const empresaNome = (empresaAtual && !empresaAtual.principal)
    ? (empresaAtual.nome_fantasia || empresaAtual.razao_social || null)
    : null;

  const allRows = s.rows
    .map((r, origIdx) => ({ ...r, _origIdx: origIdx }))
    .filter(r => !empresaNome
      || !r.marcas || r.marcas.length === 0
      || r.marcas.includes(empresaNome));

  const archivedCount = allRows.filter(r => r.situacao === 'Arquivado').length;
  const filteredRows = showArchived ? allRows : allRows.filter(r => r.situacao !== 'Arquivado');
  const activeRows = allRows.filter(r => r.situacao !== 'Arquivado');

  if (s.edit) {
    return (
      <BizForm kind="dist" state={s.edit} set={s.set}
        onCancel={s.close} onSave={s.save} onDelete={() => s.remove(s.edit.idx)} />
    );
  }

  if (mapaAberto) {
    return <MapaDistribuidores rows={activeRows} onClose={() => setMapaAberto(false)} />;
  }

  return (
    <div className="canvas">
      <PageHead title="Distribuidores" sub={empresaNome ? `${empresaNome} · Parceiros B2B com tabela própria e território exclusivo` : "Parceiros B2B com tabela própria e território exclusivo"}
        right={<><Button variant="secondary" icon="map" size="sm" onClick={() => setMapaAberto(true)}>Ver mapa</Button>
                  <Button variant="primary" icon="plus" size="sm" onClick={() => s.open("new", null, { ...blank, marcas: empresaNome ? [empresaNome] : [] })}>Novo distribuidor</Button></>}/>
      <CRMTabs active="distribuidores" onNav={onNav} counts={{ distribuidores: activeRows.length }} />

      {activeRows.length > 0 && (
        <div className="grid-4" style={{ marginBottom: 16 }}>
          <KpiMini lbl="Distribuidores ativos" v={String(activeRows.filter(r => r.situacao === "Ativo").length)} sub={`${activeRows.filter(r => r.situacao === "Onboarding").length} em onboarding`} />
          <KpiMini lbl="Salões atendidos (rede)" v={String(activeRows.reduce((a, r) => a + (r.saloes || 0), 0))} sub="total na rede" />
          <KpiMini lbl="Faturamento agregado" v={`R$ ${brl(activeRows.reduce((a, r) => a + (r.fat || 0), 0))}`} sub="acumulado" />
          <KpiMini lbl="Cobertura geográfica" v={`${new Set(activeRows.map(r => r.geral_uf).filter(Boolean)).size} UFs`} sub="regiões cobertas" />
        </div>
      )}

      <Card>
        {filteredRows.length === 0 && archivedCount === 0 ? (
          <CRMEmpty
            icon="building-2"
            title="Nenhum distribuidor cadastrado"
            sub={"Adicione distribuidores B2B para gerenciar\nterritórios, tiers e faturamento."}
            action={<Button variant="primary" icon="plus" size="sm" onClick={() => s.open("new", null, { ...blank, marcas: empresaNome ? [empresaNome] : [] })}>Novo distribuidor</Button>}
          />
        ) : (
          <>
            <Toolbar search="Buscar distribuidor, CNPJ, território…" filters={["Todos", "Tier", "UF", "Em onboarding"]}
              right={<ArchiveToggle show={showArchived} setShow={setShowArchived} archivedCount={archivedCount} />} />
            <table className="tbl">
              <thead><tr><th>Distribuidor</th><th>CPF / CNPJ</th><th>Responsável</th><th>Cidade</th><th className="num right">Salões na rede</th><th className="num right">Faturamento</th><th>Tier</th><th></th></tr></thead>
              <tbody>
                {filteredRows.map((d) => {
                  const isArchived = d.situacao === 'Arquivado';
                  return (
                  <tr key={d._origIdx} className="clickable" onClick={() => s.open("edit", d._origIdx)} style={isArchived ? { opacity: 0.55 } : undefined}>
                    <td>
                      <div>
                        <div style={{ fontWeight: 500 }}>{d.nome} {isArchived && <Badge tone="neutral">Arquivado</Badge>}</div>
                        {d.marcas && d.marcas.length > 0 && (
                          <div className="muted" style={{ fontSize: 11 }}>{d.marcas.join(' · ')}</div>
                        )}
                      </div>
                    </td>
                    <td><span className="ref-mono">{d.tipoPessoa === "PF" ? d.cpf : d.cnpj}</span></td>
                    <td>{d.resp}</td>
                    <td>{d.cidade}</td>
                    <td className="num right">{d.saloes}</td>
                    <td className="num right">R$ {brl(d.fat)}</td>
                    <td><Badge tone={d.status === "Ouro" ? "brand" : d.status === "Prata" ? "neutral" : "warning"}>{d.status}</Badge></td>
                    <td><RowActions onEdit={() => s.open("edit", d._origIdx)} onDelete={() => s.remove(d._origIdx)} onArchive={() => s.archive(d._origIdx)} onUnarchive={() => s.unarchive(d._origIdx)} archived={isArchived} /></td>
                  </tr>
                  );
                })}
              </tbody>
            </table>
            <FooterPager total={filteredRows.length} from={1} to={filteredRows.length} />
          </>
        )}
      </Card>
    </div>
  );
}

// ============================================================
// REPRESENTANTES
// ============================================================
function CRMRepresentantes({ onNav }) {
  const s = useRepresentantesList(REPS_SEED);
  const [showArchived, setShowArchived] = React.useState(false);
  const blank = { nome: "", regiao: "", email: "", celular: "", fone: "", saloes: 0, meta: 0, atual: 0, comissao: 4, cpf: "", admissao: "", ufs: [], contrato: "PJ", situacao: "Ativo" };

  const archivedCount = s.rows.filter(r => r.situacao === 'Arquivado').length;
  const visibleRows = showArchived ? s.rows : s.rows.filter(r => r.situacao !== 'Arquivado');
  const activeCount = s.rows.filter(r => r.situacao !== 'Arquivado').length;

  if (s.edit) {
    return (
      <RepresentanteForm state={s.edit} set={s.set}
        onCancel={s.close} onSave={s.save} onDelete={() => s.remove(s.edit.idx)} />
    );
  }

  return (
    <div className="canvas">
      <PageHead title="Representantes Comerciais" sub="Time externo · metas, comissões e cobertura"
        right={<><Button variant="secondary" icon="trophy" size="sm">Ranking</Button>
                  <Button variant="primary" icon="user-plus" size="sm" onClick={() => s.open("new", null, blank)}>Novo representante</Button></>}/>
      <CRMTabs active="representantes" onNav={onNav} counts={{ representantes: activeCount }} />

      {visibleRows.length === 0 && archivedCount === 0 ? (
        <div className="card" style={{ marginTop: 4 }}>
          <CRMEmpty
            icon="user-cog"
            title="Nenhum representante cadastrado"
            sub={"Adicione representantes comerciais para acompanhar\nmetas, comissões e cobertura de território."}
            action={<Button variant="primary" icon="user-plus" size="sm" onClick={() => s.open("new", null, blank)}>Novo representante</Button>}
          />
        </div>
      ) : (
        <>
          <div style={{ marginBottom: 12, display: 'flex', justifyContent: 'flex-end' }}>
            <ArchiveToggle show={showArchived} setShow={setShowArchived} archivedCount={archivedCount} />
          </div>
          <div className="grid-3">
            {visibleRows.map((r, i) => {
              const origIdx = s.rows.indexOf(r);
              const pct = r.meta ? r.atual / r.meta : 0;
              const tone = pct >= 1 ? "var(--tm-success)" : pct >= 0.75 ? "var(--tm-brand-champagne)" : "var(--tm-warning)";
              const isArchived = r.situacao === 'Arquivado';
              return (
                <div key={origIdx} className="card rep-card" style={{ padding: 18, opacity: isArchived ? 0.55 : 1 }} onClick={() => s.open("edit", origIdx)}>
                  <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                    <div className="avatar md">{r.nome[0]}</div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontWeight: 500, fontSize: 14 }}>{r.nome} {isArchived && <Badge tone="neutral">Arquivado</Badge>}</div>
                      <div className="muted" style={{ fontSize: 11.5 }}>{r.regiao}</div>
                    </div>
                    <Badge tone={pct >= 1 ? "success" : "neutral"}>{Math.round(pct * 100)}%</Badge>
                  </div>
                  <div style={{ marginTop: 14 }}>
                    <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11.5, color: "var(--tm-fg-3)" }}>
                      <span>Atingido</span>
                      <span className="num">R$ {brl(r.atual)} / R$ {brl(r.meta)}</span>
                    </div>
                    <div style={{ marginTop: 6, height: 6, background: "var(--tm-bg-3)", borderRadius: 3, overflow: "hidden" }}>
                      <div style={{ width: `${Math.min(pct, 1) * 100}%`, height: "100%", background: tone }} />
                    </div>
                  </div>
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 14, fontSize: 11.5 }}>
                    <span className="muted">{r.saloes} salões ativos · Comissão {r.comissao}%</span>
                    <span className="row-actions" style={{ opacity: 1 }} onClick={(e) => e.stopPropagation()}>
                      <button className="icon-btn" title="Editar" onClick={() => s.open("edit", origIdx)}><Icon name="pencil" size={14} /></button>
                      {isArchived ? (
                        <button className="icon-btn" title="Restaurar" onClick={() => s.unarchive(origIdx)} style={{ color: 'var(--tm-success)' }}><Icon name="rotate-ccw" size={14} /></button>
                      ) : (
                        <button className="icon-btn" title="Arquivar" onClick={() => s.archive(origIdx)} style={{ color: 'var(--tm-warning)' }}><Icon name="archive" size={14} /></button>
                      )}
                      <button className="icon-btn danger" title="Excluir permanentemente" onClick={() => s.remove(origIdx)}><Icon name="trash-2" size={14} /></button>
                    </span>
                  </div>
                </div>
              );
            })}
          </div>
        </>
      )}
    </div>
  );
}

// ============================================================
// Shared row-action buttons (replaces kebab placeholder)
// ============================================================
function RowActions({ onEdit, onDelete, onArchive, onUnarchive, archived }) {
  return (
    <span className="row-actions" onClick={(e) => e.stopPropagation()}>
      <button className="icon-btn" title="Editar" onClick={onEdit}>
        <Icon name="pencil" size={14} />
      </button>
      {archived ? (
        <button className="icon-btn" title="Restaurar" onClick={onUnarchive} style={{ color: 'var(--tm-success)' }}>
          <Icon name="rotate-ccw" size={14} />
        </button>
      ) : (
        <button className="icon-btn" title="Arquivar" onClick={onArchive} style={{ color: 'var(--tm-warning)' }}>
          <Icon name="archive" size={14} />
        </button>
      )}
      <button className="icon-btn danger" title="Excluir permanentemente" onClick={onDelete}>
        <Icon name="trash-2" size={14} />
      </button>
    </span>
  );
}

// ============================================================
// Shared sub-components (kept for compatibility w/ other modules)
// ============================================================
function CRMTabs({ active, onNav, counts = {} }) {
  const tabs = [
    { id: "clientes-finais", label: "Clientes Finais" },
    { id: "saloes", label: "Salões / Barbearias" },
    { id: "distribuidores", label: "Distribuidores" },
    { id: "representantes", label: "Representantes" },
  ];
  return (
    <div className="tabs">
      {tabs.map(t => {
        const n = counts[t.id];
        return (
          <div key={t.id}
               className={`tab ${active === t.id ? "active" : ""}`}
               onClick={() => onNav(`crm/${t.id}`)}>
            {t.label}
            {n != null && <span className="muted" style={{ marginLeft: 4 }}>({n})</span>}
          </div>
        );
      })}
    </div>
  );
}

function PageHead({ title, sub, right }) {
  return (
    <div className="page-head">
      <div>
        <div className="page-title">{title}</div>
        {sub && <div className="page-sub">{sub}</div>}
      </div>
      {right && <div style={{ display: "flex", gap: 10 }}>{right}</div>}
    </div>
  );
}

function ToolbarFilterChip({ fo, sel, isOpen, onToggle, onSelect, onClear }) {
  const chipRef = React.useRef(null);
  const [pos, setPos] = React.useState({ top: 0, left: 0 });

  React.useEffect(() => {
    if (isOpen && chipRef.current) {
      const r = chipRef.current.getBoundingClientRect();
      const dropW = 200;
      let left = r.left;
      // If dropdown would overflow right edge, align to right side of chip
      if (left + dropW > window.innerWidth - 16) {
        left = r.right - dropW;
      }
      setPos({ top: r.bottom + 6, left: Math.max(8, left) });
    }
  }, [isOpen]);

  return (
    <div>
      <span
        ref={chipRef}
        className={`chip ${sel ? "active" : ""}`}
        style={{ cursor: "pointer", userSelect: "none", display: "inline-flex", alignItems: "center", gap: 4 }}
        onClick={onToggle}
      >
        {sel || fo.label}
        {sel ? (
          <span
            style={{ fontWeight: 700, lineHeight: 1, fontSize: 14, opacity: 0.7 }}
            onClick={(e) => { e.stopPropagation(); onClear(); }}
          >×</span>
        ) : (
          <Icon name="chevron-down" size={11} />
        )}
      </span>
      {isOpen && fo.options.length > 0 && ReactDOM.createPortal(
        <div style={{
          position: "fixed", top: pos.top, left: pos.left, zIndex: 99999,
          background: "var(--tm-bg-2)", border: "1px solid var(--tm-line-1)",
          borderRadius: 8, minWidth: 180, padding: "4px 0",
          boxShadow: "0 8px 24px rgba(0,0,0,0.35)",
          maxHeight: 260, overflowY: "auto",
        }}>
          {fo.options.map(opt => (
            <div
              key={opt}
              onClick={() => onSelect(opt)}
              style={{
                padding: "8px 14px", fontSize: 13, cursor: "pointer",
                color: opt === sel ? "var(--tm-brand-champagne)" : "var(--tm-fg-1)",
                background: opt === sel ? "rgba(201,163,107,0.08)" : "transparent",
              }}
              onMouseEnter={(e) => { e.currentTarget.style.background = "var(--tm-bg-3)"; }}
              onMouseLeave={(e) => { e.currentTarget.style.background = opt === sel ? "rgba(201,163,107,0.08)" : "transparent"; }}
            >{opt}</div>
          ))}
        </div>,
        document.body
      )}
      {isOpen && fo.options.length === 0 && ReactDOM.createPortal(
        <div style={{
          position: "fixed", top: pos.top, left: pos.left, zIndex: 99999,
          background: "var(--tm-bg-2)", border: "1px solid var(--tm-line-1)",
          borderRadius: 8, minWidth: 160, padding: "12px 14px",
          boxShadow: "0 8px 24px rgba(0,0,0,0.35)",
          fontSize: 12.5, color: "var(--tm-fg-4)", textAlign: "center",
        }}>
          Nenhuma opção disponível
        </div>,
        document.body
      )}
    </div>
  );
}

function ToolbarVisDropdown() {
  const [open, setOpen] = React.useState(false);
  const [density, setDensity] = React.useState('normal');
  const [zebra, setZebra] = React.useState(false);
  const btnRef = React.useRef(null);
  const [pos, setPos] = React.useState({ top: 0, right: 0 });

  React.useEffect(() => {
    if (!open) return;
    const handler = (e) => {
      if (btnRef.current && btnRef.current.contains(e.target)) return;
      const portal = e.target.closest('div[data-vis-dropdown]');
      if (portal) return;
      setOpen(false);
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [open]);

  // Apply density to nearest .tbl
  React.useEffect(() => {
    const card = btnRef.current?.closest('.card');
    const tbl = card?.querySelector('.tbl');
    if (!tbl) return;
    tbl.classList.remove('density-compact', 'density-comfortable');
    if (density === 'compact')     tbl.classList.add('density-compact');
    if (density === 'comfortable') tbl.classList.add('density-comfortable');
  }, [density]);

  // Apply zebra stripe
  React.useEffect(() => {
    const card = btnRef.current?.closest('.card');
    const tbl = card?.querySelector('.tbl');
    if (!tbl) return;
    tbl.classList.toggle('tbl-zebra', zebra);
  }, [zebra]);

  const handleOpen = () => {
    if (!open && btnRef.current) {
      const r = btnRef.current.getBoundingClientRect();
      setPos({ top: r.bottom + 6, right: window.innerWidth - r.right });
    }
    setOpen(o => !o);
  };

  const densityOpts = [
    { key: 'compact',     label: 'Compacto',     icon: 'rows-3' },
    { key: 'normal',      label: 'Normal',        icon: 'rows-4' },
    { key: 'comfortable', label: 'Confortável',  icon: 'square-menu' },
  ];

  return (
    <>
      <button ref={btnRef} className="btn ghost sm" onClick={handleOpen}>
        <Icon name="sliders-horizontal" size={14} />
        Visualização
      </button>
      {open && ReactDOM.createPortal(
        <div data-vis-dropdown="true" style={{
          position: 'fixed', top: pos.top, right: pos.right, zIndex: 999,
          background: 'var(--tm-bg-1)', border: '1px solid var(--tm-line-1)',
          borderRadius: 10, padding: '12px 0', minWidth: 220,
          boxShadow: '0 8px 24px rgba(0,0,0,.28)',
        }}>
          <div style={{ padding: '0 14px 8px', fontSize: 11, fontWeight: 600, color: 'var(--tm-fg-3)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>
            Densidade
          </div>
          {densityOpts.map(d => (
            <div
              key={d.key}
              onClick={() => setDensity(d.key)}
              style={{
                display: 'flex', alignItems: 'center', gap: 10,
                padding: '7px 14px', cursor: 'pointer', fontSize: 13,
                color: density === d.key ? 'var(--tm-brand-champagne)' : 'var(--tm-fg-2)',
                background: density === d.key ? 'var(--tm-bg-2)' : 'transparent',
                transition: 'background .12s',
              }}
              onMouseEnter={e => { if (density !== d.key) e.currentTarget.style.background = 'var(--tm-bg-2)'; }}
              onMouseLeave={e => { if (density !== d.key) e.currentTarget.style.background = 'transparent'; }}
            >
              <Icon name={d.icon} size={14} />
              <span>{d.label}</span>
              {density === d.key && <Icon name="check" size={14} style={{ marginLeft: 'auto' }} />}
            </div>
          ))}
          <div style={{ borderTop: '1px solid var(--tm-line-1)', margin: '8px 0' }} />
          <div
            onClick={() => setZebra(z => !z)}
            style={{
              display: 'flex', alignItems: 'center', gap: 10,
              padding: '7px 14px', cursor: 'pointer', fontSize: 13,
              color: 'var(--tm-fg-2)', transition: 'background .12s',
            }}
            onMouseEnter={e => e.currentTarget.style.background = 'var(--tm-bg-2)'}
            onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
          >
            <Icon name="rows-3" size={14} />
            <span>Linhas alternadas</span>
            <div style={{
              marginLeft: 'auto', width: 32, height: 18, borderRadius: 10,
              background: zebra ? 'var(--tm-brand-champagne)' : 'var(--tm-bg-3)',
              transition: 'background .15s', position: 'relative', cursor: 'pointer',
            }}>
              <div style={{
                position: 'absolute', top: 2, left: zebra ? 16 : 2,
                width: 14, height: 14, borderRadius: '50%',
                background: zebra ? '#1a1a1a' : 'var(--tm-fg-4)',
                transition: 'left .15s',
              }} />
            </div>
          </div>
        </div>,
        document.body
      )}
    </>
  );
}

function Toolbar({ search, filters, onSearch, filterOpts, filterValues, onFilter, viewMode, onViewMode, right }) {
  const { useState: useTbS, useEffect: useTbE, useRef: useTbR } = React;
  const [openKey, setOpenKey] = useTbS(null);
  const ref = useTbR(null);

  useTbE(() => {
    if (!openKey) return;
    const handler = (e) => {
      // Ignore clicks inside the toolbar
      if (ref.current && ref.current.contains(e.target)) return;
      // Ignore clicks inside portal dropdowns (fixed position, appended to body)
      const portal = e.target.closest('div[style*="position: fixed"]');
      if (portal && portal.parentElement === document.body) return;
      setOpenKey(null);
    };
    document.addEventListener("mousedown", handler);
    return () => document.removeEventListener("mousedown", handler);
  }, [openKey]);

  return (
    <div className="toolbar" ref={ref}>
      <div className="search">
        <Icon name="search" size={14} />
        <input
          placeholder={search}
          onChange={onSearch ? (e) => onSearch(e.target.value) : undefined}
        />
      </div>
      {!filterOpts && (filters || []).map((f, i) => (
        <span key={i} className="chip">{f} <Icon name="chevron-down" size={12} /></span>
      ))}
      {filterOpts && filterOpts.map(fo => (
        <ToolbarFilterChip
          key={fo.key}
          fo={fo}
          sel={(filterValues && filterValues[fo.key]) || ""}
          isOpen={openKey === fo.key}
          onToggle={() => setOpenKey(openKey === fo.key ? null : fo.key)}
          onSelect={(val) => { onFilter(fo.key, val); setOpenKey(null); }}
          onClear={() => { onFilter(fo.key, ""); setOpenKey(null); }}
        />
      ))}
      <div className="spacer" />
      {onViewMode && (
        <div style={{ display: "flex", gap: 2, background: "var(--tm-bg-3)", borderRadius: 7, padding: 2 }}>
          <button
            title="Visualização em tabela"
            onClick={() => onViewMode("tabela")}
            style={{
              display: "flex", alignItems: "center", justifyContent: "center",
              width: 28, height: 28, borderRadius: 5, border: "none", cursor: "pointer",
              background: viewMode !== "grade" ? "var(--tm-bg-2)" : "transparent",
              color: viewMode !== "grade" ? "var(--tm-brand-champagne)" : "var(--tm-fg-3)",
              boxShadow: viewMode !== "grade" ? "0 1px 3px rgba(0,0,0,0.2)" : "none",
              transition: "all 0.15s",
            }}>
            <Icon name="list" size={14} />
          </button>
          <button
            title="Visualização em grade"
            onClick={() => onViewMode("grade")}
            style={{
              display: "flex", alignItems: "center", justifyContent: "center",
              width: 28, height: 28, borderRadius: 5, border: "none", cursor: "pointer",
              background: viewMode === "grade" ? "var(--tm-bg-2)" : "transparent",
              color: viewMode === "grade" ? "var(--tm-brand-champagne)" : "var(--tm-fg-3)",
              boxShadow: viewMode === "grade" ? "0 1px 3px rgba(0,0,0,0.2)" : "none",
              transition: "all 0.15s",
            }}>
            <Icon name="layout-grid" size={14} />
          </button>
        </div>
      )}
      {!onViewMode && (
        <ToolbarVisDropdown />
      )}
      {right && right}
    </div>
  );
}

function KpiMini({ lbl, v, sub }) {
  return (
    <div className="kpi-mini">
      <div className="lbl">{lbl}</div>
      <div className="val">{v}</div>
      <div className="sub">{sub}</div>
    </div>
  );
}

function FooterPager({ total, perPage, page, onPage }) {
  const pp = perPage || 10;
  const totalPages = Math.max(1, Math.ceil(total / pp));
  const cur = Math.min(Math.max(page || 1, 1), totalPages);
  const from = total === 0 ? 0 : (cur - 1) * pp + 1;
  const to = Math.min(cur * pp, total);

  // Build page numbers to show (max 5 visible)
  const pages = [];
  let start = Math.max(1, cur - 2);
  let end = Math.min(totalPages, start + 4);
  if (end - start < 4) start = Math.max(1, end - 4);
  for (let i = start; i <= end; i++) pages.push(i);

  const go = (p) => { if (onPage && p >= 1 && p <= totalPages && p !== cur) onPage(p); };

  return (
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 20px", borderTop: "1px solid var(--tm-line-1)", fontSize: 12, color: "var(--tm-fg-3)" }}>
      <span>Exibindo {from}–{to} de {total}</span>
      {totalPages > 1 && (
        <div style={{ display: "flex", gap: 4 }}>
          <span className="chip" style={{ cursor: cur > 1 ? 'pointer' : 'default', opacity: cur > 1 ? 1 : 0.4 }} onClick={() => go(cur - 1)}>‹</span>
          {pages.map(p => (
            <span key={p} className={`chip${p === cur ? ' active' : ''}`} style={{ cursor: p === cur ? 'default' : 'pointer' }} onClick={() => go(p)}>{p}</span>
          ))}
          <span className="chip" style={{ cursor: cur < totalPages ? 'pointer' : 'default', opacity: cur < totalPages ? 1 : 0.4 }} onClick={() => go(cur + 1)}>›</span>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { CRMClientes, CRMSaloes, CRMDistribuidores, CRMRepresentantes, PageHead, Toolbar, KpiMini, FooterPager });
