
/* ===== js/Dashboard.jsx ===== */

function Dashboard({ data, navigate, toast }) {
  const { companies, users, tickets, credentials, maintenances: allMaint = [], devices: allDevices = [] } = data;

  const openTickets    = tickets.filter(t => t.status === 'open').length;
  const inProgress     = tickets.filter(t => t.status === 'in_progress').length;
  const resolved       = tickets.filter(t => t.status === 'resolved').length;
  const urgentTickets  = tickets.filter(t => t.priority === 'urgent' && t.status !== 'resolved');
  const recentTickets  = [...tickets].sort((a,b) => new Date(b.updatedAt)-new Date(a.updatedAt)).slice(0,5);
  const today          = new Date();
  const upcomingMaint  = allMaint.filter(m => m.status === 'pending' && new Date(m.scheduledDate) >= today)
                           .sort((a,b) => new Date(a.scheduledDate) - new Date(b.scheduledDate)).slice(0,4);
  const overdueMaint   = allMaint.filter(m => m.status === 'pending' && new Date(m.scheduledDate) < today);

  const statCards = [
    { label:'Empresas', labelEn:'Companies', value: companies.length, icon:'building', color:'#2563eb', bg:'#eff6ff', nav:'companies' },
    { label:'Usuarios / Equipos', labelEn:'Users / Devices', value: users.length, icon:'users', color:'#7c3aed', bg:'#faf5ff', nav:'users' },
    { label:'Tickets Abiertos', labelEn:'Open Tickets', value: openTickets + inProgress, icon:'ticket', color:'#ea580c', bg:'#fff7ed', nav:'tickets' },
    { label:'Mantenimientos', labelEn:'Pending Maint.', value: upcomingMaint.length + overdueMaint.length, icon:'clock', color:'#0891b2', bg:'#ecfeff', nav:'maintenances' },
  ];

  const priorityColor = { urgent:'red', high:'orange', medium:'yellow', low:'slate' };
  const priorityLabel = { urgent:'Urgente', high:'Alta', medium:'Media', low:'Baja' };
  const statusColor   = { open:'orange', in_progress:'blue', resolved:'green' };
  const statusLabel   = { open:'Abierto', in_progress:'En progreso', resolved:'Resuelto' };

  function getCompanyName(id) { return companies.find(c=>c.id===id)?.name || '—'; }
  function getUserName(id)    { return users.find(u=>u.id===id)?.name || 'General'; }

  return (
    <div style={{padding:'32px 36px',maxWidth:1200}}>
      <div style={{marginBottom:28}}>
        <h1 style={{margin:0,fontSize:22,fontWeight:800,color:'#0f172a'}}>Dashboard</h1>
        <p style={{margin:'4px 0 0',fontSize:13,color:'#94a3b8'}}>Resumen general del sistema / General overview</p>
      </div>

      {/* Warranty/license expiry alerts */}
      {window.ExpiryBanner && <div style={{margin:'0 0 20px',marginLeft:-36,marginRight:-36}}><ExpiryBanner data={data} navigate={navigate}/></div>}

      {/* Urgent alert */}
      {urgentTickets.length > 0 && (
        <div style={{background:'#fff7ed',border:'1.5px solid #fed7aa',borderRadius:10,padding:'12px 16px',marginBottom:24,display:'flex',alignItems:'center',gap:10}}>
          <Icon name="bolt" size={16} color="#ea580c" />
          <span style={{fontSize:13,fontWeight:600,color:'#c2410c'}}>
            {urgentTickets.length} ticket{urgentTickets.length>1?'s':''} urgente{urgentTickets.length>1?'s':''}: {urgentTickets.map(t=>t.title).join(', ')}
          </span>
          <Btn size="sm" variant="secondary" onClick={()=>navigate('tickets')} className="ml-auto" style={{marginLeft:'auto'}}>Ver tickets</Btn>
        </div>
      )}

      {/* Stat cards */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(4,1fr)',gap:16,marginBottom:28}}>
        {statCards.map(s => (
          <Card key={s.label} style={{padding:'20px 22px',cursor:'pointer'}} onClick={()=>navigate(s.nav)}>
            <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:12}}>
              <div style={{width:38,height:38,borderRadius:10,background:s.bg,display:'flex',alignItems:'center',justifyContent:'center'}}>
                <Icon name={s.icon} size={18} color={s.color} />
              </div>
            </div>
            <div style={{fontSize:28,fontWeight:800,color:'#0f172a',lineHeight:1}}>{s.value}</div>
            <div style={{fontSize:12,fontWeight:600,color:'#64748b',marginTop:4}}>{s.label}</div>
            <div style={{fontSize:11,color:'#94a3b8'}}>{s.labelEn}</div>
          </Card>
        ))}
      </div>

      <div style={{display:'grid',gridTemplateColumns:'1fr 320px',gap:20}}>
        {/* Recent tickets */}
        <Card>
          <div style={{padding:'18px 20px',borderBottom:'1px solid #f1f5f9',display:'flex',alignItems:'center',justifyContent:'space-between'}}>
            <div style={{fontWeight:700,fontSize:14,color:'#0f172a'}}>Tickets recientes</div>
            <Btn size="sm" variant="ghost" icon="chevron-right" onClick={()=>navigate('tickets')}>Ver todos</Btn>
          </div>
          {recentTickets.length === 0 ? (
            <EmptyState icon="ticket" title="Sin tickets" desc="No hay tickets registrados aún." />
          ) : (
            <div>
              {recentTickets.map((t,i) => (
                <div key={t.id} onClick={()=>navigate('tickets',{ticketId:t.id})}
                  style={{padding:'14px 20px',borderBottom: i<recentTickets.length-1?'1px solid #f8fafc':'none',display:'flex',alignItems:'center',gap:12,cursor:'pointer',transition:'background 0.1s'}}
                  onMouseEnter={e=>e.currentTarget.style.background='#f8fafc'}
                  onMouseLeave={e=>e.currentTarget.style.background='transparent'}>
                  <div style={{flex:1,minWidth:0}}>
                    <div style={{fontSize:13,fontWeight:600,color:'#0f172a',whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{t.title}</div>
                    <div style={{fontSize:11,color:'#94a3b8',marginTop:2}}>{getCompanyName(t.companyId)} · {getUserName(t.userId)}</div>
                  </div>
                  <div style={{display:'flex',alignItems:'center',gap:6}}>
                    <Badge label={priorityLabel[t.priority]} color={priorityColor[t.priority]} />
                    <Badge label={statusLabel[t.status]} color={statusColor[t.status]} />
                  </div>
                  <div style={{fontSize:11,color:'#94a3b8',whiteSpace:'nowrap'}}>{DB.timeAgo(t.updatedAt)}</div>
                </div>
              ))}
            </div>
          )}
        </Card>

        {/* Companies + quick access */}
        <div style={{display:'flex',flexDirection:'column',gap:16}}>
          <Card>
            <div style={{padding:'16px 18px',borderBottom:'1px solid #f1f5f9'}}>
              <div style={{fontWeight:700,fontSize:13,color:'#0f172a'}}>Empresas cliente</div>
            </div>
            {companies.slice(0,5).map((c,i) => (
              <div key={c.id} onClick={()=>navigate('company-detail',{companyId:c.id})}
                style={{padding:'12px 18px',borderBottom:i<Math.min(companies.length,5)-1?'1px solid #f8fafc':'none',display:'flex',alignItems:'center',gap:10,cursor:'pointer',transition:'background 0.1s'}}
                onMouseEnter={e=>e.currentTarget.style.background='#f8fafc'}
                onMouseLeave={e=>e.currentTarget.style.background='transparent'}>
                <div style={{width:34,height:34,borderRadius:9,background:'#eff6ff',display:'flex',alignItems:'center',justifyContent:'center',fontSize:13,fontWeight:800,color:'#2563eb',flexShrink:0}}>
                  {c.name.charAt(0)}
                </div>
                <div style={{flex:1,minWidth:0}}>
                  <div style={{fontSize:12,fontWeight:600,color:'#0f172a',whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{c.name}</div>
                  <div style={{fontSize:11,color:'#94a3b8'}}>{users.filter(u=>u.companyId===c.id).length} usuario(s)</div>
                </div>
                <Badge label={c.plan} color={c.plan==='Enterprise'?'purple':c.plan==='Premium'?'blue':'slate'} />
              </div>
            ))}
          </Card>

          {/* Upcoming maintenances */}
          <Card>
            <div style={{padding:'16px 18px',borderBottom:'1px solid #f1f5f9',display:'flex',alignItems:'center',justifyContent:'space-between'}}>
              <div style={{fontWeight:700,fontSize:13,color:'#0f172a'}}>Próximos mantenimientos</div>
              <Btn size="sm" variant="ghost" icon="chevron-right" onClick={()=>navigate('maintenances')}>Ver todos</Btn>
            </div>
            {overdueMaint.length > 0 && (
              <div style={{padding:'8px 14px',background:'#fef2f2',borderBottom:'1px solid #fee2e2',display:'flex',alignItems:'center',gap:6}}>
                <Icon name="alert" size={12} color="#dc2626"/>
                <span style={{fontSize:11,fontWeight:700,color:'#dc2626'}}>{overdueMaint.length} vencido{overdueMaint.length!==1?'s':''} sin completar</span>
              </div>
            )}
            {upcomingMaint.length === 0 && overdueMaint.length === 0 ? (
              <div style={{padding:'20px 16px',fontSize:13,color:'#94a3b8',textAlign:'center'}}>Sin mantenimientos programados</div>
            ) : upcomingMaint.map((m,i) => {
              const comp = companies.find(c=>c.id===m.companyId);
              const daysUntil = Math.ceil((new Date(m.scheduledDate) - new Date()) / (1000*60*60*24));
              return (
                <div key={m.id} onClick={()=>navigate('maintenances')}
                  style={{padding:'11px 16px',borderBottom:i<upcomingMaint.length-1?'1px solid #f8fafc':'none',cursor:'pointer',transition:'background 0.1s'}}
                  onMouseEnter={e=>e.currentTarget.style.background='#f8fafc'} onMouseLeave={e=>e.currentTarget.style.background='transparent'}>
                  <div style={{fontSize:12,fontWeight:600,color:'#0f172a',marginBottom:2,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{m.title}</div>
                  <div style={{display:'flex',alignItems:'center',gap:6}}>
                    <span style={{fontSize:11,color:'#64748b'}}>{comp?.name}</span>
                    <span style={{fontSize:11,color:daysUntil<=3?'#ea580c':'#94a3b8',fontWeight:daysUntil<=3?700:400}}>
                      {daysUntil===0?'Hoy':daysUntil===1?'Mañana':`En ${daysUntil} días`}
                    </span>
                  </div>
                </div>
              );
            })}
          </Card>

          <Card style={{padding:'16px 18px'}}>
            <div style={{fontWeight:700,fontSize:13,color:'#0f172a',marginBottom:14}}>Estado de tickets</div>
            {[
              { label:'Abiertos', count: openTickets, color:'#ea580c', bg:'#fff7ed' },
              { label:'En progreso', count: inProgress, color:'#2563eb', bg:'#eff6ff' },
              { label:'Resueltos', count: resolved, color:'#16a34a', bg:'#f0fdf4' },
            ].map(row => (
              <div key={row.label} style={{display:'flex',alignItems:'center',gap:10,marginBottom:10}}>
                <div style={{fontSize:12,color:'#64748b',width:80}}>{row.label}</div>
                <div style={{flex:1,height:6,background:'#f1f5f9',borderRadius:999,overflow:'hidden'}}>
                  <div style={{height:'100%',background:row.color,borderRadius:999,width: tickets.length?`${(row.count/tickets.length)*100}%`:'0%',transition:'width 0.6s ease'}} />
                </div>
                <div style={{fontSize:12,fontWeight:700,color:row.color,width:20,textAlign:'right'}}>{row.count}</div>
              </div>
            ))}
          </Card>
        </div>
      </div>
    </div>
  );
}

window.Dashboard = Dashboard;


/* ===== js/Companies.jsx ===== */

// ─── Companies View ──────────────────────────────────────────────────────────

function CompanyForm({ initial={}, onSave, onCancel }) {
  const [form, setForm] = React.useState({
    name:'', rif:'', legalName:'', address:'', phone:'', email:'', contact:'', contact2:'', phone2:'', hours:'', hourlyRate:0, monthlyFee:0, plan:'Básico', notes:'', ...initial
  });
  const set = k => v => setForm(f => ({...f, [k]:v}));
  return (
    <div style={{display:'flex',flexDirection:'column',gap:14}}>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Nombre de empresa" value={form.name} onChange={set('name')} required placeholder="Ej: Distribuidora XYZ C.A." />
        <Input label="RFC" value={form.rif} onChange={set('rif')} placeholder="RPM010101AB1" />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Teléfono" value={form.phone} onChange={set('phone')} placeholder="+52 55 555-0000" />
        <Input label="Correo" value={form.email} onChange={set('email')} type="email" placeholder="admin@empresa.com" />
      </div>
      <Input label="Dirección" value={form.address} onChange={set('address')} placeholder="Av. Insurgentes, CDMX" />
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Contacto principal" value={form.contact} onChange={set('contact')} placeholder="Nombre del encargado IT" />
        <Select label="Plan de servicio" value={form.plan} onChange={set('plan')}
          options={[{value:'Básico',label:'Básico'},{value:'Premium',label:'Premium'},{value:'Enterprise',label:'Enterprise'}]} />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Razón social" value={form.legalName} onChange={set('legalName')} placeholder="Nombre fiscal" />
        <Input label="Horario de atención" value={form.hours} onChange={set('hours')} placeholder="L-V 9:00-18:00" />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Contacto secundario" value={form.contact2} onChange={set('contact2')} placeholder="Nombre" />
        <Input label="Tel. secundario" value={form.phone2} onChange={set('phone2')} placeholder="+52 55 555-0000" />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Tarifa por hora (MXN)" value={form.hourlyRate} onChange={set('hourlyRate')} type="number" placeholder="500" />
        <Input label="Cuota mensual (MXN)" value={form.monthlyFee} onChange={set('monthlyFee')} type="number" placeholder="0" />
      </div>
      <Textarea label="Notas" value={form.notes} onChange={set('notes')} placeholder="Observaciones, horarios, etc." rows={2} />
      <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:4}}>
        <Btn variant="secondary" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" icon="check" onClick={()=>form.name.trim()&&onSave(form)}>Guardar empresa</Btn>
      </div>
    </div>
  );
}

function Companies({ data, setData, navigate, toast }) {
  const { companies, users, tickets } = data;
  const [search, setSearch]     = React.useState('');
  const [showAdd, setShowAdd]   = React.useState(false);
  const [editId, setEditId]     = React.useState(null);
  const [deleteId, setDeleteId] = React.useState(null);
  const [planFilter, setPlanFilter] = React.useState('');

  const filtered = companies.filter(c => {
    const q = search.toLowerCase();
    const matchQ = !q || c.name.toLowerCase().includes(q) || c.rif.toLowerCase().includes(q) || c.contact.toLowerCase().includes(q) || c.email.toLowerCase().includes(q);
    const matchP = !planFilter || c.plan === planFilter;
    return matchQ && matchP;
  });

  function addCompany(form) {
    const c = { ...form, id: DB.generateId('c'), createdAt: new Date().toISOString().split('T')[0] };
    setData(d => { const nd={...d,companies:[...d.companies,c]}; DB.saveData(nd); return nd; });
    setShowAdd(false); toast('Empresa agregada');
  }

  function saveEdit(form) {
    setData(d => { const nd={...d,companies:d.companies.map(c=>c.id===editId?{...c,...form}:c)}; DB.saveData(nd); return nd; });
    setEditId(null); toast('Empresa actualizada');
  }

  function deleteCompany() {
    setData(d => {
      const nd = { ...d,
        companies: d.companies.filter(c=>c.id!==deleteId),
        users: d.users.filter(u=>u.companyId!==deleteId),
        tickets: d.tickets.filter(t=>t.companyId!==deleteId),
        credentials: d.credentials.filter(cr=>cr.companyId!==deleteId),
      };
      DB.saveData(nd); return nd;
    });
    setDeleteId(null); toast('Empresa eliminada','error');
  }

  const planColor = { Enterprise:'purple', Premium:'blue', 'Básico':'slate' };
  const editCompany = companies.find(c=>c.id===editId);

  return (
    <div style={{padding:'32px 36px',maxWidth:1100}}>
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:24}}>
        <div>
          <h1 style={{margin:0,fontSize:22,fontWeight:800,color:'#0f172a'}}>Empresas cliente</h1>
          <p style={{margin:'4px 0 0',fontSize:13,color:'#94a3b8'}}>{companies.length} empresa{companies.length!==1?'s':''} registrada{companies.length!==1?'s':''}</p>
        </div>
        <Btn icon="plus" onClick={()=>setShowAdd(true)}>Nueva empresa</Btn>
      </div>

      <div style={{display:'flex',gap:10,marginBottom:18}}>
        <div style={{flex:1,position:'relative'}}>
          <span style={{position:'absolute',left:10,top:'50%',transform:'translateY(-50%)',color:'#94a3b8',pointerEvents:'none'}}>
            <Icon name="search" size={15} />
          </span>
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar empresa, RFC, contacto..."
            style={{width:'100%',paddingLeft:34,paddingRight:12,paddingTop:9,paddingBottom:9,border:'1.5px solid #e2e8f0',borderRadius:9,fontSize:13,fontFamily:'inherit',outline:'none',background:'#fff',boxSizing:'border-box'}}
            onFocus={e=>e.target.style.borderColor='#2563eb'} onBlur={e=>e.target.style.borderColor='#e2e8f0'} />
        </div>
        <Select value={planFilter} onChange={setPlanFilter} placeholder="Todos los planes"
          options={[{value:'Básico',label:'Básico'},{value:'Premium',label:'Premium'},{value:'Enterprise',label:'Enterprise'}]} />
      </div>

      {filtered.length === 0 ? (
        <EmptyState icon="building" title="Sin resultados" desc="No hay empresas que coincidan con tu búsqueda."
          action={<Btn icon="plus" onClick={()=>setShowAdd(true)}>Agregar empresa</Btn>} />
      ) : (
        <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(320px,1fr))',gap:14}}>
          {filtered.map(c => {
            const uCount = users.filter(u=>u.companyId===c.id).length;
            const tOpen  = tickets.filter(t=>t.companyId===c.id&&t.status!=='resolved').length;
            return (
              <Card key={c.id} style={{padding:0,cursor:'pointer',transition:'box-shadow 0.15s,transform 0.15s'}}
                onMouseEnter={e=>{e.currentTarget.style.boxShadow='0 6px 20px rgba(0,0,0,0.1)';e.currentTarget.style.transform='translateY(-1px)'}}
                onMouseLeave={e=>{e.currentTarget.style.boxShadow='0 1px 3px rgba(0,0,0,0.05)';e.currentTarget.style.transform='none'}}>
                <div onClick={()=>navigate('company-detail',{companyId:c.id})} style={{padding:'18px 20px 14px'}}>
                  <div style={{display:'flex',alignItems:'flex-start',gap:12,marginBottom:12}}>
                    <div style={{width:42,height:42,borderRadius:11,background:'#eff6ff',display:'flex',alignItems:'center',justifyContent:'center',fontSize:16,fontWeight:800,color:'#2563eb',flexShrink:0}}>
                      {c.name.charAt(0)}
                    </div>
                    <div style={{flex:1,minWidth:0}}>
                      <div style={{fontSize:14,fontWeight:700,color:'#0f172a',marginBottom:2,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{c.name}</div>
                      <div style={{fontSize:12,color:'#94a3b8'}}>{c.rif}</div>
                    </div>
                    <Badge label={c.plan} color={planColor[c.plan]} />
                  </div>
                  <div style={{fontSize:12,color:'#64748b',marginBottom:6,display:'flex',alignItems:'center',gap:5}}>
                    <Icon name="user-circle" size={12} color="#94a3b8" />{c.contact || '—'}
                  </div>
                  <div style={{fontSize:12,color:'#64748b',display:'flex',alignItems:'center',gap:5,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>
                    <Icon name="link" size={12} color="#94a3b8" />{c.email || '—'}
                  </div>
                </div>
                <div style={{borderTop:'1px solid #f1f5f9',padding:'10px 20px',display:'flex',alignItems:'center',gap:12,background:'#fafbfc'}}>
                  <span style={{fontSize:12,color:'#64748b',display:'flex',alignItems:'center',gap:4}}>
                    <Icon name="users" size={12} color="#94a3b8" /> {uCount} usuario{uCount!==1?'s':''}
                  </span>
                  {tOpen > 0 && <span style={{fontSize:12,color:'#ea580c',display:'flex',alignItems:'center',gap:4}}>
                    <Icon name="ticket" size={12} color="#ea580c" /> {tOpen} ticket{tOpen!==1?'s':''}
                  </span>}
                  <div style={{marginLeft:'auto',display:'flex',gap:4}}>
                    <button onClick={e=>{e.stopPropagation();setEditId(c.id)}} style={{background:'none',border:'none',cursor:'pointer',padding:4,borderRadius:6,color:'#94a3b8',display:'flex'}}
                      onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                      <Icon name="pencil" size={14} />
                    </button>
                    <button onClick={e=>{e.stopPropagation();setDeleteId(c.id)}} style={{background:'none',border:'none',cursor:'pointer',padding:4,borderRadius:6,color:'#94a3b8',display:'flex'}}
                      onMouseEnter={e=>e.currentTarget.style.color='#ef4444'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                      <Icon name="trash" size={14} />
                    </button>
                  </div>
                </div>
              </Card>
            );
          })}
        </div>
      )}

      <Modal open={showAdd} onClose={()=>setShowAdd(false)} title="Nueva empresa cliente">
        <CompanyForm onSave={addCompany} onCancel={()=>setShowAdd(false)} />
      </Modal>
      <Modal open={!!editId} onClose={()=>setEditId(null)} title="Editar empresa">
        {editCompany && <CompanyForm initial={editCompany} onSave={saveEdit} onCancel={()=>setEditId(null)} />}
      </Modal>
      <ConfirmDialog open={!!deleteId} title="¿Eliminar empresa?"
        message="Se eliminarán también sus usuarios, tickets y credenciales. Esta acción no se puede deshacer."
        onConfirm={deleteCompany} onCancel={()=>setDeleteId(null)} />
    </div>
  );
}

// ─── Network Info Form ───────────────────────────────────────────────────────
function NetworkForm({ initial={}, onSave, onCancel }) {
  const blank = { isp:'', publicIp:'', gateway:'', subnet:'255.255.255.0', dns1:'', dns2:'', routerModel:'', switchModel:'', switchCount:'0', notes:'' };
  const [form, setForm] = React.useState({ ...blank, ...initial });
  const set = k => v => setForm(f=>({...f,[k]:v}));
  return (
    <div style={{display:'flex',flexDirection:'column',gap:12}}>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="ISP / Proveedor" value={form.isp} onChange={set('isp')} placeholder="Telmex, Totalplay, Megacable, Izzi..." />
        <Input label="IP pública" value={form.publicIp} onChange={set('publicIp')} placeholder="186.44.x.x" />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Gateway" value={form.gateway} onChange={set('gateway')} placeholder="192.168.1.1" />
        <Input label="Máscara de subred" value={form.subnet} onChange={set('subnet')} placeholder="255.255.255.0" />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="DNS primario" value={form.dns1} onChange={set('dns1')} placeholder="8.8.8.8" />
        <Input label="DNS secundario" value={form.dns2} onChange={set('dns2')} placeholder="8.8.4.4" />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:12}}>
        <Input label="Modelo de router" value={form.routerModel} onChange={set('routerModel')} placeholder="MikroTik hAP..." />
        <Input label="Modelo de switch" value={form.switchModel} onChange={set('switchModel')} placeholder="TP-Link SG108..." />
        <Input label="Nº de switches" value={form.switchCount} onChange={set('switchCount')} placeholder="1" />
      </div>
      <Textarea label="Notas de red" value={form.notes} onChange={set('notes')} placeholder="VLANs, segmentos, observaciones..." rows={2} />
      <div style={{display:'flex',justifyContent:'flex-end',gap:8,paddingTop:8,borderTop:'1px solid #f1f5f9'}}>
        <Btn variant="secondary" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" icon="check" onClick={()=>onSave(form)}>Guardar red</Btn>
      </div>
    </div>
  );
}

// ─── Device Form ─────────────────────────────────────────────────────────────
function DeviceForm({ initial={}, companyId, onSave, onCancel }) {
  const [form, setForm] = React.useState({ companyId, type:'Impresora', brand:'', model:'', serial:'', ip:'', location:'', notes:'', status:'active', ...initial });
  const set = k => v => setForm(f=>({...f,[k]:v}));
  const types = ['Impresora','Switch','Router','Servidor','NAS','Access Point','Cámara IP','UPS','Otro'];
  return (
    <div style={{display:'flex',flexDirection:'column',gap:12}}>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Select label="Tipo de dispositivo" value={form.type} onChange={set('type')} options={types.map(t=>({value:t,label:t}))} required />
        <Input label="Marca" value={form.brand} onChange={set('brand')} placeholder="HP, Cisco, Synology..." />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Modelo" value={form.model} onChange={set('model')} required placeholder="LaserJet Pro M404n" />
        <Input label="Número de serie" value={form.serial} onChange={set('serial')} placeholder="SN-XXXX-0000" />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="IP / Dirección" value={form.ip} onChange={set('ip')} placeholder="192.168.1.200" />
        <Input label="Ubicación" value={form.location} onChange={set('location')} placeholder="Sala de servidores..." />
      </div>
      <Select label="Estado" value={form.status} onChange={set('status')} options={[{value:'active',label:'Activo'},{value:'inactive',label:'Inactivo'},{value:'maintenance',label:'En mantenimiento'}]} />
      <Textarea label="Notas" value={form.notes} onChange={set('notes')} placeholder="Especificaciones adicionales..." rows={2} />
      <div style={{display:'flex',justifyContent:'flex-end',gap:8,paddingTop:8,borderTop:'1px solid #f1f5f9'}}>
        <Btn variant="secondary" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" icon="check" onClick={()=>form.model.trim()&&onSave(form)}>Guardar dispositivo</Btn>
      </div>
    </div>
  );
}

// ─── Company Detail ──────────────────────────────────────────────────────────

function CompanyDetail({ companyId, data, setData, navigate, toast }) {
  const { companies, users, tickets, credentials, devices: allDevices, maintenances: allMaint } = data;
  const c = companies.find(x=>x.id===companyId);
  if (!c) return <EmptyState icon="building" title="Empresa no encontrada" />;

  const compUsers    = users.filter(u=>u.companyId===companyId);
  const compTickets  = tickets.filter(t=>t.companyId===companyId);
  const compCreds    = credentials.filter(cr=>cr.companyId===companyId);
  const compDevices  = (allDevices||[]).filter(d=>d.companyId===companyId);
  const compMaint    = (allMaint||[]).filter(m=>m.companyId===companyId).sort((a,b)=>new Date(b.scheduledDate)-new Date(a.scheduledDate));
  const [activeTab, setActiveTab] = React.useState('overview');
  const [showNetEdit, setShowNetEdit] = React.useState(false);
  const [showAddDevice, setShowAddDevice] = React.useState(false);
  const [editDeviceId, setEditDeviceId]   = React.useState(null);
  const [deleteDeviceId, setDeleteDeviceId] = React.useState(null);

  function saveNetwork(form) {
    setData(d=>{ const nd={...d,companies:d.companies.map(co=>co.id===companyId?{...co,network:form}:co)}; DB.saveData(nd); return nd; });
    setShowNetEdit(false); toast('Red actualizada');
  }
  function addDevice(form) {
    const dv = {...form, id:DB.generateId('dv')};
    setData(d=>{ const nd={...d,devices:[...(d.devices||[]),dv]}; DB.saveData(nd); return nd; });
    setShowAddDevice(false); toast('Dispositivo agregado');
  }
  function saveDevice(form) {
    setData(d=>{ const nd={...d,devices:(d.devices||[]).map(dv=>dv.id===editDeviceId?{...dv,...form}:dv)}; DB.saveData(nd); return nd; });
    setEditDeviceId(null); toast('Dispositivo actualizado');
  }
  function deleteDevice() {
    setData(d=>{ const nd={...d,devices:(d.devices||[]).filter(dv=>dv.id!==deleteDeviceId)}; DB.saveData(nd); return nd; });
    setDeleteDeviceId(null); toast('Dispositivo eliminado','error');
  }

  function copyText(text,label){ navigator.clipboard.writeText(text).then(()=>toast(`${label} copiado ✓`)); }

  const net = c.network || {};
  const tabStyle = active => ({ padding:'7px 16px',borderRadius:7,fontSize:13,fontWeight:600,cursor:'pointer',border:'none',fontFamily:'inherit',background:active?'#fff':'transparent',color:active?'#0f172a':'#64748b',boxShadow:active?'0 1px 4px rgba(0,0,0,0.08)':'none',transition:'all 0.15s' });
  const tabs = [{id:'overview',label:'General'},{id:'network',label:'Red / Infraestructura'},{id:'topology',label:'Topología'},{id:'devices',label:`Dispositivos (${compDevices.length})`},{id:'history',label:`Mantenimientos (${compMaint.length})`}];
  const devStatusColor = {active:'green',inactive:'slate',maintenance:'yellow'};
  const devStatusLabel = {active:'Activo',inactive:'Inactivo',maintenance:'Mantenimiento'};
  const deviceTypeIcon = {'Servidor':'cpu','NAS':'cpu','Switch':'wifi','Router':'wifi','Impresora':'monitor','Access Point':'wifi','Cámara IP':'monitor','UPS':'bolt','Otro':'settings'};
  const maintStatusColor = {pending:'blue',completed:'green',cancelled:'slate'};
  const maintStatusLabel = {pending:'Pendiente',completed:'Completado',cancelled:'Cancelado'};
  const maintTypeLabel = {preventivo:'Preventivo',revision:'Revisión',instalacion:'Instalación',visita:'Visita',correctivo:'Correctivo'};
  const maintTypeColor = {preventivo:'blue',revision:'purple',instalacion:'green',visita:'orange',correctivo:'red'};

  const statusColor = { open:'orange', in_progress:'blue', resolved:'green' };
  const statusLabel = { open:'Abierto', in_progress:'En progreso', resolved:'Resuelto' };
  const priorityColor = { urgent:'red', high:'orange', medium:'yellow', low:'slate' };
  const priorityLabel = { urgent:'Urgente', high:'Alta', medium:'Media', low:'Baja' };

  return (
    <div style={{padding:'32px 36px',maxWidth:1100}}>
      <button onClick={()=>navigate('companies')} style={{background:'none',border:'none',cursor:'pointer',display:'flex',alignItems:'center',gap:6,fontSize:13,color:'#64748b',marginBottom:20,padding:0,fontFamily:'inherit'}}
        onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#64748b'}>
        <Icon name="chevron-left" size={15} /> Volver a Empresas
      </button>

      {/* Header */}
      <div style={{display:'flex',alignItems:'flex-start',gap:16,marginBottom:20}}>
        <div style={{width:52,height:52,borderRadius:14,background:'#eff6ff',display:'flex',alignItems:'center',justifyContent:'center',fontSize:20,fontWeight:800,color:'#2563eb',flexShrink:0}}>{c.name.charAt(0)}</div>
        <div style={{flex:1}}>
          <h1 style={{margin:'0 0 4px',fontSize:22,fontWeight:800,color:'#0f172a'}}>{c.name}</h1>
          <div style={{display:'flex',alignItems:'center',gap:8,flexWrap:'wrap'}}>
            <span style={{fontSize:13,color:'#64748b'}}>{c.rif}</span>
            <Badge label={c.plan} color={c.plan==='Enterprise'?'purple':c.plan==='Premium'?'blue':'slate'} />
            <span style={{fontSize:12,color:'#94a3b8',display:'flex',alignItems:'center',gap:4}}><Icon name="user-circle" size={12} color="#94a3b8"/>{c.contact}</span>
            <span style={{fontSize:12,color:'#94a3b8',display:'flex',alignItems:'center',gap:4}}><Icon name="wifi" size={12} color="#94a3b8"/>{c.phone}</span>
          </div>
        </div>
        <Btn size="sm" variant="secondary" icon="ticket" onClick={()=>navigate('tickets')}>Ver tickets</Btn>
      </div>

      {/* Tabs */}
      <div style={{display:'flex',gap:4,background:'#f1f5f9',borderRadius:10,padding:4,width:'fit-content',marginBottom:22}}>
        {tabs.map(t=><button key={t.id} style={tabStyle(activeTab===t.id)} onClick={()=>setActiveTab(t.id)}>{t.label}</button>)}
      </div>

      {/* Tab: Overview */}
      {activeTab==='overview' && (
        <div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr 1fr',gap:12,marginBottom:22}}>
            {[{label:'Contacto',val:c.contact},{label:'Teléfono',val:c.phone},{label:'Correo',val:c.email},{label:'Dirección',val:c.address}].map(f=>(
              <div key={f.label} style={{background:'#f8fafc',borderRadius:10,padding:'12px 14px'}}>
                <div style={{fontSize:11,fontWeight:600,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.05em',marginBottom:4}}>{f.label}</div>
                <div style={{fontSize:13,color:'#0f172a',fontWeight:500,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{f.val||'—'}</div>
              </div>
            ))}
          </div>
          <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:12}}>
            <h2 style={{margin:0,fontSize:15,fontWeight:700,color:'#0f172a'}}>Usuarios / Equipos ({compUsers.length})</h2>
            <Btn size="sm" icon="plus" onClick={()=>navigate('add-user',{companyId})}>Agregar usuario</Btn>
          </div>
          {compUsers.length===0 ? (
            <Card style={{padding:0}}><EmptyState icon="users" title="Sin usuarios" desc="Agrega el primer usuario." action={<Btn size="sm" icon="plus" onClick={()=>navigate('add-user',{companyId})}>Agregar usuario</Btn>} /></Card>
          ) : (
            <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(280px,1fr))',gap:12,marginBottom:22}}>
              {compUsers.map(u=>(
                <Card key={u.id} style={{padding:'16px 18px',cursor:'pointer',transition:'box-shadow 0.15s'}}
                  onClick={()=>navigate('user-detail',{userId:u.id})}
                  onMouseEnter={e=>e.currentTarget.style.boxShadow='0 4px 16px rgba(0,0,0,0.1)'}
                  onMouseLeave={e=>e.currentTarget.style.boxShadow='0 1px 3px rgba(0,0,0,0.05)'}>
                  <div style={{fontSize:14,fontWeight:700,color:'#0f172a',marginBottom:2}}>{u.name}</div>
                  <div style={{fontSize:12,color:'#64748b',marginBottom:10}}>{u.position}</div>
                  <AnyDeskBadge id={u.anydesk} onCopy={()=>toast('AnyDesk copiado')} />
                  <div style={{marginTop:10,fontSize:11,color:'#94a3b8',display:'flex',alignItems:'center',gap:4}}>
                    <Icon name="monitor" size={11} color="#94a3b8"/>{u.equipment?.brand} {u.equipment?.model}
                  </div>
                </Card>
              ))}
            </div>
          )}
          {compTickets.length>0 && (
            <div style={{marginBottom:22}}>
              <h2 style={{margin:'0 0 12px',fontSize:15,fontWeight:700,color:'#0f172a'}}>Tickets ({compTickets.length})</h2>
              <Card>
                {compTickets.map((t,i)=>(
                  <div key={t.id} onClick={()=>navigate('tickets',{ticketId:t.id})}
                    style={{padding:'12px 18px',borderBottom:i<compTickets.length-1?'1px solid #f1f5f9':'none',display:'flex',alignItems:'center',gap:10,cursor:'pointer',transition:'background 0.1s'}}
                    onMouseEnter={e=>e.currentTarget.style.background='#f8fafc'} onMouseLeave={e=>e.currentTarget.style.background='transparent'}>
                    <div style={{flex:1,fontSize:13,fontWeight:600,color:'#0f172a'}}>{t.title}</div>
                    <Badge label={priorityLabel[t.priority]} color={priorityColor[t.priority]} />
                    <Badge label={statusLabel[t.status]} color={statusColor[t.status]} />
                    <span style={{fontSize:11,color:'#94a3b8'}}>{DB.timeAgo(t.updatedAt)}</span>
                  </div>
                ))}
              </Card>
            </div>
          )}
          {c.notes && <Card style={{padding:'16px 18px'}}><div style={{fontSize:12,fontWeight:600,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.05em',marginBottom:6}}>Notas</div><div style={{fontSize:13,color:'#374151'}}>{c.notes}</div></Card>}
        </div>
      )}

      {/* Tab: Network */}
      {activeTab==='network' && (
        <div>
          <div style={{display:'flex',justifyContent:'flex-end',marginBottom:14}}>
            <Btn size="sm" icon="pencil" variant="secondary" onClick={()=>setShowNetEdit(true)}>Editar información de red</Btn>
          </div>
          {!net.gateway && !net.isp ? (
            <EmptyState icon="wifi" title="Sin información de red" desc="Agrega la configuración de red de este cliente." action={<Btn icon="plus" onClick={()=>setShowNetEdit(true)}>Configurar red</Btn>} />
          ) : (
            <div style={{display:'flex',flexDirection:'column',gap:16}}>
              <div style={{display:'grid',gridTemplateColumns:'repeat(3,1fr)',gap:12}}>
                {[
                  {label:'ISP / Proveedor',val:net.isp,copy:false},
                  {label:'IP pública',val:net.publicIp,copy:true},
                  {label:'Gateway',val:net.gateway,copy:true},
                  {label:'Máscara de subred',val:net.subnet,copy:false},
                  {label:'DNS primario',val:net.dns1,copy:true},
                  {label:'DNS secundario',val:net.dns2,copy:true},
                  {label:'Router',val:net.routerModel,copy:false},
                  {label:'Switch',val:net.switchModel,copy:false},
                  {label:'Nº de switches',val:net.switchCount,copy:false},
                ].map(f=>(
                  <div key={f.label} style={{background:'#f8fafc',borderRadius:10,padding:'12px 14px',display:'flex',alignItems:'flex-start',justifyContent:'space-between',gap:8}}>
                    <div>
                      <div style={{fontSize:11,fontWeight:600,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.05em',marginBottom:4}}>{f.label}</div>
                      <div style={{fontSize:13,color:'#0f172a',fontWeight:600,fontFamily:f.copy?'monospace':'inherit'}}>{f.val||'—'}</div>
                    </div>
                    {f.copy && f.val && (
                      <button onClick={()=>copyText(f.val,f.label)} style={{background:'none',border:'none',cursor:'pointer',padding:2,color:'#94a3b8',display:'flex',flexShrink:0,marginTop:2}}
                        onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                        <Icon name="copy" size={13}/>
                      </button>
                    )}
                  </div>
                ))}
              </div>
              {net.notes && <Card style={{padding:'14px 16px'}}><div style={{fontSize:11,fontWeight:600,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.05em',marginBottom:6}}>Notas de red</div><div style={{fontSize:13,color:'#374151'}}>{net.notes}</div></Card>}
            </div>
          )}
        </div>
      )}

      {/* Tab: Topology */}
      {activeTab==='topology' && window.NetworkTopology && (
        <div>
          <NetworkTopology company={c} users={users}/>
        </div>
      )}

      {/* Tab: Devices */}
      {activeTab==='devices' && (
        <div>
          <div style={{display:'flex',justifyContent:'flex-end',marginBottom:14}}>
            <Btn size="sm" icon="plus" onClick={()=>setShowAddDevice(true)}>Agregar dispositivo</Btn>
          </div>
          {compDevices.length===0 ? (
            <EmptyState icon="monitor" title="Sin dispositivos" desc="Registra impresoras, switches, NAS, servidores y más." action={<Btn icon="plus" onClick={()=>setShowAddDevice(true)}>Agregar dispositivo</Btn>} />
          ) : (
            <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(300px,1fr))',gap:12}}>
              {compDevices.map(dv=>(
                <Card key={dv.id} style={{padding:'16px 18px'}}>
                  <div style={{display:'flex',alignItems:'flex-start',gap:10,marginBottom:10}}>
                    <div style={{width:36,height:36,borderRadius:9,background:'#f1f5f9',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0,color:'#64748b'}}>
                      <Icon name={deviceTypeIcon[dv.type]||'monitor'} size={16}/>
                    </div>
                    <div style={{flex:1,minWidth:0}}>
                      <div style={{fontSize:13,fontWeight:700,color:'#0f172a'}}>{dv.brand} {dv.model}</div>
                      <div style={{fontSize:11,color:'#94a3b8'}}>{dv.type}</div>
                    </div>
                    <Badge label={devStatusLabel[dv.status]} color={devStatusColor[dv.status]}/>
                  </div>
                  <div style={{display:'flex',flexDirection:'column',gap:4}}>
                    {dv.ip&&<div style={{fontSize:12,color:'#64748b',display:'flex',alignItems:'center',gap:6}}><Icon name="wifi" size={11} color="#94a3b8"/><span style={{fontFamily:'monospace'}}>{dv.ip}</span><button onClick={()=>copyText(dv.ip,'IP')} style={{background:'none',border:'none',cursor:'pointer',padding:0,color:'#94a3b8',display:'flex'}}><Icon name="copy" size={11}/></button></div>}
                    {dv.location&&<div style={{fontSize:12,color:'#64748b',display:'flex',alignItems:'center',gap:6}}><Icon name="building" size={11} color="#94a3b8"/>{dv.location}</div>}
                    {dv.serial&&<div style={{fontSize:11,color:'#94a3b8'}}>S/N: {dv.serial}</div>}
                    {dv.notes&&<div style={{fontSize:11,color:'#94a3b8',marginTop:4}}>{dv.notes}</div>}
                  </div>
                  <div style={{display:'flex',gap:4,marginTop:10,justifyContent:'flex-end'}}>
                    <button onClick={()=>setEditDeviceId(dv.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}} onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}><Icon name="pencil" size={14}/></button>
                    <button onClick={()=>setDeleteDeviceId(dv.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}} onMouseEnter={e=>e.currentTarget.style.color='#ef4444'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}><Icon name="trash" size={14}/></button>
                  </div>
                </Card>
              ))}
            </div>
          )}
        </div>
      )}

      {/* Tab: Maintenance history */}
      {activeTab==='history' && (
        <div>
          <div style={{display:'flex',justifyContent:'flex-end',marginBottom:14}}>
            <Btn size="sm" icon="plus" onClick={()=>navigate('maintenances',{companyId})}>Agendar mantenimiento</Btn>
          </div>
          {compMaint.length===0 ? (
            <EmptyState icon="clock" title="Sin mantenimientos" desc="No hay mantenimientos registrados para esta empresa." />
          ) : (
            <Card style={{padding:0}}>
              {compMaint.map((m,i)=>(
                <div key={m.id} style={{padding:'14px 18px',borderBottom:i<compMaint.length-1?'1px solid #f1f5f9':'none',display:'flex',alignItems:'center',gap:12}}>
                  <div style={{flex:1,minWidth:0}}>
                    <div style={{fontSize:13,fontWeight:600,color:'#0f172a',marginBottom:3}}>{m.title}</div>
                    <div style={{display:'flex',gap:6,alignItems:'center'}}>
                      <Badge label={maintTypeLabel[m.type]||m.type} color={maintTypeColor[m.type]||'slate'}/>
                      <Badge label={maintStatusLabel[m.status]} color={maintStatusColor[m.status]}/>
                      <span style={{fontSize:11,color:'#94a3b8'}}>{DB.formatDate(m.scheduledDate)}</span>
                    </div>
                  </div>
                  {m.notes&&<div style={{fontSize:12,color:'#94a3b8',maxWidth:200,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{m.notes}</div>}
                </div>
              ))}
            </Card>
          )}
        </div>
      )}

      {/* Modals */}
      <Modal open={showNetEdit} onClose={()=>setShowNetEdit(false)} title="Información de red / infraestructura" width={600}>
        <NetworkForm initial={net} onSave={saveNetwork} onCancel={()=>setShowNetEdit(false)} />
      </Modal>
      <Modal open={showAddDevice} onClose={()=>setShowAddDevice(false)} title="Agregar dispositivo" width={540}>
        <DeviceForm companyId={companyId} onSave={addDevice} onCancel={()=>setShowAddDevice(false)} />
      </Modal>
      <Modal open={!!editDeviceId} onClose={()=>setEditDeviceId(null)} title="Editar dispositivo" width={540}>
        {editDeviceId && <DeviceForm initial={(allDevices||[]).find(d=>d.id===editDeviceId)} companyId={companyId} onSave={saveDevice} onCancel={()=>setEditDeviceId(null)} />}
      </Modal>
      <ConfirmDialog open={!!deleteDeviceId} title="¿Eliminar dispositivo?" message="Esta acción no se puede deshacer." onConfirm={deleteDevice} onCancel={()=>setDeleteDeviceId(null)} />
    </div>
  );
}

Object.assign(window, { Companies, CompanyDetail });


/* ===== js/Users.jsx ===== */

function UserForm({ initial={}, companies=[], onSave, onCancel }) {
  const blank = {
    companyId:'', name:'', email:'', phone:'', position:'', anydesk:'', rustdesk:'', notes:'',
    equipment:{ brand:'', model:'', serial:'', cpu:'', ram:'', storage:'', os:'', ip:'', hostname:'', monitor:'', licenses:'', purchaseDate:'', warrantyExpiry:'', licenseExpiry:'' }
  };
  const [form, setForm] = React.useState({ ...blank, ...initial, equipment:{ ...blank.equipment, ...(initial.equipment||{}) } });
  const [tab, setTab]   = React.useState('general');
  const set  = k => v => setForm(f=>({...f,[k]:v}));
  const setEq = k => v => setForm(f=>({...f,equipment:{...f.equipment,[k]:v}}));
  const tabStyle = active => ({
    padding:'6px 14px', borderRadius:7, fontSize:13, fontWeight:600, cursor:'pointer', border:'none', fontFamily:'inherit',
    background: active ? '#2563eb' : 'transparent', color: active ? '#fff' : '#64748b', transition:'all 0.15s'
  });
  return (
    <div style={{display:'flex',flexDirection:'column',gap:14}}>
      <div style={{display:'flex',gap:4,background:'#f1f5f9',borderRadius:9,padding:3,width:'fit-content'}}>
        <button style={tabStyle(tab==='general')} onClick={()=>setTab('general')}>General</button>
        <button style={tabStyle(tab==='equipo')} onClick={()=>setTab('equipo')}>Equipo</button>
      </div>

      {tab==='general' && (
        <div style={{display:'flex',flexDirection:'column',gap:12}}>
          <Select label="Empresa" value={form.companyId} onChange={set('companyId')} required
            options={companies.map(c=>({value:c.id,label:c.name}))} placeholder="Seleccionar empresa..." />
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
            <Input label="Nombre completo" value={form.name} onChange={set('name')} required placeholder="Nombre del usuario" />
            <Input label="Cargo / Posición" value={form.position} onChange={set('position')} placeholder="Ej: Contadora" />
          </div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
            <Input label="Correo electrónico" value={form.email} onChange={set('email')} type="email" placeholder="usuario@empresa.com" />
            <Input label="Teléfono" value={form.phone} onChange={set('phone')} placeholder="+52 55 000-0000" />
          </div>
          <Input label="AnyDesk ID" value={form.anydesk} onChange={set('anydesk')} placeholder="123 456 789" hint="ID de acceso remoto AnyDesk" />
          <Input label="Infinitos Remote ID" value={form.rustdesk} onChange={set('rustdesk')} placeholder="123456789" hint="ID de Infinitos Remote (escritorio remoto propio)" />
          <Textarea label="Notas" value={form.notes} onChange={set('notes')} placeholder="Observaciones del usuario..." rows={2} />
        </div>
      )}

      {tab==='equipo' && (
        <div style={{display:'flex',flexDirection:'column',gap:12}}>
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
            <Input label="Marca" value={form.equipment.brand} onChange={setEq('brand')} placeholder="HP, Dell, Lenovo..." />
            <Input label="Modelo" value={form.equipment.model} onChange={setEq('model')} placeholder="ProBook 450 G8" />
          </div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
            <Input label="Número de serie" value={form.equipment.serial} onChange={setEq('serial')} placeholder="SN-XXXX-0000" />
            <Input label="Sistema operativo" value={form.equipment.os} onChange={setEq('os')} placeholder="Windows 11 Pro 23H2" />
          </div>
          <Input label="Procesador (CPU)" value={form.equipment.cpu} onChange={setEq('cpu')} placeholder="Intel Core i5-1135G7 @ 2.40GHz" />
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
            <Input label="RAM" value={form.equipment.ram} onChange={setEq('ram')} placeholder="8 GB DDR4 3200MHz" />
            <Input label="Almacenamiento" value={form.equipment.storage} onChange={setEq('storage')} placeholder="256 GB SSD NVMe" />
          </div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
            <Input label="IP local" value={form.equipment.ip} onChange={setEq('ip')} placeholder="192.168.1.100" />
            <Input label="Hostname" value={form.equipment.hostname} onChange={setEq('hostname')} placeholder="PC-USUARIO" />
          </div>
          <Input label="Monitor" value={form.equipment.monitor} onChange={setEq('monitor')} placeholder='HP 24" FHD IPS' />
          <Textarea label="Licencias de software" value={form.equipment.licenses} onChange={setEq('licenses')} placeholder="Microsoft 365, Adobe Acrobat, ESET..." rows={2} />
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:12}}>
            <Input label="Fecha de compra" value={form.equipment.purchaseDate} onChange={setEq('purchaseDate')} type="date" />
            <Input label="Fin de garantía" value={form.equipment.warrantyExpiry} onChange={setEq('warrantyExpiry')} type="date" />
            <Input label="Vence licencia" value={form.equipment.licenseExpiry} onChange={setEq('licenseExpiry')} type="date" />
          </div>
        </div>
      )}

      <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:4,paddingTop:12,borderTop:'1px solid #f1f5f9'}}>
        <Btn variant="secondary" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" icon="check" onClick={()=>(form.name.trim()&&form.companyId)&&onSave(form)}>Guardar usuario</Btn>
      </div>
    </div>
  );
}

function Users({ data, setData, navigate, toast, initialUserId=null }) {
  const { companies, users } = data;
  const [search, setSearch]     = React.useState('');
  const [compFilter, setCompFilter] = React.useState('');
  const [showAdd, setShowAdd]   = React.useState(false);
  const [editId, setEditId]     = React.useState(null);
  const [deleteId, setDeleteId] = React.useState(null);
  const [detailId, setDetailId] = React.useState(initialUserId);
  const [telemetry, setTelemetry] = React.useState([]);
  React.useEffect(() => {
    let alive = true;
    const load = () => fetch('/api/agent/telemetry', { credentials:'include' })
      .then(r => r.ok ? r.json() : []).then(d => { if (alive) setTelemetry(Array.isArray(d)?d:[]); }).catch(()=>{});
    load(); const tmr = setInterval(load, 30000);
    return () => { alive = false; clearInterval(tmr); };
  }, []);
  const teleFor = (u) => telemetry.find(t =>
    (u.rustdesk && t.rustdesk_id && String(t.rustdesk_id).replace(/\s/g,'') === String(u.rustdesk).replace(/\s/g,'')) ||
    (u.equipment && u.equipment.hostname && t.hostname && String(t.hostname).toLowerCase() === String(u.equipment.hostname).toLowerCase())
  );
  const fmtGB = (b) => b ? (Number(b)/1073741824).toFixed(1)+'G' : '—';

  React.useEffect(() => { if (initialUserId) setDetailId(initialUserId); }, [initialUserId]);

  if (detailId) {
    const u = users.find(x=>x.id===detailId);
    if (u) return <UserDetail userId={detailId} data={data} setData={setData} navigate={navigate} toast={toast}
      onBack={()=>setDetailId(null)} onEdit={()=>setEditId(detailId)} />;
  }

  const filtered = users.filter(u => {
    const q = search.toLowerCase();
    const matchQ = !q || u.name.toLowerCase().includes(q) || u.anydesk.includes(q) || (u.rustdesk||'').includes(q) ||
      u.email.toLowerCase().includes(q) || u.position.toLowerCase().includes(q) ||
      (u.equipment?.hostname||'').toLowerCase().includes(q) || (u.equipment?.ip||'').includes(q);
    const matchC = !compFilter || u.companyId === compFilter;
    return matchQ && matchC;
  });

  function addUser(form) {
    const u = { ...form, id: DB.generateId('u') };
    setData(d => { const nd={...d,users:[...d.users,u]}; DB.saveData(nd); return nd; });
    setShowAdd(false); toast('Usuario agregado');
  }
  const undiscovered = telemetry.filter(t => !users.some(u =>
    (u.rustdesk && t.rustdesk_id && String(t.rustdesk_id).replace(/\s/g,'') === String(u.rustdesk).replace(/\s/g,'')) ||
    (u.equipment && u.equipment.hostname && t.hostname && String(t.hostname).toLowerCase() === String(u.equipment.hostname).toLowerCase())
  ));
  function registerDevice(t) {
    const ex = t.extra || {};
    const u = { id: DB.generateId('u'), companyId: compFilter || (companies[0] && companies[0].id) || '',
      name: t.hostname || t.device_id, email:'', phone:'', position:'', anydesk:'', rustdesk: t.rustdesk_id || '',
      notes: 'Auto-registrado desde el agente ('+new Date().toISOString().slice(0,10)+')',
      equipment: { brand:'', model:'', serial:'', cpu: ex.cpuModel||'', ram: t.ram_total?(Number(t.ram_total)/1073741824).toFixed(1)+' GB':'',
        storage: t.disk_total?(Number(t.disk_total)/1073741824).toFixed(0)+' GB':'', os: ex.osDetail||t.os||'', ip: t.ip||'',
        hostname: t.hostname||'', monitor:'', licenses:'', purchaseDate:'', warrantyExpiry:'', licenseExpiry:'' } };
    setData(d => { const nd={...d,users:[...d.users,u]}; DB.saveData(nd); return nd; });
    toast('Equipo registrado con inventario del agente ✓');
  }

  function saveEdit(form) {
    setData(d => { const nd={...d,users:d.users.map(u=>u.id===editId?{...u,...form}:u)}; DB.saveData(nd); return nd; });
    setEditId(null); toast('Usuario actualizado');
  }

  function deleteUser() {
    setData(d => { const nd={...d,users:d.users.filter(u=>u.id!==deleteId)}; DB.saveData(nd); return nd; });
    setDeleteId(null); toast('Usuario eliminado','error');
  }

  const getCompany = id => companies.find(c=>c.id===id);

  return (
    <div style={{padding:'32px 36px',maxWidth:1100}}>
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:24}}>
        <div>
          <h1 style={{margin:0,fontSize:22,fontWeight:800,color:'#0f172a'}}>Usuarios / Equipos</h1>
          <p style={{margin:'4px 0 0',fontSize:13,color:'#94a3b8'}}>{users.length} usuario{users.length!==1?'s':''} registrado{users.length!==1?'s':''}</p>
        </div>
        <Btn icon="plus" onClick={()=>setShowAdd(true)}>Nuevo usuario</Btn>
      </div>

      <div style={{display:'flex',gap:10,marginBottom:18}}>
        <div style={{flex:1,position:'relative'}}>
          <span style={{position:'absolute',left:10,top:'50%',transform:'translateY(-50%)',color:'#94a3b8',pointerEvents:'none'}}><Icon name="search" size={15} /></span>
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar nombre, AnyDesk, IP, hostname..."
            style={{width:'100%',paddingLeft:34,paddingRight:12,paddingTop:9,paddingBottom:9,border:'1.5px solid #e2e8f0',borderRadius:9,fontSize:13,fontFamily:'inherit',outline:'none',background:'#fff',boxSizing:'border-box'}}
            onFocus={e=>e.target.style.borderColor='#2563eb'} onBlur={e=>e.target.style.borderColor='#e2e8f0'} />
        </div>
        <Select value={compFilter} onChange={setCompFilter} placeholder="Todas las empresas"
          options={companies.map(c=>({value:c.id,label:c.name}))} />
      </div>

      {undiscovered.length>0 && (
        <Card style={{padding:0,marginBottom:16,border:'1.5px solid #bfdbfe'}}>
          <div style={{padding:'12px 16px',borderBottom:'1px solid #eff6ff',display:'flex',alignItems:'center',gap:8,background:'#eff6ff',borderRadius:'12px 12px 0 0'}}>
            <Icon name="monitor" size={15} color="#2563eb"/>
            <span style={{fontSize:13,fontWeight:700,color:'#1e3a8a'}}>Equipos detectados sin registrar ({undiscovered.length})</span>
            <span style={{marginLeft:'auto',fontSize:11,color:'#3b82f6'}}>el agente los reporta — regístralos en 1 clic</span>
          </div>
          {undiscovered.map((t,i)=>(
            <div key={t.device_id} style={{padding:'10px 16px',borderBottom:i<undiscovered.length-1?'1px solid #f8fafc':'none',display:'flex',alignItems:'center',gap:12}}>
              <span style={{width:8,height:8,borderRadius:999,flexShrink:0,background:t.online?'#22c55e':'#cbd5e1'}}></span>
              <div style={{flex:1,minWidth:0}}>
                <div style={{fontSize:13,fontWeight:600,color:'#0f172a'}}>{t.hostname||t.device_id}</div>
                <div style={{fontSize:11,color:'#94a3b8'}}>{(t.extra&&t.extra.osDetail)||t.os||''} · {t.ip||''}{t.extra&&t.extra.softwareCount!=null?(' · '+t.extra.softwareCount+' programas'):''}</div>
              </div>
              <Btn size="sm" icon="plus" onClick={()=>registerDevice(t)}>Registrar</Btn>
            </div>
          ))}
        </Card>
      )}
      {filtered.length===0 ? (
        <EmptyState icon="users" title="Sin resultados" desc="No hay usuarios que coincidan." action={<Btn icon="plus" onClick={()=>setShowAdd(true)}>Agregar usuario</Btn>} />
      ) : (
        <Card style={{padding:0}}>
          <table style={{width:'100%',borderCollapse:'collapse'}}>
            <thead>
              <tr style={{background:'#f8fafc'}}>
                {['Usuario','Empresa','AnyDesk','Equipo','IP / Hostname',''].map(h=>(
                  <th key={h} style={{padding:'10px 16px',fontSize:11,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.05em',textAlign:'left',borderBottom:'1px solid #f1f5f9'}}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {filtered.map((u,i)=>{
                const comp = getCompany(u.companyId);
                const tele = teleFor(u);
                return (
                  <tr key={u.id} style={{cursor:'pointer',transition:'background 0.1s',borderBottom:i<filtered.length-1?'1px solid #f8fafc':'none'}}
                    onMouseEnter={e=>e.currentTarget.style.background='#f8fafc'}
                    onMouseLeave={e=>e.currentTarget.style.background='transparent'}
                    onClick={()=>setDetailId(u.id)}>
                    <td style={{padding:'12px 16px'}}>
                      <div style={{display:'flex',alignItems:'center',gap:10}}>
                        <div style={{width:34,height:34,borderRadius:999,background:'#eff6ff',display:'flex',alignItems:'center',justifyContent:'center',fontSize:13,fontWeight:700,color:'#2563eb',flexShrink:0}}>
                          {u.name.split(' ').map(n=>n[0]).slice(0,2).join('')}
                        </div>
                        <div>
                          <div style={{fontSize:13,fontWeight:600,color:'#0f172a'}}>{u.name}</div>
                          <div style={{fontSize:11,color:'#94a3b8'}}>{u.position}</div>
                        </div>
                      </div>
                    </td>
                    <td style={{padding:'12px 16px',fontSize:12,color:'#64748b'}}>{comp?.name||'—'}</td>
                    <td style={{padding:'12px 16px'}} onClick={e=>e.stopPropagation()}>
                      <AnyDeskBadge id={u.anydesk} onCopy={()=>toast('AnyDesk copiado ✓')} />
                    </td>
                    <td style={{padding:'12px 16px',fontSize:12,color:'#64748b'}}>
                      <div>{u.equipment?.brand} {u.equipment?.model}</div>
                      <div style={{fontSize:11,color:'#94a3b8'}}>{u.equipment?.os}</div>
                    </td>
                    <td style={{padding:'12px 16px'}}>
                      <div style={{fontSize:12,fontFamily:'monospace',color:'#374151'}}>{u.equipment?.ip||'—'}</div>
                      <div style={{fontSize:11,color:'#94a3b8',fontFamily:'monospace',display:'flex',alignItems:'center',gap:5}}>
                        {tele && <span title={tele.online?'En línea':'Desconectado'} style={{width:8,height:8,borderRadius:999,flexShrink:0,background:tele.online?'#22c55e':'#cbd5e1',boxShadow:tele.online?'0 0 0 2px rgba(34,197,94,0.2)':'none'}}></span>}
                        {u.equipment?.hostname||'—'}
                      </div>
                      {tele && tele.online && <div style={{fontSize:10,color:'#94a3b8',marginTop:2}}>CPU {tele.cpu_pct ?? '—'}% · RAM {fmtGB(tele.ram_used)}/{fmtGB(tele.ram_total)} · Disco {fmtGB(tele.disk_used)}/{fmtGB(tele.disk_total)}</div>}
                    </td>
                    <td style={{padding:'12px 16px'}} onClick={e=>e.stopPropagation()}>
                      <div style={{display:'flex',gap:4}}>
                        <button onClick={()=>setEditId(u.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}
                          onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                          <Icon name="pencil" size={14} />
                        </button>
                        <button onClick={()=>setDeleteId(u.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}
                          onMouseEnter={e=>e.currentTarget.style.color='#ef4444'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                          <Icon name="trash" size={14} />
                        </button>
                      </div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </Card>
      )}

      <Modal open={showAdd} onClose={()=>setShowAdd(false)} title="Nuevo usuario / equipo" width={620}>
        <UserForm companies={companies} onSave={addUser} onCancel={()=>setShowAdd(false)} />
      </Modal>
      <Modal open={!!editId} onClose={()=>setEditId(null)} title="Editar usuario / equipo" width={620}>
        {editId && <UserForm initial={users.find(u=>u.id===editId)} companies={companies} onSave={saveEdit} onCancel={()=>setEditId(null)} />}
      </Modal>
      <ConfirmDialog open={!!deleteId} title="¿Eliminar usuario?" message="Esta acción no se puede deshacer."
        onConfirm={deleteUser} onCancel={()=>setDeleteId(null)} />
    </div>
  );
}

function UserDetail({ userId, data, setData, navigate, toast, onBack, onEdit }) {
  const { companies, users, tickets } = data;
  const u = users.find(x=>x.id===userId);
  if (!u) return null;
  const comp = companies.find(c=>c.id===u.companyId);
  const userTickets = tickets.filter(t=>t.userId===userId);
  const eq = u.equipment || {};
  const [tele, setTele] = React.useState(null);
  React.useEffect(()=>{
    let alive=true;
    const norm=x=>String(x||'').replace(/\s/g,'').toLowerCase();
    const load=()=>fetch('/api/agent/telemetry',{credentials:'include'}).then(r=>r.ok?r.json():[]).then(list=>{
      if(!alive)return;
      const m=(Array.isArray(list)?list:[]).find(t=>(u.rustdesk&&norm(t.rustdesk_id)===norm(u.rustdesk))||(eq.hostname&&t.hostname&&String(t.hostname).toLowerCase()===String(eq.hostname).toLowerCase()));
      setTele(m||null);
    }).catch(()=>{});
    load(); const tmr=setInterval(load,30000); return ()=>{alive=false;clearInterval(tmr);};
  },[userId]);
  const gb=b=>b?(Number(b)/1073741824).toFixed(1)+'G':'—';
  const infoBox=(label,val)=>(<div style={{background:'#f8fafc',borderRadius:8,padding:'10px 12px'}}><div style={{fontSize:10,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:3}}>{label}</div><div style={{fontSize:12,color:'#0f172a',fontWeight:600,wordBreak:'break-word'}}>{val}</div></div>);
  const [cmds,setCmds]=React.useState([]);
  React.useEffect(()=>{ if(!tele||!tele.device_id) return; let alive=true;
    const load=()=>fetch('/api/agent/commands/list?deviceId='+encodeURIComponent(tele.device_id),{credentials:'include'}).then(r=>r.ok?r.json():[]).then(d=>{if(alive)setCmds(Array.isArray(d)?d:[]);}).catch(()=>{});
    load(); const tm=setInterval(load,10000); return ()=>{alive=false;clearInterval(tm);};
  },[tele&&tele.device_id]);
  const runAction=(k)=>fetch('/api/agent/commands',{method:'POST',credentials:'include',headers:{'Content-Type':'application/json'},body:JSON.stringify({deviceId:tele.device_id,action:k})}).then(r=>{ if(r.ok) toast('Acción enviada — el equipo la ejecuta en segundos'); else toast('Error al enviar','error'); }).catch(()=>toast('Error al enviar','error'));
  const metric=(label,val,used,total)=>{ const pct=total?Math.min(100,Math.round(used/total*100)):0; return (
    <div style={{background:'#f8fafc',borderRadius:8,padding:'10px 12px'}}>
      <div style={{fontSize:10,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:4}}>{label}</div>
      <div style={{fontSize:13,fontWeight:700,color:'#0f172a',marginBottom:6}}>{val}</div>
      <div style={{height:4,background:'#e2e8f0',borderRadius:2}}><div style={{height:4,width:pct+'%',background:pct>=90?'#ef4444':pct>=70?'#f59e0b':'#22c55e',borderRadius:2}}></div></div>
    </div>
  ); };
  const expChip=(label,dateStr)=>{ if(!dateStr) return null; const days=Math.ceil((new Date(dateStr).getTime()-Date.now())/86400000); const col=days<0?'#ef4444':days<=30?'#f59e0b':'#22c55e'; return <span style={{fontSize:11,padding:'3px 9px',borderRadius:6,background:col+'1a',color:col,fontWeight:600}}>{label}: {days<0?('venció hace '+(-days)+'d'):(days+'d')}</span>; };

  const specs = [
    {label:'CPU / Procesador',val:eq.cpu,icon:'cpu'},
    {label:'RAM',val:eq.ram,icon:'cpu'},
    {label:'Almacenamiento',val:eq.storage,icon:'cpu'},
    {label:'Sistema Operativo',val:eq.os,icon:'monitor'},
    {label:'Monitor',val:eq.monitor,icon:'monitor'},
    {label:'IP Local',val:eq.ip,icon:'wifi'},
    {label:'Hostname',val:eq.hostname,icon:'wifi'},
    {label:'Número de serie',val:eq.serial,icon:'cpu'},
  ];

  return (
    <div style={{padding:'32px 36px',maxWidth:960}}>
      <button onClick={onBack} style={{background:'none',border:'none',cursor:'pointer',display:'flex',alignItems:'center',gap:6,fontSize:13,color:'#64748b',marginBottom:20,padding:0,fontFamily:'inherit'}}
        onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#64748b'}>
        <Icon name="chevron-left" size={15}/> Volver
      </button>

      <div style={{display:'flex',alignItems:'flex-start',gap:16,marginBottom:24}}>
        <div style={{width:52,height:52,borderRadius:999,background:'#eff6ff',display:'flex',alignItems:'center',justifyContent:'center',fontSize:18,fontWeight:800,color:'#2563eb',flexShrink:0}}>
          {u.name.split(' ').map(n=>n[0]).slice(0,2).join('')}
        </div>
        <div style={{flex:1}}>
          <h1 style={{margin:'0 0 4px',fontSize:20,fontWeight:800,color:'#0f172a'}}>{u.name}</h1>
          <div style={{fontSize:13,color:'#64748b'}}>{u.position} · {comp?.name}</div>
          <div style={{display:'flex',gap:8,marginTop:10,flexWrap:'wrap'}}>
            <AnyDeskBadge id={u.anydesk} onCopy={()=>toast('AnyDesk copiado ✓')} />
            {u.email&&<span style={{fontSize:12,color:'#64748b',display:'flex',alignItems:'center',gap:4}}><Icon name="link" size={12} color="#94a3b8"/>{u.email}</span>}
            {u.phone&&<span style={{fontSize:12,color:'#64748b',display:'flex',alignItems:'center',gap:4}}><Icon name="wifi" size={12} color="#94a3b8"/>{u.phone}</span>}
          </div>
          {u.stickerId && (
            <div style={{marginTop:12,padding:'10px 14px',background:'linear-gradient(135deg,#fff7ed,#ffedd5)',border:'1.5px dashed #fb923c',borderRadius:12,display:'inline-flex',alignItems:'center',gap:14}}>
              <div>
                <div style={{fontSize:9,fontWeight:700,color:'#9a3412',textTransform:'uppercase',letterSpacing:'0.08em',marginBottom:2}}>Sticker</div>
                <div style={{fontSize:18,fontWeight:900,color:'#0f172a',letterSpacing:'4px',fontFamily:'monospace'}}>{u.stickerId}</div>
              </div>
              <div style={{width:1,height:30,background:'#fb923c'}}/>
              <div>
                <div style={{fontSize:9,fontWeight:700,color:'#9a3412',textTransform:'uppercase',letterSpacing:'0.08em',marginBottom:2}}>PIN</div>
                <div style={{fontSize:18,fontWeight:900,color:'#0f172a',letterSpacing:'5px',fontFamily:'monospace'}}>{u.pin}</div>
              </div>
              <Btn size="sm" variant="secondary" onClick={()=>window.imprimirSticker && window.imprimirSticker(u, comp)}>Imprimir</Btn>
              <Btn size="sm" variant="secondary" onClick={()=>{
                if (!confirm('¿Generar nuevo sticker y PIN? El anterior dejará de funcionar.')) return;
                const ALPHA='ABCDEFGHJKMNPQRSTUVWXYZ';
                let nid=''; for (let i=0;i<5;i++) nid+=ALPHA[Math.floor(Math.random()*ALPHA.length)];
                const npin=String(Math.floor(Math.random()*900000)+100000);
                const nd={...data, users: data.users.map(x=>x.id===u.id?{...x, stickerId:nid, pin:npin}:x)};
                setData(nd); DB.saveData(nd);
                toast('Nuevo sticker generado');
              }}>Regenerar</Btn>
            </div>
          )}
          {window.Launchers && <div style={{marginTop:12}}><Launchers user={u} company={comp}/></div>}
        </div>
        <Btn size="sm" variant="secondary" icon="pencil" onClick={onEdit}>Editar</Btn>
      </div>

      <div style={{display:'grid',gridTemplateColumns:'1fr 300px',gap:20}}>
        <div>
          <Card style={{padding:'16px 20px',marginBottom:16}}>
            <div style={{display:'flex',alignItems:'center',gap:8,marginBottom:tele?14:0}}>
              <span style={{width:10,height:10,borderRadius:999,flexShrink:0,background:tele?(tele.online?'#22c55e':'#cbd5e1'):'#e2e8f0'}}></span>
              <span style={{fontSize:14,fontWeight:700,color:'#0f172a'}}>{tele?(tele.online?'En línea':'Desconectado'):'Sin agente'}</span>
              {tele && <span style={{marginLeft:'auto',fontSize:11,color:'#94a3b8'}}>visto {DB.timeAgo(tele.last_seen)}</span>}
            </div>
            {tele ? (
              <div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:10}}>
                {metric('CPU', tele.cpu_pct!=null?tele.cpu_pct+'%':'—', Number(tele.cpu_pct)||0, 100)}
                {metric('RAM', gb(tele.ram_used)+' / '+gb(tele.ram_total), Number(tele.ram_used), Number(tele.ram_total))}
                {metric('Disco', gb(tele.disk_used)+' / '+gb(tele.disk_total), Number(tele.disk_used), Number(tele.disk_total))}
              </div>
            ) : <div style={{fontSize:12,color:'#94a3b8'}}>Instala el agente Infinitos Remote en este equipo para ver CPU/RAM/disco en vivo.</div>}
            {(eq.warrantyExpiry||eq.licenseExpiry||eq.purchaseDate) && <div style={{display:'flex',gap:6,marginTop:14,flexWrap:'wrap',alignItems:'center'}}>
              {eq.purchaseDate && <span style={{fontSize:11,color:'#94a3b8'}}>Comprado {eq.purchaseDate}</span>}
              {expChip('Garantía',eq.warrantyExpiry)}
              {expChip('Licencia',eq.licenseExpiry)}
            </div>}
          </Card>
          {tele && tele.extra && (tele.extra.cpuModel || tele.extra.softwareCount!=null) && (
            <Card style={{padding:'16px 20px',marginBottom:16}}>
              <div style={{display:'flex',alignItems:'center',gap:8,marginBottom:12}}>
                <Icon name="cpu" size={15} color="#16a34a"/>
                <span style={{fontSize:14,fontWeight:700,color:'#0f172a'}}>Inventario automático</span>
                <span style={{marginLeft:'auto',fontSize:10,color:'#16a34a',background:'#f0fdf4',padding:'2px 8px',borderRadius:6,fontWeight:600}}>detectado por el agente</span>
              </div>
              <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:10}}>
                {tele.extra.cpuModel && infoBox('Procesador (real)', tele.extra.cpuModel + (tele.extra.cpuCores?(' · '+tele.extra.cpuCores+' núcleos'):''))}
                {tele.extra.osDetail && infoBox('Sistema operativo', tele.extra.osDetail)}
                {tele.extra.loggedUsers && tele.extra.loggedUsers.length>0 && infoBox('Sesión activa', tele.extra.loggedUsers.join(', '))}
                {tele.extra.softwareCount!=null && infoBox('Software instalado', tele.extra.softwareCount + ' programas')}
              </div>
              {tele.extra.software && tele.extra.software.length>0 && (
                <details style={{marginTop:12}}>
                  <summary style={{cursor:'pointer',fontSize:12,fontWeight:600,color:'#2563eb'}}>Ver software ({tele.extra.software.length} de {tele.extra.softwareCount})</summary>
                  <div style={{marginTop:8,maxHeight:200,overflowY:'auto'}}>
                    {tele.extra.software.map((sw,i)=><div key={i} style={{fontSize:11,color:'#475569',fontFamily:'monospace',borderBottom:'1px solid #f8fafc',padding:'3px 0'}}>{sw}</div>)}
                  </div>
                </details>
              )}
            </Card>
          )}
          {tele && (
            <Card style={{padding:'16px 20px',marginBottom:16}}>
              <div style={{display:'flex',alignItems:'center',gap:8,marginBottom:12}}>
                <Icon name="bolt" size={15} color="#7c3aed"/>
                <span style={{fontSize:14,fontWeight:700,color:'#0f172a'}}>Acciones remotas</span>
                <span style={{marginLeft:'auto',fontSize:10,color:'#94a3b8'}}>vía agente · seguro</span>
              </div>
              <div style={{display:'flex',gap:6,flexWrap:'wrap'}}>
                {[{k:'uptime',l:'Uptime'},{k:'disk',l:'Disco'},{k:'procs',l:'Procesos'},{k:'sessions',l:'Sesiones'},{k:'netinfo',l:'Red'},{k:'cleanup',l:'Limpiar temp'}].map(a=>(
                  <button key={a.k} onClick={()=>runAction(a.k)} style={{padding:'6px 12px',borderRadius:8,border:'1.5px solid #e2e8f0',background:'#fff',fontSize:12,fontWeight:600,cursor:'pointer',color:'#475569',fontFamily:'inherit'}}
                    onMouseEnter={e=>{e.currentTarget.style.borderColor='#7c3aed';e.currentTarget.style.color='#7c3aed';}} onMouseLeave={e=>{e.currentTarget.style.borderColor='#e2e8f0';e.currentTarget.style.color='#475569';}}>{a.l}</button>
                ))}
              </div>
              {cmds.slice(0,5).map(c=>(
                <div key={c.id} style={{borderTop:'1px solid #f1f5f9',paddingTop:8,marginTop:8}}>
                  <div style={{display:'flex',alignItems:'center',gap:8}}>
                    <Badge label={c.action} color="purple"/>
                    <span style={{fontSize:11,fontWeight:600,color:c.status==='done'?'#16a34a':c.status==='error'?'#ef4444':'#f59e0b'}}>{c.status}</span>
                    <span style={{marginLeft:'auto',fontSize:10,color:'#94a3b8'}}>{c.requested_by}</span>
                  </div>
                  {c.output && <pre style={{margin:'6px 0 0',fontSize:10,color:'#475569',background:'#f8fafc',borderRadius:6,padding:'8px',whiteSpace:'pre-wrap',maxHeight:130,overflow:'auto',fontFamily:'monospace'}}>{c.output}</pre>}
                </div>
              ))}
            </Card>
          )}
          <Card style={{padding:'18px 20px',marginBottom:16}}>
            <div style={{display:'flex',alignItems:'center',gap:8,marginBottom:14}}>
              <Icon name="monitor" size={15} color="#2563eb"/>
              <span style={{fontSize:14,fontWeight:700,color:'#0f172a'}}>{eq.brand} {eq.model}</span>
            </div>
            <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:10}}>
              {specs.map(s=>s.val&&(
                <div key={s.label} style={{background:'#f8fafc',borderRadius:8,padding:'10px 12px'}}>
                  <div style={{fontSize:10,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:3}}>{s.label}</div>
                  <div style={{fontSize:12,color:'#0f172a',fontWeight:500}}>{s.val}</div>
                </div>
              ))}
            </div>
            {eq.licenses&&(
              <div style={{marginTop:12,background:'#f0fdf4',borderRadius:8,padding:'10px 12px'}}>
                <div style={{fontSize:10,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:3}}>Licencias de software</div>
                <div style={{fontSize:12,color:'#166534'}}>{eq.licenses}</div>
              </div>
            )}
          </Card>
        </div>

        <div style={{display:'flex',flexDirection:'column',gap:14}}>
          {u.notes&&(
            <Card style={{padding:'14px 16px'}}>
              <div style={{fontSize:11,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:6}}>Notas</div>
              <div style={{fontSize:13,color:'#374151'}}>{u.notes}</div>
            </Card>
          )}
          <Card style={{padding:0}}>
            <div style={{padding:'12px 16px',borderBottom:'1px solid #f1f5f9',fontSize:13,fontWeight:700,color:'#0f172a'}}>Tickets ({userTickets.length})</div>
            {userTickets.length===0 ? <div style={{padding:'20px 16px',fontSize:13,color:'#94a3b8',textAlign:'center'}}>Sin tickets</div> :
              userTickets.map((t,i)=>(
                <div key={t.id} onClick={()=>navigate('tickets',{ticketId:t.id})}
                  style={{padding:'10px 16px',borderBottom:i<userTickets.length-1?'1px solid #f8fafc':'none',cursor:'pointer',transition:'background 0.1s'}}
                  onMouseEnter={e=>e.currentTarget.style.background='#f8fafc'} onMouseLeave={e=>e.currentTarget.style.background='transparent'}>
                  <div style={{fontSize:12,fontWeight:600,color:'#0f172a',marginBottom:3}}>{t.title}</div>
                  <Badge label={t.status==='resolved'?'Resuelto':t.status==='in_progress'?'En progreso':'Abierto'} color={t.status==='resolved'?'green':t.status==='in_progress'?'blue':'orange'} />
                </div>
              ))
            }
          </Card>
          {window.Timeline && window.Features && (
            <Card style={{padding:'14px 16px'}}>
              <div style={{fontSize:11,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:10}}>Historial del equipo</div>
              <Timeline events={window.Features.getEquipmentTimeline(data, u.id)}/>
            </Card>
          )}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { Users, UserDetail });


/* ===== js/Tickets.jsx ===== */

function TicketForm({ initial={}, companies=[], users=[], onSave, onCancel }) {
  const [form, setForm] = React.useState({
    companyId:'', userId:'', title:'', description:'', status:'open', priority:'medium', ...initial
  });
  const set = k => v => setForm(f=>({...f,[k]:v}));
  const compUsers = users.filter(u=>u.companyId===form.companyId);
  return (
    <div style={{display:'flex',flexDirection:'column',gap:12}}>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Select label="Empresa" value={form.companyId} onChange={v=>{set('companyId')(v);set('userId')('');}} required
          options={companies.map(c=>({value:c.id,label:c.name}))} />
        <Select label="Usuario" value={form.userId} onChange={set('userId')}
          options={compUsers.map(u=>({value:u.id,label:u.name}))} placeholder="General / Sin usuario" />
      </div>
      <Input label="Título del ticket" value={form.title} onChange={set('title')} required placeholder="Descripción breve del problema" />
      <Textarea label="Descripción detallada" value={form.description} onChange={set('description')} placeholder="Explica el problema, pasos para reproducirlo, etc." rows={4} />
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Select label="Prioridad" value={form.priority} onChange={set('priority')}
          options={[{value:'urgent',label:'🔴 Urgente'},{value:'high',label:'🟠 Alta'},{value:'medium',label:'🟡 Media'},{value:'low',label:'⚪ Baja'}]} />
        <Select label="Estado" value={form.status} onChange={set('status')}
          options={[{value:'open',label:'Abierto'},{value:'in_progress',label:'En progreso'},{value:'resolved',label:'Resuelto'}]} />
      </div>
      <div style={{display:'flex',justifyContent:'flex-end',gap:8,paddingTop:8,borderTop:'1px solid #f1f5f9'}}>
        <Btn variant="secondary" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" icon="check" onClick={()=>form.title.trim()&&form.companyId&&onSave(form)}>Guardar ticket</Btn>
      </div>
    </div>
  );
}

function Tickets({ data, setData, navigate, toast, initialTicketId=null }) {
  const { companies, users, tickets } = data;
  const [search, setSearch]       = React.useState('');
  const [statusFilter, setStatus] = React.useState('');
  const [priorityFilter, setPrio] = React.useState('');
  const [compFilter, setComp]     = React.useState('');
  const [showAdd, setShowAdd]     = React.useState(false);
  const [selected, setSelected]   = React.useState(initialTicketId);
  const [editId, setEditId]       = React.useState(null);
  const [deleteId, setDeleteId]   = React.useState(null);
  const [noteText, setNoteText]   = React.useState('');
  const [tecnicos, setTecnicos]   = React.useState([]);
  React.useEffect(()=>{ fetch('/api/usuarios',{credentials:'include'}).then(r=>r.ok?r.json():[]).then(d=>setTecnicos(Array.isArray(d)?d:[])).catch(()=>{}); },[]);
  const tecName = (id)=>{ const u=tecnicos.find(x=>String(x.id)===String(id)); return u?(u.nombre||u.username):null; };
  const patchField = (id, patch, note)=>{ const now=new Date().toISOString(); setData(d=>{ const nd={...d, tickets:d.tickets.map(t=>t.id===id?{...t,...patch,updatedAt:now,history:note?[...(t.history||[]),{date:now,note,author:'Soporte IT'}]:(t.history||[])}:t)}; DB.saveData(nd); return nd; }); };
  const fLbl = {fontSize:11,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.05em',display:'block',marginBottom:4};
  const fInp = {width:'100%',padding:'6px 8px',border:'1.5px solid #e2e8f0',borderRadius:7,fontSize:12,fontFamily:'inherit',boxSizing:'border-box',background:'#fff'};

  React.useEffect(()=>{ if(initialTicketId) setSelected(initialTicketId); },[initialTicketId]);

  const priorityColor = { urgent:'red', high:'orange', medium:'yellow', low:'slate' };
  const priorityLabel = { urgent:'Urgente', high:'Alta', medium:'Media', low:'Baja' };
  const statusColor   = { open:'orange', in_progress:'blue', resolved:'green' };
  const statusLabel   = { open:'Abierto', in_progress:'En progreso', resolved:'Resuelto' };

  const SLA_HOURS = { urgent: 4, high: 8, medium: 24, low: 72 };
  const slaInfo = (t) => {
    const target = SLA_HOURS[t.priority] ?? 24;
    const created = new Date(t.createdAt).getTime();
    if (!created) return null;
    if (t.status === 'resolved') {
      const ok = (new Date(t.updatedAt).getTime() - created) <= target*3600e3;
      return { label: ok ? 'SLA cumplido' : 'SLA incumplido', color: ok ? 'green' : 'red' };
    }
    const remH = target - (Date.now() - created)/3600e3;
    if (remH < 0) return { label: 'SLA vencido ' + Math.round(-remH) + 'h', color: 'red' };
    if (remH < target*0.25) return { label: 'Vence en ' + Math.ceil(remH) + 'h', color: 'yellow' };
    return { label: 'En SLA · ' + Math.ceil(remH) + 'h', color: 'green' };
  };

  const filtered = tickets.filter(t=>{
    const q = search.toLowerCase();
    const matchQ = !q || t.title.toLowerCase().includes(q) || t.description.toLowerCase().includes(q);
    const matchS = !statusFilter || t.status===statusFilter;
    const matchP = !priorityFilter || t.priority===priorityFilter;
    const matchC = !compFilter || t.companyId===compFilter;
    return matchQ && matchS && matchP && matchC;
  }).sort((a,b)=>{
    const pOrd = {urgent:0,high:1,medium:2,low:3};
    if(a.status!=='resolved'&&b.status==='resolved') return -1;
    if(a.status==='resolved'&&b.status!=='resolved') return 1;
    return (pOrd[a.priority]||2)-(pOrd[b.priority]||2);
  });

  const selectedTicket = tickets.find(t=>t.id===selected);

  function addTicket(form) {
    const now = new Date().toISOString();
    const t = { ...form, id: DB.generateId('t'), createdAt:now, updatedAt:now, history:[{date:now,note:'Ticket creado',author:'Sistema'}] };
    setData(d=>{ const nd={...d,tickets:[t,...d.tickets]}; DB.saveData(nd); return nd; });
    setShowAdd(false); setSelected(t.id); toast('Ticket creado');
  }

  function saveEdit(form) {
    const now = new Date().toISOString();
    setData(d=>{ const nd={...d,tickets:d.tickets.map(t=>t.id===editId?{...t,...form,updatedAt:now}:t)}; DB.saveData(nd); return nd; });
    setEditId(null); toast('Ticket actualizado');
  }

  function deleteTicket() {
    setData(d=>{ const nd={...d,tickets:d.tickets.filter(t=>t.id!==deleteId)}; DB.saveData(nd); return nd; });
    setDeleteId(null); setSelected(null); toast('Ticket eliminado','error');
  }

  function changeStatus(ticketId, newStatus) {
    const now = new Date().toISOString();
    const statusLabel2 = {open:'Abierto',in_progress:'En progreso',resolved:'Resuelto'};
    setData(d=>{ const nd={...d,tickets:d.tickets.map(t=>t.id===ticketId?{...t,status:newStatus,updatedAt:now,history:[...(t.history||[]),{date:now,note:`Estado cambiado a: ${statusLabel2[newStatus]}`,author:'Soporte IT'}]}:t)}; DB.saveData(nd); return nd; });
    toast('Estado actualizado');
  }

  function addNote(ticketId) {
    if(!noteText.trim()) return;
    const now = new Date().toISOString();
    setData(d=>{ const nd={...d,tickets:d.tickets.map(t=>t.id===ticketId?{...t,updatedAt:now,history:[...(t.history||[]),{date:now,note:noteText.trim(),author:'Soporte IT'}]}:t)}; DB.saveData(nd); return nd; });
    setNoteText(''); toast('Nota agregada');
  }

  const getCompany = id => companies.find(c=>c.id===id);
  const getUser = id => users.find(u=>u.id===id);

  return (
    <div style={{padding:'32px 36px',maxWidth:1200}}>
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:24}}>
        <div>
          <h1 style={{margin:0,fontSize:22,fontWeight:800,color:'#0f172a'}}>Tickets / Incidencias</h1>
          <p style={{margin:'4px 0 0',fontSize:13,color:'#94a3b8'}}>{tickets.filter(t=>t.status!=='resolved').length} abierto{tickets.filter(t=>t.status!=='resolved').length!==1?'s':''} · {tickets.filter(t=>t.status==='resolved').length} resuelto{tickets.filter(t=>t.status==='resolved').length!==1?'s':''}</p>
        </div>
        <Btn icon="plus" onClick={()=>setShowAdd(true)}>Nuevo ticket</Btn>
      </div>

      <div style={{display:'flex',gap:10,marginBottom:18,flexWrap:'wrap'}}>
        <div style={{flex:1,minWidth:200,position:'relative'}}>
          <span style={{position:'absolute',left:10,top:'50%',transform:'translateY(-50%)',color:'#94a3b8',pointerEvents:'none'}}><Icon name="search" size={15}/></span>
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar ticket..."
            style={{width:'100%',paddingLeft:34,paddingRight:12,paddingTop:9,paddingBottom:9,border:'1.5px solid #e2e8f0',borderRadius:9,fontSize:13,fontFamily:'inherit',outline:'none',background:'#fff',boxSizing:'border-box'}}
            onFocus={e=>e.target.style.borderColor='#2563eb'} onBlur={e=>e.target.style.borderColor='#e2e8f0'} />
        </div>
        <Select value={statusFilter} onChange={setStatus} placeholder="Todos los estados"
          options={[{value:'open',label:'Abiertos'},{value:'in_progress',label:'En progreso'},{value:'resolved',label:'Resueltos'}]} />
        <Select value={priorityFilter} onChange={setPrio} placeholder="Todas las prioridades"
          options={[{value:'urgent',label:'Urgente'},{value:'high',label:'Alta'},{value:'medium',label:'Media'},{value:'low',label:'Baja'}]} />
        <Select value={compFilter} onChange={setComp} placeholder="Todas las empresas"
          options={companies.map(c=>({value:c.id,label:c.name}))} />
      </div>

      <div style={{display:'grid',gridTemplateColumns:selected?'1fr 420px':'1fr',gap:16}}>
        {/* List */}
        <Card style={{padding:0,height:'fit-content'}}>
          {filtered.length===0 ? (
            <EmptyState icon="ticket" title="Sin tickets" desc="No hay tickets que coincidan." action={<Btn icon="plus" onClick={()=>setShowAdd(true)}>Crear ticket</Btn>} />
          ) : filtered.map((t,i)=>{
            const comp = getCompany(t.companyId);
            const user = getUser(t.userId);
            const sla = slaInfo(t);
            const isActive = selected===t.id;
            return (
              <div key={t.id} onClick={()=>setSelected(isActive?null:t.id)}
                style={{padding:'14px 18px',borderBottom:i<filtered.length-1?'1px solid #f1f5f9':'none',cursor:'pointer',transition:'background 0.1s',background:isActive?'#f0f7ff':'transparent',borderLeft:isActive?'3px solid #2563eb':'3px solid transparent'}}
                onMouseEnter={e=>{if(!isActive)e.currentTarget.style.background='#f8fafc'}}
                onMouseLeave={e=>{if(!isActive)e.currentTarget.style.background='transparent'}}>
                <div style={{display:'flex',alignItems:'flex-start',gap:10}}>
                  <div style={{flex:1,minWidth:0}}>
                    <div style={{fontSize:13,fontWeight:700,color:'#0f172a',marginBottom:3,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{t.title}</div>
                    <div style={{fontSize:11,color:'#94a3b8',marginBottom:6,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{comp?.name}{user?` · ${user.name}`:''}</div>
                    <div style={{display:'flex',gap:5,flexWrap:'wrap'}}>
                      <Badge label={priorityLabel[t.priority]} color={priorityColor[t.priority]} />
                      <Badge label={statusLabel[t.status]} color={statusColor[t.status]} />
                      {sla && <Badge label={sla.label} color={sla.color} />}
                      {t.assigneeId && <span style={{fontSize:10,color:'#64748b',alignSelf:'center'}}>· {tecName(t.assigneeId)||'asignado'}</span>}
                    </div>
                  </div>
                  <div style={{fontSize:11,color:'#94a3b8',whiteSpace:'nowrap',paddingTop:2}}>{DB.timeAgo(t.updatedAt)}</div>
                </div>
              </div>
            );
          })}
        </Card>

        {/* Detail panel */}
        {selectedTicket && (
          <Card style={{padding:0,height:'fit-content',position:'sticky',top:20}}>
            <div style={{padding:'16px 18px',borderBottom:'1px solid #f1f5f9',display:'flex',alignItems:'center',justifyContent:'space-between'}}>
              <div style={{fontSize:14,fontWeight:700,color:'#0f172a',flex:1,marginRight:8,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{selectedTicket.title}</div>
              <div style={{display:'flex',gap:4}}>
                <button onClick={()=>setEditId(selectedTicket.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}
                  onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}><Icon name="pencil" size={14}/></button>
                <button onClick={()=>setDeleteId(selectedTicket.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}
                  onMouseEnter={e=>e.currentTarget.style.color='#ef4444'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}><Icon name="trash" size={14}/></button>
                <button onClick={()=>setSelected(null)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}><Icon name="x" size={14}/></button>
              </div>
            </div>
            <div style={{padding:'14px 18px',borderBottom:'1px solid #f1f5f9'}}>
              <div style={{display:'flex',gap:6,marginBottom:12,flexWrap:'wrap'}}>
                <Badge label={priorityLabel[selectedTicket.priority]} color={priorityColor[selectedTicket.priority]} />
                <Badge label={statusLabel[selectedTicket.status]} color={statusColor[selectedTicket.status]} />
              </div>
              <div style={{fontSize:12,color:'#64748b',marginBottom:4}}>
                <b style={{color:'#374151'}}>Empresa:</b> {getCompany(selectedTicket.companyId)?.name||'—'}
              </div>
              {selectedTicket.userId&&<div style={{fontSize:12,color:'#64748b',marginBottom:8}}>
                <b style={{color:'#374151'}}>Usuario:</b> {getUser(selectedTicket.userId)?.name||'—'}
              </div>}
              <div style={{fontSize:13,color:'#374151',lineHeight:1.6}}>{selectedTicket.description}</div>
            </div>
            {/* Status buttons */}
            <div style={{padding:'12px 18px',borderBottom:'1px solid #f1f5f9',display:'flex',gap:6}}>
              {['open','in_progress','resolved'].map(s=>(
                <button key={s} onClick={()=>changeStatus(selectedTicket.id,s)}
                  style={{flex:1,padding:'6px 4px',borderRadius:7,border:`1.5px solid ${selectedTicket.status===s?'#2563eb':'#e2e8f0'}`,background:selectedTicket.status===s?'#eff6ff':'transparent',fontSize:11,fontWeight:700,cursor:'pointer',color:selectedTicket.status===s?'#2563eb':'#94a3b8',fontFamily:'inherit',transition:'all 0.15s'}}>
                  {statusLabel[s]}
                </button>
              ))}
            </div>
            {/* Asignacion / gestion */}
            <div style={{padding:'12px 18px',borderBottom:'1px solid #f1f5f9',display:'grid',gridTemplateColumns:'1fr 1fr',gap:10}}>
              <div>
                <label style={fLbl}>Asignado a</label>
                <select value={selectedTicket.assigneeId||''} style={fInp}
                  onChange={e=>patchField(selectedTicket.id,{assigneeId:e.target.value||null}, e.target.value?('Asignado a '+(tecName(e.target.value)||'tecnico')):'Sin asignar')}>
                  <option value=''>Sin asignar</option>
                  {tecnicos.map(u=><option key={u.id} value={u.id}>{u.nombre||u.username}</option>)}
                </select>
              </div>
              <div>
                <label style={fLbl}>Vence</label>
                <input type='date' value={(selectedTicket.dueDate||'').slice(0,10)} style={fInp}
                  onChange={e=>patchField(selectedTicket.id,{dueDate:e.target.value||null})} />
              </div>
              <div>
                <label style={fLbl}>Prioridad</label>
                <select value={selectedTicket.priority} style={fInp}
                  onChange={e=>patchField(selectedTicket.id,{priority:e.target.value}, 'Prioridad: '+priorityLabel[e.target.value])}>
                  {['urgent','high','medium','low'].map(p=><option key={p} value={p}>{priorityLabel[p]}</option>)}
                </select>
              </div>
              <div>
                <label style={fLbl}>Horas facturables</label>
                <input type='number' min='0' step='0.25' value={selectedTicket.billableHours||0} style={fInp}
                  onChange={e=>patchField(selectedTicket.id,{billableHours:Number(e.target.value)})} />
              </div>
            </div>
            {/* History */}
            <div style={{padding:'12px 18px',borderBottom:'1px solid #f1f5f9',maxHeight:200,overflowY:'auto'}}>
              <div style={{fontSize:11,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:8}}>Historial</div>
              {(selectedTicket.history||[]).map((h,i)=>(
                <div key={i} style={{display:'flex',gap:8,marginBottom:8}}>
                  <div style={{width:6,height:6,borderRadius:'50%',background:'#cbd5e1',flexShrink:0,marginTop:5}} />
                  <div>
                    <div style={{fontSize:12,color:'#374151'}}>{h.note}</div>
                    <div style={{fontSize:10,color:'#94a3b8'}}>{DB.formatDateTime(h.date)} · {h.author}</div>
                  </div>
                </div>
              ))}
            </div>
            {/* Add note */}
            <div style={{padding:'12px 18px'}}>
              <div style={{fontSize:11,fontWeight:700,color:'#94a3b8',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:6}}>Agregar nota</div>
              <div style={{display:'flex',gap:8}}>
                <input value={noteText} onChange={e=>setNoteText(e.target.value)}
                  onKeyDown={e=>e.key==='Enter'&&addNote(selectedTicket.id)}
                  placeholder="Escribe una nota y presiona Enter..."
                  style={{flex:1,padding:'7px 10px',border:'1.5px solid #e2e8f0',borderRadius:7,fontSize:12,fontFamily:'inherit',outline:'none'}}
                  onFocus={e=>e.target.style.borderColor='#2563eb'} onBlur={e=>e.target.style.borderColor='#e2e8f0'} />
                <Btn size="sm" icon="plus" onClick={()=>addNote(selectedTicket.id)}>Agregar</Btn>
              </div>
            </div>

            {/* Ticket Tools Panel */}
            <TicketToolsPanel ticket={selectedTicket} setData={setData} toast={toast}
              company={companies.find(c=>c.id===selectedTicket.companyId)}
              user={users.find(u=>u.id===selectedTicket.userId)}/>
          </Card>
        )}
      </div>

      <Modal open={showAdd} onClose={()=>setShowAdd(false)} title="Nuevo ticket" width={580}>
        <TicketForm companies={companies} users={users} onSave={addTicket} onCancel={()=>setShowAdd(false)} />
      </Modal>
      <Modal open={!!editId} onClose={()=>setEditId(null)} title="Editar ticket" width={580}>
        {editId && <TicketForm initial={tickets.find(t=>t.id===editId)} companies={companies} users={users} onSave={saveEdit} onCancel={()=>setEditId(null)} />}
      </Modal>
      <ConfirmDialog open={!!deleteId} title="¿Eliminar ticket?" message="Esta acción no se puede deshacer."
        onConfirm={deleteTicket} onCancel={()=>setDeleteId(null)} />
    </div>
  );
}

window.Tickets = Tickets;


/* ===== js/Credentials.jsx ===== */

function CredentialForm({ initial={}, companies=[], users=[], onSave, onCancel }) {
  const [form, setForm] = React.useState({
    companyId:'', userId:'', service:'', username:'', password:'', url:'', notes:'', ...initial
  });
  const [showPwd, setShowPwd] = React.useState(false);
  const pwScore = (p)=>{ if(!p) return 0; let v=0; if(p.length>=8)v++; if(p.length>=12)v++; if(/[A-Z]/.test(p)&&/[a-z]/.test(p))v++; if(/[0-9]/.test(p))v++; if(/[^A-Za-z0-9]/.test(p))v++; return Math.min(v,4); };
  const genPw = ()=>{ const cs='ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789!@#$%&*'; const a=new Uint32Array(16); crypto.getRandomValues(a); let p=''; for(let i=0;i<16;i++)p+=cs[a[i]%cs.length]; set('password')(p); setShowPwd(true); };
  const set = k => v => setForm(f=>({...f,[k]:v}));
  const compUsers = users.filter(u=>u.companyId===form.companyId);
  return (
    <div style={{display:'flex',flexDirection:'column',gap:12}}>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Select label="Empresa" value={form.companyId} onChange={v=>{set('companyId')(v);set('userId')('');}} required
          options={companies.map(c=>({value:c.id,label:c.name}))} />
        <Select label="Usuario (opcional)" value={form.userId} onChange={set('userId')}
          options={compUsers.map(u=>({value:u.id,label:u.name}))} placeholder="General / Sin usuario" />
      </div>
      <Input label="Servicio / Sistema" value={form.service} onChange={set('service')} required placeholder="Ej: Router, NAS, Portal SAT..." />
      <Input label="URL / IP" value={form.url} onChange={set('url')} placeholder="192.168.1.1 o https://portal.com" />
      <Input label="Usuario / Login" value={form.username} onChange={set('username')} required placeholder="admin" />
      <div style={{display:'flex',flexDirection:'column',gap:4}}>
        <label style={{fontSize:12,fontWeight:600,color:'#64748b',textTransform:'uppercase',letterSpacing:'0.05em'}}>Contraseña <span style={{color:'#ef4444'}}>*</span></label>
        <div style={{position:'relative'}}>
          <input type={showPwd?'text':'password'} value={form.password} onChange={e=>set('password')(e.target.value)}
            placeholder="Contraseña segura"
            style={{width:'100%',paddingRight:40,paddingLeft:12,paddingTop:9,paddingBottom:9,border:'1.5px solid #e2e8f0',borderRadius:8,fontSize:14,fontFamily:'monospace',outline:'none',background:'#fff',color:'#0f172a',boxSizing:'border-box',transition:'border-color 0.15s'}}
            onFocus={e=>e.target.style.borderColor='#2563eb'} onBlur={e=>e.target.style.borderColor='#e2e8f0'} />
          <button onClick={()=>setShowPwd(v=>!v)} type="button"
            style={{position:'absolute',right:8,top:'50%',transform:'translateY(-50%)',background:'none',border:'none',cursor:'pointer',color:'#94a3b8',display:'flex',padding:4}}>
            <Icon name={showPwd?'eye-off':'eye'} size={16} />
          </button>
        </div>
      </div>
      {form.password && (()=>{ const sc=pwScore(form.password); const cols=['#ef4444','#f59e0b','#eab308','#22c55e']; const lbls=['Débil','Regular','Buena','Fuerte']; const idx=Math.max(0,sc-1); return (
        <div style={{marginTop:-6}}>
          <div style={{display:'flex',gap:3,marginBottom:4}}>{[0,1,2,3].map(i=><div key={i} style={{flex:1,height:4,borderRadius:2,background:i<sc?cols[idx]:'#e2e8f0'}}/>)}</div>
          <div style={{fontSize:10,color:'#94a3b8',display:'flex',justifyContent:'space-between'}}><span>Fuerza: {lbls[idx]}</span><button type="button" onClick={genPw} style={{background:'none',border:'none',color:'#2563eb',cursor:'pointer',fontSize:10,fontWeight:600,fontFamily:'inherit'}}>Generar segura</button></div>
        </div>
      ); })()}
      <Textarea label="Notas" value={form.notes} onChange={set('notes')} placeholder="Información adicional..." rows={2} />
      <div style={{display:'flex',justifyContent:'flex-end',gap:8,paddingTop:8,borderTop:'1px solid #f1f5f9'}}>
        <Btn variant="secondary" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" icon="check" onClick={()=>(form.service.trim()&&form.username.trim()&&form.companyId)&&onSave(form)}>Guardar credencial</Btn>
      </div>
    </div>
  );
}

function Credentials({ data, setData, navigate, toast }) {
  const { companies, users, credentials } = data;
  const [search, setSearch]     = React.useState('');
  const [compFilter, setComp]   = React.useState('');
  const [showAdd, setShowAdd]   = React.useState(false);
  const [editId, setEditId]     = React.useState(null);
  const [deleteId, setDeleteId] = React.useState(null);
  const [visiblePwds, setVisible] = React.useState({});

  const filtered = credentials.filter(cr=>{
    const q = search.toLowerCase();
    const matchQ = !q || cr.service.toLowerCase().includes(q) || cr.username.toLowerCase().includes(q) || (cr.url||'').toLowerCase().includes(q) || (cr.notes||'').toLowerCase().includes(q);
    const matchC = !compFilter || cr.companyId===compFilter;
    return matchQ && matchC;
  });

  function addCred(form) {
    const cr = { ...form, id: DB.generateId('cr'), lastChanged: new Date().toISOString() };
    setData(d=>{ const nd={...d,credentials:[...d.credentials,cr]}; DB.saveData(nd); return nd; });
    setShowAdd(false); toast('Credencial guardada');
  }
  function saveEdit(form) {
    setData(d=>{ const nd={...d,credentials:d.credentials.map(cr=>cr.id===editId?{...cr,...form,lastChanged: form.password!==cr.password?new Date().toISOString():(cr.lastChanged||null)}:cr)}; DB.saveData(nd); return nd; });
    setEditId(null); toast('Credencial actualizada');
  }
  function deleteCred() {
    setData(d=>{ const nd={...d,credentials:d.credentials.filter(cr=>cr.id!==deleteId)}; DB.saveData(nd); return nd; });
    setDeleteId(null); toast('Credencial eliminada','error');
  }
  function copyText(text, label) {
    navigator.clipboard.writeText(text).then(()=>toast(`${label} copiado ✓`));
  }
  function togglePwd(id) { setVisible(v=>({...v,[id]:!v[id]})); }

  const getCompany = id => companies.find(c=>c.id===id);
  const getUser    = id => users.find(u=>u.id===id);

  const grouped = {};
  filtered.forEach(cr=>{
    const key = cr.companyId || 'none';
    if(!grouped[key]) grouped[key]=[];
    grouped[key].push(cr);
  });

  return (
    <div style={{padding:'32px 36px',maxWidth:980}}>
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:24}}>
        <div>
          <h1 style={{margin:0,fontSize:22,fontWeight:800,color:'#0f172a'}}>Credenciales / Contraseñas</h1>
          <p style={{margin:'4px 0 0',fontSize:13,color:'#94a3b8'}}>{credentials.length} credencial{credentials.length!==1?'es':''} almacenada{credentials.length!==1?'s':''}</p>
        </div>
        <Btn icon="plus" onClick={()=>setShowAdd(true)}>Nueva credencial</Btn>
      </div>

      <div style={{background:'#fffbeb',border:'1.5px solid #fde68a',borderRadius:10,padding:'10px 14px',marginBottom:20,display:'flex',alignItems:'center',gap:8}}>
        <Icon name="shield" size={15} color="#ca8a04" />
        <span style={{fontSize:12,color:'#92400e',fontWeight:500}}>
          <b>Aviso de seguridad:</b> Las contraseñas se almacenan en localStorage. Para producción, usa cifrado en tu servidor.
        </span>
      </div>

      <div style={{display:'flex',gap:10,marginBottom:20}}>
        <div style={{flex:1,position:'relative'}}>
          <span style={{position:'absolute',left:10,top:'50%',transform:'translateY(-50%)',color:'#94a3b8',pointerEvents:'none'}}><Icon name="search" size={15}/></span>
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar servicio, usuario, URL..."
            style={{width:'100%',paddingLeft:34,paddingRight:12,paddingTop:9,paddingBottom:9,border:'1.5px solid #e2e8f0',borderRadius:9,fontSize:13,fontFamily:'inherit',outline:'none',background:'#fff',boxSizing:'border-box'}}
            onFocus={e=>e.target.style.borderColor='#2563eb'} onBlur={e=>e.target.style.borderColor='#e2e8f0'} />
        </div>
        <Select value={compFilter} onChange={setComp} placeholder="Todas las empresas"
          options={companies.map(c=>({value:c.id,label:c.name}))} />
      </div>

      {filtered.length===0 ? (
        <EmptyState icon="key" title="Sin credenciales" desc="No hay credenciales que coincidan." action={<Btn icon="plus" onClick={()=>setShowAdd(true)}>Agregar credencial</Btn>} />
      ) : (
        Object.entries(grouped).map(([compId, creds])=>{
          const comp = getCompany(compId);
          return (
            <div key={compId} style={{marginBottom:24}}>
              <div style={{display:'flex',alignItems:'center',gap:8,marginBottom:10}}>
                <div style={{width:28,height:28,borderRadius:8,background:'#eff6ff',display:'flex',alignItems:'center',justifyContent:'center',fontSize:12,fontWeight:800,color:'#2563eb'}}>
                  {(comp?.name||'?').charAt(0)}
                </div>
                <span style={{fontSize:13,fontWeight:700,color:'#0f172a'}}>{comp?.name||'Sin empresa'}</span>
                <span style={{fontSize:11,color:'#94a3b8'}}>{creds.length} credencial{creds.length!==1?'es':''}</span>
              </div>
              <Card style={{padding:0}}>
                {creds.map((cr,i)=>{
                  const user = getUser(cr.userId);
                  const pwdVisible = visiblePwds[cr.id];
                  return (
                    <div key={cr.id} style={{padding:'14px 18px',borderBottom:i<creds.length-1?'1px solid #f1f5f9':'none'}}>
                      <div style={{display:'flex',alignItems:'flex-start',gap:12}}>
                        <div style={{width:36,height:36,borderRadius:9,background:'#f0fdf4',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
                          <Icon name="key" size={16} color="#16a34a" />
                        </div>
                        <div style={{flex:1,minWidth:0}}>
                          <div style={{display:'flex',alignItems:'center',gap:8,marginBottom:4}}>
                            <span style={{fontSize:14,fontWeight:700,color:'#0f172a'}}>{cr.service}</span>
                            {user&&<Badge label={user.name} color="blue" />}
                          </div>
                          {cr.url&&<div style={{fontSize:11,color:'#94a3b8',fontFamily:'monospace',marginBottom:8}}>{cr.url}</div>}
                          <div style={{display:'flex',gap:16,flexWrap:'wrap'}}>
                            {/* Username */}
                            <div style={{display:'flex',alignItems:'center',gap:6}}>
                              <span style={{fontSize:11,fontWeight:600,color:'#94a3b8',textTransform:'uppercase'}}>Usuario</span>
                              <span style={{fontSize:13,fontFamily:'monospace',color:'#374151'}}>{cr.username}</span>
                              <button onClick={()=>copyText(cr.username,'Usuario')} style={{background:'none',border:'none',cursor:'pointer',padding:2,color:'#94a3b8',display:'flex'}}
                                onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                                <Icon name="copy" size={12} />
                              </button>
                            </div>
                            {/* Password */}
                            <div style={{display:'flex',alignItems:'center',gap:6}}>
                              <span style={{fontSize:11,fontWeight:600,color:'#94a3b8',textTransform:'uppercase'}}>Contraseña</span>
                              <span style={{fontSize:13,fontFamily:'monospace',color:'#374151',letterSpacing:pwdVisible?'normal':'0.1em'}}>
                                {pwdVisible ? cr.password : '••••••••••'}
                              </span>
                              <button onClick={()=>togglePwd(cr.id)} style={{background:'none',border:'none',cursor:'pointer',padding:2,color:'#94a3b8',display:'flex'}}
                                onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                                <Icon name={pwdVisible?'eye-off':'eye'} size={13} />
                              </button>
                              <button onClick={()=>copyText(cr.password,'Contraseña')} style={{background:'none',border:'none',cursor:'pointer',padding:2,color:'#94a3b8',display:'flex'}}
                                onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                                <Icon name="copy" size={12} />
                              </button>
                            </div>
                          </div>
                          {cr.notes&&<div style={{marginTop:6,fontSize:11,color:'#94a3b8'}}>{cr.notes}</div>}
                        </div>
                        <div style={{display:'flex',gap:4,flexShrink:0}}>
                          <button onClick={()=>setEditId(cr.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}
                            onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                            <Icon name="pencil" size={14}/>
                          </button>
                          <button onClick={()=>setDeleteId(cr.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}
                            onMouseEnter={e=>e.currentTarget.style.color='#ef4444'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}>
                            <Icon name="trash" size={14}/>
                          </button>
                        </div>
                      </div>
                    </div>
                  );
                })}
              </Card>
            </div>
          );
        })
      )}

      <Modal open={showAdd} onClose={()=>setShowAdd(false)} title="Nueva credencial" width={540}>
        <CredentialForm companies={companies} users={users} onSave={addCred} onCancel={()=>setShowAdd(false)} />
      </Modal>
      <Modal open={!!editId} onClose={()=>setEditId(null)} title="Editar credencial" width={540}>
        {editId && <CredentialForm initial={credentials.find(c=>c.id===editId)} companies={companies} users={users} onSave={saveEdit} onCancel={()=>setEditId(null)} />}
      </Modal>
      <ConfirmDialog open={!!deleteId} title="¿Eliminar credencial?" message="Esta acción no se puede deshacer."
        onConfirm={deleteCred} onCancel={()=>setDeleteId(null)} />
    </div>
  );
}

window.Credentials = Credentials;


/* ===== js/Maintenance.jsx ===== */

function MaintenanceForm({ initial={}, companies=[], onSave, onCancel }) {
  const today = new Date().toISOString().split('T')[0];
  const [form, setForm] = React.useState({
    companyId:'', title:'', type:'preventivo', scheduledDate:today,
    completedDate:'', status:'pending', technician:'Soporte IT', frequency:'none', notes:'', ...initial
  });
  const set = k => v => setForm(f=>({...f,[k]:v}));
  return (
    <div style={{display:'flex',flexDirection:'column',gap:12}}>
      <Select label="Empresa" value={form.companyId} onChange={set('companyId')} required
        options={companies.map(c=>({value:c.id,label:c.name}))} />
      <Input label="Título / Descripción" value={form.title} onChange={set('title')} required placeholder="Ej: Mantenimiento preventivo mensual" />
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Select label="Tipo" value={form.type} onChange={set('type')} options={[
          {value:'preventivo',label:'Preventivo'},{value:'correctivo',label:'Correctivo'},
          {value:'revision',label:'Revisión'},{value:'instalacion',label:'Instalación'},
          {value:'visita',label:'Visita técnica'}]} />
        <Select label="Estado" value={form.status} onChange={set('status')} options={[
          {value:'pending',label:'Pendiente'},{value:'completed',label:'Completado'},
          {value:'cancelled',label:'Cancelado'}]} />
      </div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Input label="Fecha programada" value={form.scheduledDate} onChange={set('scheduledDate')} type="date" required />
        <Input label="Fecha completado" value={form.completedDate||''} onChange={set('completedDate')} type="date" hint="Dejar vacío si aún no se realiza" />
      </div>
      <Input label="Técnico asignado" value={form.technician} onChange={set('technician')} placeholder="Nombre del técnico" />
      <Select label="Recurrencia" value={form.frequency||'none'} onChange={set('frequency')} options={[
        {value:'none',label:'Sin recurrencia'},{value:'monthly',label:'Mensual'},{value:'quarterly',label:'Trimestral'},
        {value:'biannual',label:'Semestral'},{value:'annual',label:'Anual'}]} hint="Al completarlo se agenda el siguiente automáticamente" />
      <Textarea label="Notas / Descripción de trabajos" value={form.notes} onChange={set('notes')} placeholder="Detalle de los trabajos a realizar o realizados..." rows={3} />
      <div style={{display:'flex',justifyContent:'flex-end',gap:8,paddingTop:8,borderTop:'1px solid #f1f5f9'}}>
        <Btn variant="secondary" onClick={onCancel}>Cancelar</Btn>
        <Btn variant="primary" icon="check" onClick={()=>form.title.trim()&&form.companyId&&onSave(form)}>Guardar</Btn>
      </div>
    </div>
  );
}

function Maintenances({ data, setData, navigate, toast, initialCompanyId=null }) {
  const { companies, maintenances: allMaint = [] } = data;
  const [search, setSearch]         = React.useState('');
  const [compFilter, setCompFilter] = React.useState(initialCompanyId||'');
  const [typeFilter, setTypeFilter] = React.useState('');
  const [statusFilter, setStatus]   = React.useState('');
  const [showAdd, setShowAdd]       = React.useState(false);
  const [editId, setEditId]         = React.useState(null);
  const [deleteId, setDeleteId]     = React.useState(null);
  const [view, setView]             = React.useState('list'); // list | calendar

  const typeLabel  = {preventivo:'Preventivo',correctivo:'Correctivo',revision:'Revisión',instalacion:'Instalación',visita:'Visita'};
  const typeColor  = {preventivo:'blue',correctivo:'red',revision:'purple',instalacion:'green',visita:'orange'};
  const statusLabel = {pending:'Pendiente',completed:'Completado',cancelled:'Cancelado'};
  const statusColor = {pending:'blue',completed:'green',cancelled:'slate'};

  const filtered = allMaint.filter(m=>{
    const q = search.toLowerCase();
    const matchQ = !q || m.title.toLowerCase().includes(q) || (m.notes||'').toLowerCase().includes(q);
    const matchC = !compFilter || m.companyId===compFilter;
    const matchT = !typeFilter || m.type===typeFilter;
    const matchS = !statusFilter || m.status===statusFilter;
    return matchQ && matchC && matchT && matchS;
  }).sort((a,b)=>new Date(a.scheduledDate)-new Date(b.scheduledDate));

  const upcoming = filtered.filter(m=>m.status==='pending' && new Date(m.scheduledDate) >= new Date());
  const overdue  = filtered.filter(m=>m.status==='pending' && new Date(m.scheduledDate) < new Date());
  const done     = filtered.filter(m=>m.status==='completed');

  function addMaint(form) {
    const m = {...form, id:DB.generateId('m')};
    setData(d=>{ const nd={...d,maintenances:[...(d.maintenances||[]),m]}; DB.saveData(nd); return nd; });
    setShowAdd(false); toast('Mantenimiento agendado');
  }
  function saveEdit(form) {
    setData(d=>{ const nd={...d,maintenances:(d.maintenances||[]).map(m=>m.id===editId?{...m,...form}:m)}; DB.saveData(nd); return nd; });
    setEditId(null); toast('Mantenimiento actualizado');
  }
  function deleteMaint() {
    setData(d=>{ const nd={...d,maintenances:(d.maintenances||[]).filter(m=>m.id!==deleteId)}; DB.saveData(nd); return nd; });
    setDeleteId(null); toast('Mantenimiento eliminado','error');
  }
  function markDone(id) {
    const today = new Date().toISOString().split('T')[0];
    setData(d=>{
      const list = (d.maintenances||[]);
      const done = list.find(m=>m.id===id);
      let next = list.map(m=>m.id===id?{...m,status:'completed',completedDate:today}:m);
      const add = {monthly:1,quarterly:3,biannual:6,annual:12}[done&&done.frequency];
      if (done && add) {
        const base = new Date(done.scheduledDate); base.setMonth(base.getMonth()+add);
        next = [...next, {...done, id:DB.generateId('mnt'), status:'pending', completedDate:'', scheduledDate: base.toISOString().split('T')[0]}];
      }
      const nd={...d,maintenances:next}; DB.saveData(nd); return nd;
    });
    toast('Marcado como completado ✓');
  }

  const getCompany = id => companies.find(c=>c.id===id);

  function MaintCard({ m }) {
    const comp = getCompany(m.companyId);
    const isOverdue = m.status==='pending' && new Date(m.scheduledDate) < new Date();
    return (
      <div style={{padding:'14px 18px',borderBottom:'1px solid #f1f5f9',display:'flex',alignItems:'flex-start',gap:12,transition:'background 0.1s'}}
        onMouseEnter={e=>e.currentTarget.style.background='#f8fafc'} onMouseLeave={e=>e.currentTarget.style.background='transparent'}>
        <div style={{width:38,height:38,borderRadius:10,background:isOverdue?'#fef2f2':m.status==='completed'?'#f0fdf4':'#eff6ff',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
          <Icon name={m.status==='completed'?'check':isOverdue?'alert':'clock'} size={16} color={isOverdue?'#dc2626':m.status==='completed'?'#16a34a':'#2563eb'}/>
        </div>
        <div style={{flex:1,minWidth:0}}>
          <div style={{fontSize:13,fontWeight:700,color:'#0f172a',marginBottom:3}}>{m.title}</div>
          <div style={{fontSize:12,color:'#64748b',marginBottom:6,display:'flex',alignItems:'center',gap:6}}>
            <span style={{display:'flex',alignItems:'center',gap:4}}><Icon name="building" size={11} color="#94a3b8"/>{comp?.name||'—'}</span>
            {m.technician && <span>· {m.technician}</span>}
          </div>
          <div style={{display:'flex',gap:6,flexWrap:'wrap',alignItems:'center'}}>
            <Badge label={typeLabel[m.type]||m.type} color={typeColor[m.type]||'slate'}/>
            <Badge label={statusLabel[m.status]} color={isOverdue?'red':statusColor[m.status]}/>
            <span style={{fontSize:11,color:isOverdue?'#dc2626':'#94a3b8',fontWeight:isOverdue?700:400}}>
              {isOverdue?'⚠ Vencido: ':'📅 '}{DB.formatDate(m.scheduledDate)}
            </span>
            {m.status==='completed'&&m.completedDate&&<span style={{fontSize:11,color:'#16a34a'}}>✓ {DB.formatDate(m.completedDate)}</span>}
          </div>
          {m.notes&&<div style={{fontSize:11,color:'#94a3b8',marginTop:5,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{m.notes}</div>}
        </div>
        <div style={{display:'flex',gap:4,flexShrink:0}}>
          {m.status==='pending'&&<button onClick={()=>markDone(m.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}} title="Marcar completado"
            onMouseEnter={e=>e.currentTarget.style.color='#16a34a'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}><Icon name="check" size={14}/></button>}
          <button onClick={()=>setEditId(m.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}
            onMouseEnter={e=>e.currentTarget.style.color='#2563eb'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}><Icon name="pencil" size={14}/></button>
          <button onClick={()=>setDeleteId(m.id)} style={{background:'none',border:'none',cursor:'pointer',padding:5,borderRadius:6,color:'#94a3b8',display:'flex'}}
            onMouseEnter={e=>e.currentTarget.style.color='#ef4444'} onMouseLeave={e=>e.currentTarget.style.color='#94a3b8'}><Icon name="trash" size={14}/></button>
        </div>
      </div>
    );
  }

  // Mini calendar view (current month)
  function CalendarView() {
    const now = new Date();
    const [calYear, setCalYear]   = React.useState(now.getFullYear());
    const [calMonth, setCalMonth] = React.useState(now.getMonth());
    const firstDay = new Date(calYear, calMonth, 1).getDay();
    const daysInMonth = new Date(calYear, calMonth+1, 0).getDate();
    const monthName = new Date(calYear, calMonth).toLocaleDateString('es-MX',{month:'long',year:'numeric'});
    const monthMaint = allMaint.filter(m=>{
      const d = new Date(m.scheduledDate);
      return d.getFullYear()===calYear && d.getMonth()===calMonth;
    });

    function getDayMaint(day) {
      return monthMaint.filter(m=>new Date(m.scheduledDate).getDate()===day);
    }

    return (
      <Card style={{padding:'18px 20px'}}>
        <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:16}}>
          <button onClick={()=>{if(calMonth===0){setCalMonth(11);setCalYear(y=>y-1);}else setCalMonth(m=>m-1);}} style={{background:'none',border:'none',cursor:'pointer',padding:4,color:'#64748b',display:'flex'}}><Icon name="chevron-left" size={18}/></button>
          <span style={{fontSize:14,fontWeight:700,color:'#0f172a',textTransform:'capitalize'}}>{monthName}</span>
          <button onClick={()=>{if(calMonth===11){setCalMonth(0);setCalYear(y=>y+1);}else setCalMonth(m=>m+1);}} style={{background:'none',border:'none',cursor:'pointer',padding:4,color:'#64748b',display:'flex'}}><Icon name="chevron-right" size={18}/></button>
        </div>
        <div style={{display:'grid',gridTemplateColumns:'repeat(7,1fr)',gap:2,marginBottom:4}}>
          {['Dom','Lun','Mar','Mié','Jue','Vie','Sáb'].map(d=>(
            <div key={d} style={{textAlign:'center',fontSize:10,fontWeight:700,color:'#94a3b8',padding:'4px 0'}}>{d}</div>
          ))}
        </div>
        <div style={{display:'grid',gridTemplateColumns:'repeat(7,1fr)',gap:2}}>
          {Array.from({length:firstDay}).map((_,i)=><div key={'e'+i}/>)}
          {Array.from({length:daysInMonth}).map((_,i)=>{
            const day = i+1;
            const dayMaint = getDayMaint(day);
            const isToday = new Date().getDate()===day && new Date().getMonth()===calMonth && new Date().getFullYear()===calYear;
            return (
              <div key={day} style={{minHeight:42,borderRadius:7,background:isToday?'#eff6ff':dayMaint.length?'#f8fafc':'transparent',border:isToday?'1.5px solid #2563eb':'1.5px solid transparent',padding:'4px 5px',position:'relative'}}>
                <div style={{fontSize:11,fontWeight:isToday?800:500,color:isToday?'#2563eb':'#374151',marginBottom:2}}>{day}</div>
                {dayMaint.slice(0,2).map(m=>(
                  <div key={m.id} style={{fontSize:9,background:typeColor[m.type]?`var(--c-${typeColor[m.type]})`:undefined,padding:'1px 4px',borderRadius:3,marginBottom:1,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',
                    backgroundColor:m.status==='completed'?'#d1fae5':m.status==='cancelled'?'#f1f5f9':'#dbeafe',
                    color:m.status==='completed'?'#065f46':m.status==='cancelled'?'#94a3b8':'#1e40af',fontWeight:600}}>
                    {m.title.substring(0,14)}{m.title.length>14?'…':''}
                  </div>
                ))}
                {dayMaint.length>2&&<div style={{fontSize:9,color:'#94a3b8'}}>+{dayMaint.length-2} más</div>}
              </div>
            );
          })}
        </div>
      </Card>
    );
  }

  return (
    <div style={{padding:'32px 36px',maxWidth:1100}}>
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:24}}>
        <div>
          <h1 style={{margin:0,fontSize:22,fontWeight:800,color:'#0f172a'}}>Mantenimientos / Visitas</h1>
          <p style={{margin:'4px 0 0',fontSize:13,color:'#94a3b8'}}>{upcoming.length} próximo{upcoming.length!==1?'s':''} · {overdue.length} vencido{overdue.length!==1?'s':''} · {done.length} completado{done.length!==1?'s':''}</p>
        </div>
        <div style={{display:'flex',gap:8}}>
          <div style={{display:'flex',gap:2,background:'#f1f5f9',borderRadius:8,padding:3}}>
            {[{v:'list',icon:'menu'},{v:'calendar',icon:'chart-bar'}].map(b=>(
              <button key={b.v} onClick={()=>setView(b.v)} style={{padding:'5px 10px',borderRadius:6,border:'none',background:view===b.v?'#fff':'transparent',cursor:'pointer',color:view===b.v?'#0f172a':'#94a3b8',boxShadow:view===b.v?'0 1px 3px rgba(0,0,0,0.1)':'none',display:'flex',alignItems:'center',gap:4,fontSize:12,fontFamily:'inherit',fontWeight:600}}>
                <Icon name={b.icon} size={14}/>{b.v==='list'?'Lista':'Calendario'}
              </button>
            ))}
          </div>
          <Btn icon="plus" onClick={()=>setShowAdd(true)}>Agendar mantenimiento</Btn>
        </div>
      </div>

      {/* Stats */}
      <div style={{display:'grid',gridTemplateColumns:'repeat(4,1fr)',gap:12,marginBottom:20}}>
        {[
          {label:'Total',val:allMaint.length,color:'#2563eb',bg:'#eff6ff'},
          {label:'Próximos',val:upcoming.length,color:'#7c3aed',bg:'#faf5ff'},
          {label:'Vencidos',val:overdue.length,color:'#dc2626',bg:'#fef2f2'},
          {label:'Completados',val:done.length,color:'#16a34a',bg:'#f0fdf4'},
        ].map(s=>(
          <div key={s.label} style={{background:s.bg,borderRadius:10,padding:'12px 16px'}}>
            <div style={{fontSize:22,fontWeight:800,color:s.color}}>{s.val}</div>
            <div style={{fontSize:12,color:'#64748b',marginTop:2}}>{s.label}</div>
          </div>
        ))}
      </div>

      {/* Filters */}
      <div style={{display:'flex',gap:10,marginBottom:18,flexWrap:'wrap'}}>
        <div style={{flex:1,minWidth:180,position:'relative'}}>
          <span style={{position:'absolute',left:10,top:'50%',transform:'translateY(-50%)',color:'#94a3b8',pointerEvents:'none'}}><Icon name="search" size={15}/></span>
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar mantenimiento..."
            style={{width:'100%',paddingLeft:34,paddingRight:12,paddingTop:9,paddingBottom:9,border:'1.5px solid #e2e8f0',borderRadius:9,fontSize:13,fontFamily:'inherit',outline:'none',background:'#fff',boxSizing:'border-box'}}
            onFocus={e=>e.target.style.borderColor='#2563eb'} onBlur={e=>e.target.style.borderColor='#e2e8f0'} />
        </div>
        <Select value={compFilter} onChange={setCompFilter} placeholder="Todas las empresas" options={companies.map(c=>({value:c.id,label:c.name}))} />
        <Select value={typeFilter} onChange={setTypeFilter} placeholder="Todos los tipos"
          options={[{value:'preventivo',label:'Preventivo'},{value:'correctivo',label:'Correctivo'},{value:'revision',label:'Revisión'},{value:'instalacion',label:'Instalación'},{value:'visita',label:'Visita'}]} />
        <Select value={statusFilter} onChange={setStatus} placeholder="Todos los estados"
          options={[{value:'pending',label:'Pendientes'},{value:'completed',label:'Completados'},{value:'cancelled',label:'Cancelados'}]} />
      </div>

      {view==='calendar' ? <CalendarView /> : (
        filtered.length===0 ? (
          <EmptyState icon="clock" title="Sin mantenimientos" desc="No hay mantenimientos que coincidan." action={<Btn icon="plus" onClick={()=>setShowAdd(true)}>Agendar mantenimiento</Btn>} />
        ) : (
          <div style={{display:'flex',flexDirection:'column',gap:16}}>
            {overdue.length>0&&(
              <div>
                <div style={{fontSize:12,fontWeight:700,color:'#dc2626',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:8,display:'flex',alignItems:'center',gap:6}}><Icon name="alert" size={13} color="#dc2626"/>Vencidos ({overdue.length})</div>
                <Card style={{padding:0}}>{overdue.map(m=><MaintCard key={m.id} m={m}/>)}</Card>
              </div>
            )}
            {upcoming.length>0&&(
              <div>
                <div style={{fontSize:12,fontWeight:700,color:'#2563eb',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:8,display:'flex',alignItems:'center',gap:6}}><Icon name="clock" size={13} color="#2563eb"/>Próximos ({upcoming.length})</div>
                <Card style={{padding:0}}>{upcoming.map(m=><MaintCard key={m.id} m={m}/>)}</Card>
              </div>
            )}
            {done.length>0&&(
              <div>
                <div style={{fontSize:12,fontWeight:700,color:'#16a34a',textTransform:'uppercase',letterSpacing:'0.06em',marginBottom:8,display:'flex',alignItems:'center',gap:6}}><Icon name="check" size={13} color="#16a34a"/>Completados ({done.length})</div>
                <Card style={{padding:0}}>{done.map(m=><MaintCard key={m.id} m={m}/>)}</Card>
              </div>
            )}
          </div>
        )
      )}

      <Modal open={showAdd} onClose={()=>setShowAdd(false)} title="Agendar mantenimiento / visita" width={560}>
        <MaintenanceForm companies={companies} initial={initialCompanyId?{companyId:initialCompanyId}:{}} onSave={addMaint} onCancel={()=>setShowAdd(false)} />
      </Modal>
      <Modal open={!!editId} onClose={()=>setEditId(null)} title="Editar mantenimiento" width={560}>
        {editId && <MaintenanceForm initial={allMaint.find(m=>m.id===editId)} companies={companies} onSave={saveEdit} onCancel={()=>setEditId(null)} />}
      </Modal>
      <ConfirmDialog open={!!deleteId} title="¿Eliminar mantenimiento?" message="Esta acción no se puede deshacer." onConfirm={deleteMaint} onCancel={()=>setDeleteId(null)} />
    </div>
  );
}

window.Maintenances = Maintenances;

