/* Bell de notificaciones, panel de webhooks, CSV import, PDF export. */

function NotificationBell({ user }) {
  const [list, setList] = React.useState([]);
  const [open, setOpen] = React.useState(false);
  const unread = list.filter(n => !n.leida).length;

  React.useEffect(() => {
    reload();
    const stop = window.useWS(m => {
      if (m.type === 'notificacion') reload();
    });
    return stop;
  }, []);

  function reload() { window.API.listNotificaciones().then(setList); }

  async function markAll() {
    await window.API.marcarTodasLeidas();
    reload();
  }

  return (
    <div style={{position:'relative'}}>
      <button onClick={()=>setOpen(!open)}
        style={{position:'relative',width:36,height:36,borderRadius:9,background:'#f1f5f9',border:'none',cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center'}}>
        <span style={{fontSize:16}}>🔔</span>
        {unread > 0 && <span style={{position:'absolute',top:-2,right:-2,background:'#ef4444',color:'#fff',borderRadius:99,fontSize:10,fontWeight:800,padding:'1px 5px',minWidth:16,textAlign:'center'}}>{unread}</span>}
      </button>
      {open && (
        <>
          <div onClick={()=>setOpen(false)} style={{position:'fixed',inset:0,zIndex:900}} />
          <div style={{position:'absolute',top:'calc(100% + 8px)',right:0,width:340,maxHeight:480,overflowY:'auto',background:'#fff',borderRadius:12,boxShadow:'0 8px 32px rgba(0,0,0,0.15)',border:'1px solid #e2e8f0',zIndex:901}}>
            <div style={{padding:'12px 16px',borderBottom:'1px solid #f1f5f9',display:'flex',justifyContent:'space-between',alignItems:'center'}}>
              <div style={{fontSize:13,fontWeight:700,color:'#0f172a'}}>Notificaciones</div>
              {unread > 0 && <button onClick={markAll} style={{background:'none',border:'none',color:'#2563eb',fontSize:11,cursor:'pointer',fontWeight:600}}>Marcar todo leído</button>}
            </div>
            {list.length === 0 && <div style={{padding:'30px 16px',textAlign:'center',color:'#94a3b8',fontSize:13}}>Sin notificaciones</div>}
            {list.map(n => (
              <div key={n.id} style={{padding:'10px 14px',borderBottom:'1px solid #f8fafc',background:n.leida?'#fff':'#eff6ff',cursor:'pointer'}}>
                <div style={{display:'flex',alignItems:'center',gap:6,marginBottom:2}}>
                  {!n.leida && <span style={{width:6,height:6,borderRadius:99,background:'#2563eb'}}/>}
                  <span style={{fontSize:12,fontWeight:700,color:'#0f172a'}}>{n.titulo}</span>
                </div>
                {n.mensaje && <div style={{fontSize:11,color:'#64748b'}}>{n.mensaje}</div>}
                <div style={{fontSize:10,color:'#94a3b8',marginTop:3}}>{DB.timeAgo(n.creada)}</div>
              </div>
            ))}
          </div>
        </>
      )}
    </div>
  );
}

const EVENTOS_DISPONIBLES = [
  { id:'ticket.creado',              label:'Ticket creado' },
  { id:'ticket.creado_por_cliente',  label:'Ticket creado por cliente' },
  { id:'ticket.resuelto',            label:'Ticket resuelto' },
  { id:'usuario.creado',             label:'Usuario del sistema creado' },
];

function WebhooksPanel({ toast }) {
  const [list, setList] = React.useState([]);
  const [showAdd, setShowAdd] = React.useState(false);
  const [editing, setEditing] = React.useState(null);

  React.useEffect(reload, []);
  function reload() { window.API.listWebhooks().then(setList); }

  return (
    <div>
      <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:14}}>
        <div>
          <div style={{fontSize:14,fontWeight:700,color:'#0f172a',marginBottom:2}}>Webhooks salientes</div>
          <div style={{fontSize:11,color:'#64748b'}}>Reenvía eventos a n8n, Slack, Discord, tu propio servicio…</div>
        </div>
        <Btn size="sm" onClick={()=>setShowAdd(true)}>+ Nuevo webhook</Btn>
      </div>
      <Card style={{padding:0}}>
        <table style={{width:'100%',borderCollapse:'collapse',fontSize:13}}>
          <thead style={{background:'#f8fafc',fontWeight:700,color:'#64748b',textTransform:'uppercase',fontSize:11}}>
            <tr>
              <th style={{textAlign:'left',padding:'10px 14px'}}>Nombre</th>
              <th style={{textAlign:'left',padding:'10px 14px'}}>URL</th>
              <th style={{textAlign:'left',padding:'10px 14px'}}>Eventos</th>
              <th style={{textAlign:'left',padding:'10px 14px'}}>Último</th>
              <th style={{textAlign:'right',padding:'10px 14px'}}></th>
            </tr>
          </thead>
          <tbody>
            {list.map(w => (
              <tr key={w.id} style={{borderTop:'1px solid #f1f5f9'}}>
                <td style={{padding:'10px 14px',fontWeight:600}}>{w.nombre}{!w.activo && <Badge label="inactivo" color="slate"/>}</td>
                <td style={{padding:'10px 14px',fontSize:11,color:'#64748b',maxWidth:260,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{w.url}</td>
                <td style={{padding:'10px 14px',fontSize:11}}>{w.eventos.map(e=><span key={e} style={{display:'inline-block',background:'#e0e7ff',color:'#3730a3',padding:'1px 6px',borderRadius:4,marginRight:3,marginBottom:2}}>{e}</span>)}</td>
                <td style={{padding:'10px 14px',fontSize:11,color:'#94a3b8'}}>
                  {w.ultimo_disparo ? <>{DB.timeAgo(w.ultimo_disparo)} · {w.ultimo_status?<span style={{color:w.ultimo_status<400?'#10b981':'#dc2626'}}>HTTP {w.ultimo_status}</span>:<span style={{color:'#dc2626'}}>error</span>}</> : '—'}
                  <div style={{fontSize:10}}>{w.total_disparos} disparos / {w.total_errores} errores</div>
                </td>
                <td style={{padding:'10px 14px',textAlign:'right'}}>
                  <Btn size="sm" variant="secondary" onClick={async()=>{await window.API.testWebhook(w.id); toast('Webhook disparado'); reload();}}>Test</Btn>
                  <Btn size="sm" variant="secondary" style={{marginLeft:6}} onClick={()=>setEditing(w)}>Editar</Btn>
                  <Btn size="sm" variant="danger" style={{marginLeft:6}} onClick={async()=>{if(confirm('¿Borrar webhook?')){await window.API.deleteWebhook(w.id); reload();}}}>Borrar</Btn>
                </td>
              </tr>
            ))}
            {list.length===0 && <tr><td colSpan={5} style={{padding:'30px',textAlign:'center',color:'#94a3b8',fontSize:13}}>Sin webhooks configurados</td></tr>}
          </tbody>
        </table>
      </Card>
      {showAdd && <WebhookForm onSave={async f=>{await window.API.createWebhook(f); reload(); setShowAdd(false); toast('Webhook creado');}} onCancel={()=>setShowAdd(false)} />}
      {editing && <WebhookForm initial={editing} onSave={async f=>{await window.API.updateWebhook(editing.id,f); reload(); setEditing(null); toast('Actualizado');}} onCancel={()=>setEditing(null)} />}
    </div>
  );
}

function WebhookForm({ initial = {}, onSave, onCancel }) {
  const [f, setF] = React.useState({
    nombre: initial.nombre || '', url: initial.url || '',
    eventos: initial.eventos || [], secret: initial.secret || '',
    activo: initial.activo !== false,
  });
  return (
    <Modal title={initial.id?`Editar ${initial.nombre}`:'Nuevo webhook'} onClose={onCancel}>
      <div style={{display:'flex',flexDirection:'column',gap:12}}>
        <Field label="Nombre" value={f.nombre} onChange={v=>setF({...f,nombre:v})} placeholder="Slack #soporte" />
        <Field label="URL" value={f.url} onChange={v=>setF({...f,url:v})} placeholder="https://hooks.slack.com/..." />
        <div>
          <label style={{fontSize:11,fontWeight:700,color:'#64748b',textTransform:'uppercase',display:'block',marginBottom:6}}>Eventos</label>
          <div style={{display:'flex',flexDirection:'column',gap:6}}>
            {EVENTOS_DISPONIBLES.map(e => (
              <label key={e.id} style={{display:'flex',alignItems:'center',gap:8,fontSize:13,padding:'4px 0'}}>
                <input type="checkbox" checked={f.eventos.includes(e.id)} onChange={ev=>{
                  setF(p=>({...p, eventos: ev.target.checked ? [...p.eventos,e.id] : p.eventos.filter(x=>x!==e.id)}));
                }} />
                <code style={{background:'#f1f5f9',padding:'1px 6px',borderRadius:3,fontSize:11}}>{e.id}</code>
                <span>{e.label}</span>
              </label>
            ))}
          </div>
        </div>
        <Field label="Secret HMAC (opcional)" value={f.secret} onChange={v=>setF({...f,secret:v})} hint="Se firma cada request con HMAC-SHA256 en x-iti-signature" />
        <label style={{display:'flex',alignItems:'center',gap:8,fontSize:13}}>
          <input type="checkbox" checked={f.activo} onChange={e=>setF({...f,activo:e.target.checked})} /> Activo
        </label>
        <div style={{display:'flex',gap:8,justifyContent:'flex-end',marginTop:6}}>
          <Btn size="sm" variant="secondary" onClick={onCancel}>Cancelar</Btn>
          <Btn size="sm" onClick={()=>onSave(f)} disabled={!f.nombre||!f.url||f.eventos.length===0}>Guardar</Btn>
        </div>
      </div>
    </Modal>
  );
}

// Imprime un sticker imprimible para pegar en la PC del usuario
async function loadQRLib() {
  if (window.qrcode) return;
  await new Promise((res, rej) => {
    const s = document.createElement('script');
    s.src = 'https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js';
    s.onload = res; s.onerror = rej;
    document.head.appendChild(s);
  });
}

function makeQRSvg(text, modulesPerSide = 4) {
  const qr = window.qrcode(0, 'M');
  qr.addData(text); qr.make();
  return qr.createSvgTag(modulesPerSide, 4);
}

window.imprimirSticker = async function (user, empresa) {
  const portalUrl = location.origin + '/?portal=1';
  let waUrl = portalUrl;
  let waNumber = '', waTemplate = '';
  try {
    const s = await window.API.getSettingsPublic();
    waNumber = s.wa_number || '';
    waTemplate = s.wa_template || 'Hola, soy {nombre}. ID: {sticker} PIN: {pin}';
  } catch {}
  if (waNumber) {
    const num = waNumber.replace(/[^0-9]/g, '');
    const text = waTemplate
      .replace('{sticker}', user.stickerId)
      .replace('{pin}', user.pin)
      .replace('{nombre}', user.name)
      .replace('{empresa}', empresa?.name || '');
    waUrl = `https://wa.me/${num}?text=${encodeURIComponent(text)}`;
  }

  await loadQRLib();
  const qrSvg = makeQRSvg(waUrl, 3);

  const html = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Sticker · ${user.name}</title>
  <style>
    @page { size: 80mm 50mm; margin: 0; }
    body { margin:0; padding:0; font-family: -apple-system, "Plus Jakarta Sans", sans-serif; background:#f5f5f7; }
    .sticker { width: 80mm; height: 50mm; padding: 3mm 4mm; background: #fff; border:2px dashed #fb923c; border-radius:4mm; display:flex; gap:3mm; box-sizing:border-box; }
    .left { flex:1; display:flex; flex-direction:column; min-width:0; }
    .right { width:30mm; display:flex; flex-direction:column; align-items:center; justify-content:center; }
    .right svg { width: 100%; height: auto; max-width: 28mm; }
    .header { display:flex; align-items:center; justify-content:space-between; margin-bottom:1mm; }
    .brand { font-size:8pt; font-weight:900; color:#0f172a; letter-spacing:0.05em; }
    .brand-sub { font-size:5pt; color:#64748b; }
    .empresa { font-size:6pt; color:#475569; font-weight:600; }
    .nombre { font-size:7.5pt; color:#0f172a; font-weight:700; margin-bottom:1mm; }
    .codes { display:flex; gap:2mm; margin-top:auto; }
    .code-box { flex:1; background: linear-gradient(135deg,#fff7ed,#ffedd5); border-radius:1.5mm; padding:1mm 1.5mm; }
    .code-label { font-size:4.5pt; font-weight:700; color:#9a3412; text-transform:uppercase; letter-spacing:0.08em; }
    .code-value { font-size:11pt; font-weight:900; color:#0f172a; font-family:"SF Mono",monospace; letter-spacing:0.15em; line-height:1; margin-top:0.5mm; }
    .qr-label { font-size:5pt; color:#0f172a; font-weight:700; text-align:center; margin-top:1mm; line-height:1.1; }
    .controls { padding:14px; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.1); margin-bottom:10px; display:flex; gap:8px; align-items:center; }
    .btn { padding:8px 14px; background:#2563eb; color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:13px; font-weight:600; font-family:inherit; }
    @media print { .controls { display:none; } body { background:#fff; padding:0 !important; } }
  </style></head><body>
  <div class="controls">
    <button class="btn" onclick="window.print()">🖨 Imprimir</button>
    <span style="font-size:12px;color:#64748b">80×50mm — escanea con la cámara: abre WhatsApp con tu ID y PIN listos para enviar.${waNumber?'':' <b style=\"color:#dc2626\">Configura el número de WhatsApp en Sistema → Configuración antes de imprimir.</b>'}</span>
  </div>
  <div style="padding:20px; display:grid; grid-template-columns:repeat(2,80mm); gap:6mm">
  ${[1,2].map(()=>`<div class="sticker">
    <div class="left">
      <div class="header"><div><div class="brand">INFINITOS TI</div><div class="brand-sub">Soporte técnico</div></div></div>
      <div class="nombre">${user.name}</div>
      <div class="empresa">${empresa?.name || ''}</div>
      <div class="codes">
        <div class="code-box"><div class="code-label">ID</div><div class="code-value">${user.stickerId}</div></div>
        <div class="code-box"><div class="code-label">PIN</div><div class="code-value">${user.pin}</div></div>
      </div>
    </div>
    <div class="right">
      ${qrSvg}
      <div class="qr-label">${waNumber?'📲 Escanéame<br>WhatsApp':'Portal web'}</div>
    </div>
  </div>`).join('')}
  </div>
  </body></html>`;
  const w = window.open('', '_blank', 'width=820,height=560');
  w.document.write(html); w.document.close();
};

function ConfigPanel({ toast }) {
  const [s, setS] = React.useState({ wa_number:'', wa_template:'', portal_url:'' });
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    window.API.getSettings().then(rows => {
      const next = { wa_number:'', wa_template:'', portal_url:'' };
      rows.forEach(r => { next[r.clave] = typeof r.valor === 'string' ? r.valor : (r.valor ?? ''); });
      if (!next.wa_template) next.wa_template = 'Hola, soy {nombre} de {empresa}. Necesito ayuda. ID: {sticker} PIN: {pin}';
      if (!next.portal_url) next.portal_url = location.origin;
      setS(next); setLoading(false);
    });
  }, []);

  async function save(clave) {
    await window.API.saveSetting(clave, s[clave]);
    toast(`${clave} actualizado`);
  }

  if (loading) return <div style={{padding:20,color:'#94a3b8'}}>Cargando...</div>;

  return (
    <div style={{maxWidth:760}}>
      <Card style={{padding:'20px 24px',marginBottom:16}}>
        <h3 style={{margin:'0 0 4px',fontSize:15,fontWeight:700,color:'#0f172a'}}>📲 WhatsApp Bot</h3>
        <div style={{fontSize:12,color:'#64748b',marginBottom:14}}>Número y plantilla del bot que recibe tickets vía WhatsApp. Aparece también en el QR del sticker imprimible.</div>
        <Field label="Número de WhatsApp (con código país, sin +)" value={s.wa_number}
          onChange={v=>setS({...s,wa_number:v.replace(/[^0-9]/g,'')})}
          placeholder="525512345678" hint="Ej: 525512345678 para México (52 + 10 dígitos)" />
        <div style={{marginTop:8,marginBottom:8}}>
          <label style={{fontSize:11,fontWeight:700,color:'#64748b',textTransform:'uppercase',display:'block',marginBottom:5}}>Plantilla del mensaje</label>
          <textarea value={s.wa_template} onChange={e=>setS({...s,wa_template:e.target.value})} rows={2}
            style={{width:'100%',padding:'10px 12px',border:'1.5px solid #e2e8f0',borderRadius:8,fontSize:13,fontFamily:'inherit',resize:'vertical',outline:'none'}} />
          <div style={{fontSize:10,color:'#94a3b8',marginTop:4}}>Variables: <code>{`{sticker}`}</code> <code>{`{pin}`}</code> <code>{`{nombre}`}</code> <code>{`{empresa}`}</code></div>
        </div>
        <Btn size="sm" onClick={async()=>{await save('wa_number'); await save('wa_template');}}>Guardar configuración WhatsApp</Btn>
      </Card>

      <Card style={{padding:'20px 24px'}}>
        <h3 style={{margin:'0 0 4px',fontSize:15,fontWeight:700,color:'#0f172a'}}>🌐 URL pública del portal</h3>
        <div style={{fontSize:12,color:'#64748b',marginBottom:14}}>La que aparece en stickers y emails. Ej: https://infinitos.losinfinitos.com</div>
        <Field label="URL" value={s.portal_url} onChange={v=>setS({...s,portal_url:v})} />
        <div style={{marginTop:8}}>
          <Btn size="sm" onClick={()=>save('portal_url')}>Guardar URL</Btn>
        </div>
      </Card>

      <Card style={{padding:'18px 22px',marginTop:16,background:'#fff7ed',border:'1.5px dashed #fb923c'}}>
        <div style={{fontSize:13,fontWeight:700,color:'#9a3412',marginBottom:6}}>🤖 Activar el bot de WhatsApp</div>
        <div style={{fontSize:12,color:'#7c2d12',lineHeight:1.6}}>
          1. Crea un <b>API token</b> con scope "Lectura y escritura" en la pestaña <b>API tokens</b>.<br/>
          2. Pasa ese token al servicio <code>wa-bot</code> en el servidor.<br/>
          3. La primera vez, escanea el código QR de WhatsApp Web que sale en los logs del contenedor.<br/>
          4. Una vez conectado, los clientes que escaneen el QR del sticker mandarán automáticamente su <code>ID + PIN</code> al bot, y el bot atiende primer nivel: les pregunta el problema, prioridad y crea el ticket.
        </div>
      </Card>
    </div>
  );
}

// CSV import: parse simple CSV (RFC compatible básico)
window.parseCSV = function (text) {
  const rows = [];
  let cur = [], field = '', q = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i];
    if (q) {
      if (c === '"' && text[i+1] === '"') { field += '"'; i++; }
      else if (c === '"') q = false;
      else field += c;
    } else {
      if (c === '"') q = true;
      else if (c === ',') { cur.push(field); field = ''; }
      else if (c === '\n' || c === '\r') {
        if (field || cur.length) { cur.push(field); rows.push(cur); cur = []; field = ''; }
        if (c === '\r' && text[i+1] === '\n') i++;
      }
      else field += c;
    }
  }
  if (field || cur.length) { cur.push(field); rows.push(cur); }
  return rows;
};

window.importCSVUsers = async function (file, companyId, dataRef, setData, toast) {
  const text = await file.text();
  const rows = window.parseCSV(text);
  if (rows.length < 2) return toast('CSV vacío','error');
  const header = rows[0].map(h => h.trim().toLowerCase());
  const newUsers = [];
  for (let i = 1; i < rows.length; i++) {
    const row = rows[i];
    if (!row[0]) continue;
    const obj = {};
    header.forEach((h, idx) => obj[h] = row[idx] ?? '');
    newUsers.push({
      id: DB.generateId('u'),
      companyId,
      name: obj.name || obj.nombre || '',
      email: obj.email || '',
      phone: obj.phone || obj.telefono || '',
      position: obj.position || obj.puesto || '',
      anydesk: obj.anydesk || '',
      notes: obj.notes || obj.notas || '',
      equipment: {
        brand: obj.brand || obj.marca || '',
        model: obj.model || obj.modelo || '',
        serial: obj.serial || '',
        cpu: obj.cpu || '',
        ram: obj.ram || '',
        storage: obj.storage || obj.almacenamiento || '',
        os: obj.os || obj.so || '',
        ip: obj.ip || '',
        hostname: obj.hostname || '',
        monitor: obj.monitor || '',
        licenses: obj.licenses || obj.licencias || '',
      },
    });
  }
  const data = {...dataRef, users: [...(dataRef.users||[]), ...newUsers]};
  setData(data); DB.saveData(data);
  toast(`${newUsers.length} usuarios importados`);
};

// PDF export usando jsPDF
window.exportEmpresaPDF = async function (companyId, data, mes) {
  if (!window.jspdf) {
    await new Promise((res, rej) => {
      const s = document.createElement('script');
      s.src = 'https://unpkg.com/jspdf@2.5.1/dist/jspdf.umd.min.js';
      s.onload = res; s.onerror = rej;
      document.head.appendChild(s);
    });
  }
  const { jsPDF } = window.jspdf;
  const doc = new jsPDF();
  const empresa = data.companies.find(c => c.id === companyId);
  if (!empresa) return;
  const ahora = new Date();
  const mesIni = mes ? new Date(mes) : new Date(ahora.getFullYear(), ahora.getMonth(), 1);
  const mesFin = new Date(mesIni.getFullYear(), mesIni.getMonth()+1, 0, 23, 59, 59);

  doc.setFontSize(20); doc.setFont('helvetica','bold');
  doc.text('Reporte de Soporte TI', 14, 20);
  doc.setFontSize(11); doc.setFont('helvetica','normal');
  doc.text(`Empresa: ${empresa.name}`, 14, 30);
  doc.text(`RFC: ${empresa.rif}`, 14, 36);
  doc.text(`Período: ${mesIni.toLocaleDateString('es-MX',{month:'long',year:'numeric'})}`, 14, 42);
  doc.text(`Generado: ${ahora.toLocaleString('es-MX')}`, 14, 48);

  doc.setFont('helvetica','bold'); doc.setFontSize(13);
  doc.text('Tickets del período', 14, 60);
  doc.setFontSize(9); doc.setFont('helvetica','normal');
  let y = 66;
  const ticketsMes = (data.tickets||[]).filter(t => t.companyId===companyId &&
    new Date(t.createdAt) >= mesIni && new Date(t.createdAt) <= mesFin);
  if (ticketsMes.length===0) { doc.text('Sin tickets en este período.', 14, y); y += 8; }
  else ticketsMes.forEach(t => {
    if (y > 270) { doc.addPage(); y = 20; }
    doc.setFont('helvetica','bold'); doc.text(`• ${t.title} [${t.status}]`, 14, y); y += 5;
    doc.setFont('helvetica','normal');
    const desc = doc.splitTextToSize(t.description, 180);
    doc.text(desc, 18, y); y += desc.length*4 + 2;
    doc.setFontSize(8); doc.setTextColor(120);
    doc.text(`Creado: ${new Date(t.createdAt).toLocaleString('es-MX')} · Prioridad: ${t.priority}`, 18, y);
    doc.setTextColor(0); doc.setFontSize(9);
    y += 8;
  });

  if (y > 240) { doc.addPage(); y = 20; }
  doc.setFont('helvetica','bold'); doc.setFontSize(13);
  doc.text('Mantenimientos', 14, y); y += 6;
  doc.setFontSize(9); doc.setFont('helvetica','normal');
  const mantsMes = (data.maintenances||[]).filter(m => m.companyId===companyId &&
    new Date(m.scheduledDate) >= mesIni && new Date(m.scheduledDate) <= mesFin);
  if (mantsMes.length===0) doc.text('Sin mantenimientos.', 14, y);
  else mantsMes.forEach(m => {
    doc.text(`• ${m.title} — ${m.scheduledDate} (${m.status})`, 14, y); y += 5;
  });

  if (y > 240) { doc.addPage(); y = 20; }
  y += 10;
  doc.setFont('helvetica','bold'); doc.setFontSize(13);
  doc.text('Equipos registrados', 14, y); y += 6;
  doc.setFontSize(8); doc.setFont('helvetica','normal');
  const usuariosEmp = (data.users||[]).filter(u => u.companyId===companyId);
  usuariosEmp.forEach(u => {
    if (y > 270) { doc.addPage(); y = 20; }
    doc.text(`• ${u.name} — ${u.equipment?.brand} ${u.equipment?.model} (${u.equipment?.os}) · AnyDesk ${u.anydesk}`, 14, y); y += 5;
  });

  doc.save(`reporte-${empresa.name.replace(/\W+/g,'_')}-${mesIni.toISOString().slice(0,7)}.pdf`);
};
