// LOLA Consola Web — AUDITORÍA (bitácora). Registro inmutable de todo lo que ocurre:
// accesos, cambios y acciones — quién, qué y cuándo. Búsqueda, rango de fechas, filtro por
// tipo, vista tabla/tarjetas y exportación CSV. Sobrescribe window.BitacoraView.
//
// TODO viene del backend real (GET /admin/bitacora → colección Bitacora en MongoDB,
// escrita por bitacora.service.js cada vez que ocurre una acción administrativa). No hay
// generador ni dato de ejemplo aquí — si la bitácora está vacía es porque todavía no ha
// ocurrido nada que registrar.

// ── Íconos locales ──
const _BI = (p, path) => React.createElement('svg', { width: p.size || 16, height: p.size || 16, viewBox: '0 0 24 24',
  fill: 'none', stroke: 'currentColor', strokeWidth: p.sw || 1.9, strokeLinecap: 'round', strokeLinejoin: 'round' }, path);
const BList = (p) => _BI(p, [React.createElement('path', { key: 1, d: 'M8 6h13M8 12h13M8 18h13' }), React.createElement('path', { key: 2, d: 'M3 6h.01M3 12h.01M3 18h.01' })]);
const BSearch = (p) => _BI(p, [React.createElement('circle', { key: 1, cx: 11, cy: 11, r: 7 }), React.createElement('path', { key: 2, d: 'm21 21-4.3-4.3' })]);
const BDownload = (p) => _BI(p, [React.createElement('path', { key: 1, d: 'M12 3v12' }), React.createElement('path', { key: 2, d: 'm7 12 5 5 5-5' }), React.createElement('path', { key: 3, d: 'M5 21h14' })]);
const BLock = (p) => _BI(p, [React.createElement('rect', { key: 1, x: 4, y: 11, width: 16, height: 10, rx: 2 }), React.createElement('path', { key: 2, d: 'M8 11V7a4 4 0 0 1 8 0v4' })]);

// ── Tipos de evento (agrupan las acciones reales que escribe el backend) ──
const B_TIPOS = {
  acceso: { label: 'Acceso', color: '#1D57A9', icon: 'User', grupo: 'accesos' },
  seguridad: { label: 'Seguridad', color: '#C0392B', icon: 'Shield', grupo: 'seguridad' },
  aprobacion: { label: 'Aprobación', color: '#1F8A5B', icon: 'Check', grupo: 'cambios' },
  rechazo: { label: 'Rechazo', color: '#C0392B', icon: 'X', grupo: 'cambios' },
  usuario: { label: 'Usuario', color: '#2E6EC4', icon: 'Users', grupo: 'cambios' },
  rol: { label: 'Rol / Permiso', color: '#7A5AF8', icon: 'Shield', grupo: 'seguridad' },
  comision: { label: 'Comisión', color: '#0E9CA6', icon: 'Wallet', grupo: 'cambios' },
  pago: { label: 'Pago', color: '#1F8A5B', icon: 'Tag', grupo: 'cambios' },
  publicidad: { label: 'Publicidad', color: '#7A5AF8', icon: 'Megaphone', grupo: 'cambios' },
  config: { label: 'Configuración', color: '#D98A0B', icon: 'Gear', grupo: 'cambios' },
  export: { label: 'Exportación', color: '#5B6470', icon: 'Download', grupo: 'accesos' },
};

// Etiqueta legible para cada `accion` real que escribe bitacora.service.js. Cualquier acción
// nueva que no esté aquí se muestra igual (versión legible del snake_case) en vez de romperse.
const ACCION_LABELS = {
  iniciar_sesion: 'Inició sesión', cerrar_sesion: 'Cerró sesión', intento_fallido: 'Intento de acceso fallido',
  aprobar_contrato: 'Aprobó contrato', rechazar_contrato: 'Rechazó contrato',
  cambiar_estado_usuario: 'Cambió el estado de un usuario', borrar_cuenta: 'Eliminó una cuenta',
  cambiar_comision: 'Actualizó la comisión', cambiar_config: 'Actualizó la configuración',
  confirmar_pago: 'Confirmó un pago', confirmar_recarga: 'Confirmó una recarga',
  confirmar_retiro: 'Confirmó un retiro', rechazar_retiro: 'Rechazó un retiro',
  crear_campania: 'Creó una campaña', actualizar_campania: 'Actualizó una campaña',
  eliminar_campania: 'Eliminó una campaña', toggle_campania: 'Activó/pausó una campaña',
  catalogo_transporte_crear: 'Creó un tipo de transporte', catalogo_transporte_editar: 'Editó un tipo de transporte',
  catalogo_transporte_eliminar: 'Eliminó un tipo de transporte',
  catalogo_carga_crear: 'Creó un tipo de carga', catalogo_carga_editar: 'Editó un tipo de carga',
  catalogo_carga_eliminar: 'Eliminó un tipo de carga',
};
const cap = (s) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : s);
const humanAccion = (a) => ACCION_LABELS[a] || cap(String(a || '').replace(/_/g, ' '));

function clasificar(accion) {
  const a = accion || '';
  if (a === 'iniciar_sesion' || a === 'cerrar_sesion') return 'acceso';
  if (a === 'intento_fallido') return 'seguridad';
  if (a === 'aprobar_contrato') return 'aprobacion';
  if (a === 'rechazar_contrato' || a === 'rechazar_retiro') return 'rechazo';
  if (a === 'cambiar_estado_usuario' || a === 'borrar_cuenta') return 'usuario';
  if (a === 'cambiar_comision') return 'comision';
  if (a === 'confirmar_pago' || a === 'confirmar_recarga' || a === 'confirmar_retiro') return 'pago';
  if (a.indexOf('campania') !== -1) return 'publicidad';
  return 'config';
}

const pad = (n) => String(n).padStart(2, '0');
const fmtTs = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
const dayKey = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;

function exportCSV(rows) {
  const head = ['Fecha y hora', 'Usuario', 'Tipo', 'Acción', 'Detalle', 'IP'];
  const lines = [head].concat(rows.map((r) => [fmtTs(r.ts), r.usuario, B_TIPOS[r.tipo].label, r.accion, r.detalle, r.ip]));
  const csv = lines.map((l) => l.map((c) => '"' + String(c).replace(/"/g, '""') + '"').join(',')).join('\r\n');
  const blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a'); a.href = url; a.download = 'bitacora-lola.csv'; document.body.appendChild(a); a.click(); a.remove();
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

function TipoBadge({ tipo, small }) {
  const t = window.WC, I = window.WI; const m = B_TIPOS[tipo]; const Icn = I[m.icon] || I.Book;
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: small ? 11 : 11.5, fontWeight: 700, color: m.color,
      background: m.color + '15', padding: small ? '2px 8px' : '3px 10px', borderRadius: 999, fontFamily: t.mono, whiteSpace: 'nowrap' }}>
      <Icn size={12}/> {m.label}
    </span>
  );
}
function Field({ t, children, style }) {
  return <div style={{ display: 'flex', alignItems: 'center', gap: 8, border: `1px solid ${t.border}`, borderRadius: 10, background: '#fff', padding: '0 12px', height: 42, ...style }}>{children}</div>;
}

function BitacoraView() {
  const t = window.WC, I = window.WI;
  const isMobile = window.useIsMobile();
  const { data, loading, error, reload } = window.useAsync(() => window.LOLA.api.bitacora(), []);
  const [q, setQ] = React.useState('');
  const [tipo, setTipo] = React.useState('todos');
  const [ini, setIni] = React.useState('');
  const [fin, setFin] = React.useState('');
  const [vista, setVista] = React.useState('tabla');
  const [limit, setLimit] = React.useState(50);

  if (loading) return <window.Loading label="Cargando bitácora…"/>;
  if (error) return <window.ErrState error={error} onRetry={reload}/>;

  const eventos = ((data && data.items) || []).map((r) => ({
    id: r.id, ts: new Date(r.createdAt), usuario: r.actorNombre || 'Sistema',
    tipo: clasificar(r.accion), accion: humanAccion(r.accion),
    detalle: [r.entidad, r.detalle].filter(Boolean).join(' · '), ip: r.ip || '—',
  }));

  const filtered = eventos.filter((e) => {
    const qq = q.trim().toLowerCase();
    const di = ini ? new Date(ini + 'T00:00:00') : null;
    const df = fin ? new Date(fin + 'T23:59:59') : null;
    if (tipo !== 'todos' && e.tipo !== tipo) return false;
    if (di && e.ts < di) return false;
    if (df && e.ts > df) return false;
    if (qq && !(e.usuario.toLowerCase().includes(qq) || e.accion.toLowerCase().includes(qq) || e.detalle.toLowerCase().includes(qq) || B_TIPOS[e.tipo].label.toLowerCase().includes(qq))) return false;
    return true;
  });

  const hoyKey = dayKey(new Date());
  const stats = {
    total: eventos.length,
    hoy: eventos.filter((e) => dayKey(e.ts) === hoyKey).length,
    accesos: eventos.filter((e) => B_TIPOS[e.tipo].grupo === 'accesos').length,
    sensibles: eventos.filter((e) => B_TIPOS[e.tipo].grupo === 'seguridad').length,
  };
  const visibles = filtered.slice(0, limit);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      {/* Franja inmutable + stats */}
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr 1fr' : 'auto repeat(3, 1fr)', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, background: '#0C1826', color: '#fff', borderRadius: 14, padding: '14px 18px' }}>
          <span style={{ width: 34, height: 34, borderRadius: 9, background: 'rgba(255,255,255,.1)', color: t.accent, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><BLock size={17}/></span>
          <div><div style={{ fontSize: 12.5, fontWeight: 800 }}>Registro inmutable</div><div style={{ fontSize: 11, color: 'rgba(255,255,255,.6)', fontFamily: t.mono }}>no editable</div></div>
        </div>
        <BStat t={t} label="Eventos totales" value={stats.total}/>
        <BStat t={t} label="Hoy" value={stats.hoy}/>
        <BStat t={t} label="Cambios sensibles" value={stats.sensibles} accent={t.danger}/>
      </div>

      <div style={{ background: '#fff', border: `1px solid ${t.border}`, borderRadius: 16, overflow: 'hidden' }}>
        {/* Toolbar */}
        <div style={{ padding: isMobile ? 14 : '16px 18px', borderBottom: `1px solid ${t.grid}`, display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            <Field t={t} style={{ flex: 1, minWidth: 200 }}>
              <span style={{ color: t.ter, display: 'flex' }}><BSearch size={17}/></span>
              <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Buscar por usuario, acción o detalle…" style={{ flex: 1, minWidth: 0, border: 'none', outline: 'none', background: 'transparent', fontFamily: t.font, fontSize: 13.5, color: t.text }}/>
              {q && <button onClick={() => setQ('')} style={{ background: 'none', border: 'none', cursor: 'pointer', color: t.ter, display: 'flex' }}><I.X size={15}/></button>}
            </Field>
            <select value={tipo} onChange={(e) => setTipo(e.target.value)} style={{ border: `1px solid ${t.border}`, borderRadius: 10, background: '#fff', padding: '0 12px', height: 42, fontFamily: t.font, fontSize: 13.5, color: t.text, cursor: 'pointer' }}>
              <option value="todos">Todos los tipos</option>
              {Object.keys(B_TIPOS).map((k) => <option key={k} value={k}>{B_TIPOS[k].label}</option>)}
            </select>
            <div style={{ display: 'flex', gap: 2, background: t.grid, borderRadius: 10, padding: 3 }}>
              {[['tabla', BList], ['tarjetas', I.Grid]].map(([id, Icn]) => (
                <button key={id} onClick={() => setVista(id)} title={id === 'tabla' ? 'Lista' : 'Tarjetas'} style={{ width: 38, height: 36, borderRadius: 8, border: 'none', cursor: 'pointer',
                  background: vista === id ? '#fff' : 'transparent', color: vista === id ? t.brand : t.sec, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: vista === id ? '0 1px 3px rgba(0,0,0,.12)' : 'none' }}><Icn size={17}/></button>
              ))}
            </div>
          </div>
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'flex-end' }}>
            <label style={{ fontSize: 10.5, color: t.sec, fontFamily: t.mono, textTransform: 'uppercase', letterSpacing: .8, fontWeight: 700 }}>
              <div style={{ marginBottom: 5 }}>Fecha inicio</div>
              <input type="date" value={ini} onChange={(e) => setIni(e.target.value)} style={{ border: `1px solid ${t.border}`, borderRadius: 9, padding: '9px 11px', fontFamily: t.mono, fontSize: 13, color: t.text }}/>
            </label>
            <label style={{ fontSize: 10.5, color: t.sec, fontFamily: t.mono, textTransform: 'uppercase', letterSpacing: .8, fontWeight: 700 }}>
              <div style={{ marginBottom: 5 }}>Fecha fin</div>
              <input type="date" value={fin} onChange={(e) => setFin(e.target.value)} style={{ border: `1px solid ${t.border}`, borderRadius: 9, padding: '9px 11px', fontFamily: t.mono, fontSize: 13, color: t.text }}/>
            </label>
            {(q || tipo !== 'todos' || ini || fin) && (
              <button onClick={() => { setQ(''); setTipo('todos'); setIni(''); setFin(''); }} style={{ background: 'none', border: 'none', cursor: 'pointer', color: t.brand, fontFamily: t.mono, fontSize: 12, fontWeight: 700, height: 38 }}>Limpiar filtros</button>
            )}
            <div style={{ flex: 1 }}/>
            <span style={{ fontSize: 12.5, color: t.ter, fontFamily: t.mono }}>{filtered.length} evento(s)</span>
            <button onClick={() => exportCSV(filtered)} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer', padding: '9px 15px', borderRadius: 10, border: `1px solid ${t.border}`, background: '#fff', color: t.text, fontFamily: t.font, fontSize: 13.5, fontWeight: 700 }}>
              <BDownload size={16}/> Exportar CSV
            </button>
          </div>
        </div>

        {/* Contenido */}
        {filtered.length === 0 ? (
          <window.EmptyState icon="Book" title={eventos.length === 0 ? 'Sin eventos todavía' : 'Sin eventos con estos filtros'}
            sub={eventos.length === 0 ? 'Las acciones administrativas (accesos, aprobaciones, cambios de comisión, campañas…) aparecerán aquí en cuanto ocurran.' : 'No hay registros que coincidan con los filtros.'}/>
        ) : vista === 'tabla' ? (
          <div style={{ maxHeight: 560, overflow: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13.5, minWidth: 720 }}>
              <thead><tr style={{ background: '#FAFBFC', position: 'sticky', top: 0, zIndex: 1 }}>
                {['Fecha y hora', 'Usuario', 'Tipo', 'Acción', 'Detalle'].map((h) => (
                  <th key={h} style={{ textAlign: 'left', padding: '11px 18px', fontFamily: t.mono, fontSize: 10.5, letterSpacing: 1, textTransform: 'uppercase', color: t.ter, fontWeight: 700, borderBottom: `1px solid ${t.border}`, whiteSpace: 'nowrap' }}>{h}</th>
                ))}
              </tr></thead>
              <tbody>
                {visibles.map((e, i) => (
                  <tr key={e.id} style={{ borderBottom: `1px solid ${t.grid}`, background: i % 2 ? '#FCFCFD' : '#fff' }}>
                    <td style={{ padding: '11px 18px', fontFamily: t.mono, fontSize: 12.5, color: t.sec, whiteSpace: 'nowrap' }}>{fmtTs(e.ts)}</td>
                    <td style={{ padding: '11px 18px', fontWeight: 600, color: t.text, whiteSpace: 'nowrap' }}>{e.usuario}</td>
                    <td style={{ padding: '11px 18px' }}><TipoBadge tipo={e.tipo}/></td>
                    <td style={{ padding: '11px 18px', fontWeight: 700, color: t.text }}>{e.accion}</td>
                    <td style={{ padding: '11px 18px', color: t.sec }}>{e.detalle}{e.ip !== '—' ? <span style={{ color: t.ter, fontFamily: t.mono, fontSize: 11.5 }}> · IP {e.ip}</span> : null}</td>
                  </tr>
                ))}
              </tbody>
            </table>
            {visibles.length < filtered.length && (
              <div style={{ padding: '14px', textAlign: 'center', borderTop: `1px solid ${t.grid}` }}>
                <button onClick={() => setLimit((l) => l + 50)} style={{ cursor: 'pointer', padding: '9px 18px', borderRadius: 10, border: `1px solid ${t.border}`, background: '#fff', color: t.brand, fontFamily: t.font, fontSize: 13.5, fontWeight: 700 }}>Mostrar más ({filtered.length - visibles.length})</button>
              </div>
            )}
          </div>
        ) : (
          <div>
            <div style={{ padding: 16, display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(auto-fill, minmax(300px, 1fr))', gap: 12 }}>
              {visibles.map((e) => {
                const m = B_TIPOS[e.tipo]; const Icn = I[m.icon] || I.Book;
                return (
                  <div key={e.id} style={{ border: `1px solid ${t.border}`, borderRadius: 13, padding: '14px 16px' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginBottom: 10 }}>
                      <span style={{ width: 36, height: 36, borderRadius: 10, background: m.color + '16', color: m.color, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icn size={17}/></span>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 14, fontWeight: 700, color: t.text }}>{e.accion}</div>
                        <div style={{ fontSize: 11.5, color: t.ter, fontFamily: t.mono }}>{fmtTs(e.ts)}</div>
                      </div>
                      <TipoBadge tipo={e.tipo} small/>
                    </div>
                    <div style={{ fontSize: 12.5, color: t.sec, marginBottom: 8 }}>{e.detalle}</div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11.5, color: t.ter, fontFamily: t.mono, borderTop: `1px solid ${t.grid}`, paddingTop: 8 }}>
                      <window.WI.User size={13}/> {e.usuario}{e.ip !== '—' ? ' · IP ' + e.ip : ''}
                    </div>
                  </div>
                );
              })}
            </div>
            {visibles.length < filtered.length && (
              <div style={{ padding: '4px 0 18px', textAlign: 'center' }}>
                <button onClick={() => setLimit((l) => l + 50)} style={{ cursor: 'pointer', padding: '9px 18px', borderRadius: 10, border: `1px solid ${t.border}`, background: '#fff', color: t.brand, fontFamily: t.font, fontSize: 13.5, fontWeight: 700 }}>Mostrar más ({filtered.length - visibles.length})</button>
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

function BStat({ t, label, value, accent }) {
  return (
    <div style={{ background: '#fff', border: `1px solid ${t.border}`, borderRadius: 14, padding: '13px 16px' }}>
      <div style={{ fontSize: 10.5, color: t.ter, fontFamily: t.mono, textTransform: 'uppercase', letterSpacing: .8, fontWeight: 700 }}>{label}</div>
      <div style={{ fontSize: 24, fontWeight: 800, color: accent || t.text, fontFamily: t.mono, marginTop: 3 }}>{value}</div>
    </div>
  );
}

window.BitacoraView = BitacoraView;
window.lolaHumanAccion = humanAccion;
window.lolaClasificarAccion = clasificar;
