// LOLA Consola Web — Vistas con DATOS REALES (API): Aprobaciones, Usuarios, Comisiones.
// (Bitácora vive en bitacora.jsx y Configuración en configuracion.jsx — cargan después y
// sobrescriben window.BitacoraView / window.ConfiguracionView a propósito). Exporta window.*View.

const api = () => window.LOLA.api;
const M = () => window.LOLA.map;

// ── Visor de documento + observación puntual ────────────────────────────────
// QA 31-ago-2026 (docx de Mario, punto 1): antes un documento solo abría en pestaña nueva
// (window.open) — sin forma de marcarlo como incorrecto sin rechazar TODA la solicitud.
// Este modal muestra el documento (PDF o imagen) en línea y deja al admin dejar una
// observación puntual que el usuario recibe como notificación real.
const esImagen = (url) => /^data:image\//i.test(url || '') || /\.(png|jpe?g|gif|webp|bmp)(\?|#|$)/i.test(url || '');

function DocumentoModal({ t, I, doc, idx, contratoId, onClose, onSaved }) {
  const [motivo, setMotivo] = React.useState(doc.observacion || '');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');

  const guardar = async (motivoFinal) => {
    setBusy(true); setErr('');
    try {
      const r = await api().observarDocumento(contratoId, idx, motivoFinal);
      onSaved(r.usuario);
      onClose();
    } catch (e) { setErr(e.message || 'No se pudo guardar la observación'); }
    setBusy(false);
  };

  const badge = doc.estado === 'observado'
    ? { txt: 'Observado', bg: t.danger + '14', fg: t.danger }
    : doc.estado === 'aprobado'
    ? { txt: 'Aprobado', bg: t.success + '14', fg: t.success }
    : { txt: 'Sin revisar', bg: t.ter + '14', fg: t.ter };

  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 95, background: 'rgba(10,20,32,.6)', backdropFilter: 'blur(3px)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 22 }}>
      <div onClick={(e) => e.stopPropagation()} style={{ background: '#fff', borderRadius: 18, width: '100%', maxWidth: 640, maxHeight: '90vh', display: 'flex', flexDirection: 'column', boxShadow: '0 40px 100px -30px rgba(0,0,0,.6)', overflow: 'hidden' }}>
        <div style={{ padding: '18px 22px', borderBottom: `1px solid ${t.grid}`, display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 15, fontWeight: 700, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{doc.nombre || ('Documento ' + (idx + 1))}</div>
            <span style={{ display: 'inline-block', marginTop: 5, fontSize: 11, fontWeight: 700, color: badge.fg, background: badge.bg, padding: '2px 9px', borderRadius: 999, fontFamily: t.mono }}>{badge.txt}</span>
          </div>
          <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', color: t.ter, padding: 6 }}><I.X size={18}/></button>
        </div>
        <div style={{ flex: 1, overflow: 'auto', background: '#F6F7F9', display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 300 }}>
          {doc.url ? (esImagen(doc.url)
            ? <img src={doc.url} alt={doc.nombre || 'documento'} style={{ maxWidth: '100%', maxHeight: '60vh', objectFit: 'contain' }}/>
            : <iframe src={doc.url} title={doc.nombre || 'documento'} style={{ width: '100%', height: '60vh', border: 'none' }}/>)
            : <div style={{ padding: 40, color: t.ter, fontSize: 13 }}>Sin archivo adjunto.</div>}
        </div>
        <div style={{ padding: '16px 22px 20px', borderTop: `1px solid ${t.grid}` }}>
          {doc.observacion && doc.estado === 'observado' && (
            <div style={{ fontSize: 12.5, color: t.ter, marginBottom: 10 }}>Observación actual: <b style={{ color: t.text }}>{doc.observacion}</b> {doc.revisadoAt ? `· ${M().fecha(doc.revisadoAt)}` : ''}</div>
          )}
          <textarea value={motivo} onChange={(e) => setMotivo(e.target.value)} placeholder="Ej. La foto del DPI sale borrosa, no se lee el número — pide que la reenvíe."
            style={{ width: '100%', minHeight: 66, resize: 'vertical', boxSizing: 'border-box', border: `1px solid ${t.border}`, borderRadius: 10, padding: '10px 12px', fontFamily: t.font, fontSize: 13.5, color: t.text, marginBottom: 12 }}/>
          {err && <div style={{ fontSize: 12.5, color: t.danger, marginBottom: 10 }}>{err}</div>}
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            <button disabled={busy || !motivo.trim()} onClick={() => guardar(motivo.trim())} style={{ ...wcBtn(t, 'danger-outline'), opacity: busy || !motivo.trim() ? .5 : 1 }}>Marcar como incorrecto</button>
            <button disabled={busy} onClick={() => guardar('')} style={{ ...wcBtn(t, 'success'), opacity: busy ? .5 : 1 }}><I.Check/> Aprobar este documento</button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── APROBACIONES (contratos pendientes reales) ──────────────────────────────
function AprobacionesView() {
  const t = window.WC, I = window.WI;
  const isMobile = window.useIsMobile();
  const { data, loading, error, reload } = window.useAsync(() => api().contratos(), []);
  const [selId, setSelId] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [docAbierto, setDocAbierto] = React.useState(null);

  if (loading) return <window.Loading label="Cargando cola de revisión…"/>;
  if (error) return <window.ErrState error={error} onRetry={reload}/>;

  const items = (data && data.items) || [];
  if (!items.length) return <window.EmptyState icon="Check" title="No hay contratos pendientes"
    sub="Cuando un cliente o proveedor cree su cuenta y envíe sus documentos, aparecerá aquí para aprobación."/>;

  const sel = items.find((x) => x.id === selId) || items[0];
  const tipoTxt = sel.tipoPersona === 'juridica' ? 'Persona jurídica' : 'Persona individual';

  const decidir = async (accion) => {
    if (accion === 'rechazar') {
      // M3: 'Cancelar' en el prompt ABORTA de verdad (antes rechazaba igual con motivo vacío).
      // OJO: no cambiar esto a `window.prompt(...) || ''` — null||'' da string vacío y hace que
      // Cancelar rechace igual, exactamente el bug que este fix corrigió.
      const motivo = window.prompt('Motivo del rechazo (opcional):');
      if (motivo === null) return;
      setBusy(true);
      try { await api().rechazar(sel.id, motivo); setSelId(null); reload(); }
      catch (e) { alert(e.message || 'No se pudo completar la acción'); }
      setBusy(false);
      return;
    }
    setBusy(true);
    try { await api().aprobar(sel.id); setSelId(null); reload(); }
    catch (e) { alert(e.message || 'No se pudo completar la acción'); }
    setBusy(false);
  };

  return (
    <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '380px 1fr', gap: 18, alignItems: 'start' }}>
      <window.Panel title="Cola de revisión" sub={`${items.length} pendiente(s)`} pad={0}>
        <div>
          {items.map((c, i) => (
            <button key={c.id} onClick={() => setSelId(c.id)} style={{
              width: '100%', textAlign: 'left', cursor: 'pointer', border: 'none',
              borderBottom: i < items.length - 1 ? `1px solid ${t.grid}` : 'none',
              borderLeft: `3px solid ${sel.id === c.id ? t.brand : 'transparent'}`,
              background: sel.id === c.id ? '#F4F8FF' : '#fff', padding: '14px 18px',
              display: 'flex', flexDirection: 'column', gap: 5, fontFamily: t.font }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                <span style={{ fontWeight: 700, fontSize: 14, color: t.text }}>{c.empresa || c.nombre}</span>
                <span style={{ width: 7, height: 7, borderRadius: '50%', background: c.estado === 'pendiente' ? t.warn : t.ter }}/>
              </div>
              <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
                <span style={{ fontSize: 11, fontWeight: 700, color: c.rol === 'cliente' ? t.brand : t.success,
                  background: (c.rol === 'cliente' ? t.brand : t.success) + '14', padding: '2px 8px', borderRadius: 5, fontFamily: t.mono }}>{M().rol(c.rol)}</span>
                <span style={{ fontSize: 12, color: t.ter }}>{c.tipoPersona === 'juridica' ? 'Jurídica' : 'Individual'}</span>
              </div>
              <div style={{ fontSize: 11.5, color: t.ter, fontFamily: t.mono }}>{M().fecha(c.createdAt)} · {(c.documentos || []).length} doc(s)</div>
            </button>
          ))}
        </div>
      </window.Panel>

      <window.Panel title={sel.empresa || sel.nombre} sub={`${M().rol(sel.rol)} · ${tipoTxt}`}
        action={<span style={{ fontSize: 11.5, fontWeight: 700, color: t.warn, background: t.warn + '16', padding: '4px 11px', borderRadius: 999, fontFamily: t.mono }}>{M().estado(sel.estado)}</span>}>
        <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr', gap: 14, marginBottom: 18 }}>
          {/* QA 30-ago-2026: antes solo mostraba 7 campos fijos — con empresa/jurídica el nombre
              de la persona de contacto se perdía de la vista (el título ya usa empresa||nombre),
              y NIT/dirección nunca se mostraban aunque el contrato ya los pide y ahora sí se
              guardan (ver phone-flow.js enviarContrato). */}
          {[['Nombre / Razón social', sel.empresa || sel.nombre],
            ...(sel.empresa && sel.nombre && sel.nombre !== sel.empresa ? [['Nombre de contacto', sel.nombre]] : []),
            ['Rol', M().rol(sel.rol)], ['Tipo de entidad', tipoTxt],
            ['Solicitado', M().fecha(sel.createdAt)], ['DPI / CUI', sel.documento || '—'], ['NIT', sel.nit || '—'],
            ['Teléfono', sel.telefono || '—'], ['Correo', sel.email || '—'],
            ['Dirección', (sel.ubicacion && sel.ubicacion.texto) || '—']].map(([k, v]) => (
            <div key={k} style={{ background: '#FAFBFC', border: `1px solid ${t.grid}`, borderRadius: 10, padding: '11px 14px' }}>
              <div style={{ fontSize: 10.5, color: t.ter, fontFamily: t.mono, textTransform: 'uppercase', letterSpacing: .8 }}>{k}</div>
              <div style={{ fontSize: 14, fontWeight: 600, color: t.text, marginTop: 3, wordBreak: 'break-word' }}>{v}</div>
            </div>
          ))}
        </div>
        <div style={{ fontSize: 12, fontWeight: 700, color: t.sec, fontFamily: t.mono, textTransform: 'uppercase', letterSpacing: 1, marginBottom: 10 }}>
          Documentos ({(sel.documentos || []).length})</div>
        {(sel.documentos || []).length ? (
          <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(3,1fr)', gap: 10, marginBottom: 20 }}>
            {sel.documentos.map((doc, i) => {
              const dotColor = doc.estado === 'observado' ? t.danger : doc.estado === 'aprobado' ? t.success : t.ter;
              return (
                <button key={i} onClick={() => setDocAbierto(i)} style={{ textAlign: 'left', cursor: 'pointer', background: '#fff', textDecoration: 'none', border: `1px solid ${t.border}`, borderRadius: 10, padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 10, fontFamily: t.font }}>
                  <span style={{ width: 32, height: 32, borderRadius: 8, background: t.danger + '12', color: t.danger, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><I.Doc/></span>
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 600, color: t.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{doc.nombre || ('Documento ' + (i + 1))}</div>
                  </div>
                  <span title={doc.estado === 'observado' ? 'Observado' : doc.estado === 'aprobado' ? 'Aprobado' : 'Sin revisar'} style={{ width: 8, height: 8, borderRadius: '50%', background: dotColor, flexShrink: 0 }}/>
                </button>
              );
            })}
          </div>
        ) : (
          <div style={{ padding: '14px 16px', borderRadius: 10, background: '#FAFBFC', border: `1px dashed ${t.border}`,
            color: t.ter, fontSize: 13, marginBottom: 20 }}>El usuario todavía no adjuntó documentos.</div>
        )}
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
          <button disabled={busy} onClick={() => decidir('aprobar')} style={{ flex: 1, minWidth: 180, ...wcBtn(t, 'success'), opacity: busy ? .6 : 1 }}><I.Check/> Aprobar y habilitar</button>
          <button disabled={busy} onClick={() => decidir('rechazar')} style={{ flex: 1, minWidth: 140, ...wcBtn(t, 'danger-outline'), opacity: busy ? .6 : 1 }}><I.X/> Rechazar</button>
        </div>
      </window.Panel>
      {docAbierto != null && sel.documentos[docAbierto] && (
        <DocumentoModal t={t} I={I} doc={sel.documentos[docAbierto]} idx={docAbierto} contratoId={sel.id}
          onClose={() => setDocAbierto(null)} onSaved={reload}/>
      )}
    </div>
  );
}

// ── USUARIOS (reales) ───────────────────────────────────────────────────────
function UsuariosView() {
  const t = window.WC;
  const { data, loading, error, reload } = window.useAsync(() => api().usuarios(), []);
  const [filtro, setFiltro] = React.useState('Todos');
  const [busyId, setBusyId] = React.useState(null);

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

  const all = ((data && data.items) || []).filter((u) => u.rol !== 'admin');
  const rows = all.filter((u) => filtro === 'Todos' ? true
    : filtro === 'Suspendido' ? u.estado === 'suspendido' : u.rol === filtro.toLowerCase());
  const estadoColor = (e) => e === 'activo' ? t.success : e === 'pendiente' || e === 'nuevo' ? t.warn : t.danger;

  const toggle = async (u) => {
    setBusyId(u.id);
    try { await api().cambiarEstado(u.id, u.estado === 'suspendido' ? 'activo' : 'suspendido'); reload(); }
    catch (e) { alert(e.message || 'No se pudo cambiar el estado'); }
    setBusyId(null);
  };

  return (
    <window.Panel title="Usuarios" sub={`${all.length} cuenta(s) · clientes y proveedores`} pad={0}
      action={<window.Segmented options={['Todos', 'Cliente', 'Proveedor', 'Suspendido']} value={filtro} onChange={setFiltro}/>}>
      {rows.length ? (
        <div style={{ overflowX: 'auto' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13.5 }}>
            <thead><tr style={{ background: '#FAFBFC' }}>
              {['Usuario', 'Rol', 'Estado', 'Viajes', 'Rating', 'Desde', ''].map((h, i) => (
                <th key={i} style={{ textAlign: i === 3 || i === 4 ? 'center' : 'left', padding: '12px 22px',
                  fontFamily: t.mono, fontSize: 10.5, letterSpacing: 1, textTransform: 'uppercase', color: t.ter,
                  fontWeight: 700, borderBottom: `1px solid ${t.border}` }}>{h}</th>
              ))}
            </tr></thead>
            <tbody>
              {rows.map((u, i) => (
                <tr key={u.id} style={{ borderBottom: i < rows.length - 1 ? `1px solid ${t.grid}` : 'none' }}>
                  <td style={{ padding: '13px 22px' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
                      <span style={{ width: 34, height: 34, borderRadius: 9, background: t.brand + '14', color: t.brand,
                        display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 700, fontSize: 13, fontFamily: t.mono, flexShrink: 0 }}>
                        {M().iniciales(u.empresa || u.nombre)}</span>
                      <div style={{ minWidth: 0 }}>
                        <div style={{ fontWeight: 600, color: t.text }}>{u.empresa || u.nombre}</div>
                        <div style={{ fontSize: 11.5, color: t.ter, fontFamily: t.mono }}>{u.email}</div>
                      </div>
                    </div>
                  </td>
                  <td style={{ padding: '13px 22px' }}>
                    <span style={{ fontSize: 11.5, fontWeight: 700, color: u.rol === 'cliente' ? t.brand : t.success,
                      background: (u.rol === 'cliente' ? t.brand : t.success) + '14', padding: '2px 9px', borderRadius: 5, fontFamily: t.mono }}>{M().rol(u.rol)}</span></td>
                  <td style={{ padding: '13px 22px' }}>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12.5, color: estadoColor(u.estado), fontWeight: 600 }}>
                      <span style={{ width: 7, height: 7, borderRadius: '50%', background: estadoColor(u.estado) }}/>{M().estado(u.estado)}</span></td>
                  <td style={{ padding: '13px 22px', textAlign: 'center', fontFamily: t.mono, fontWeight: 700, color: t.text }}>{u.viajes || 0}</td>
                  <td style={{ padding: '13px 22px', textAlign: 'center', fontFamily: t.mono, color: u.rating ? t.text : t.ter }}>{u.rating ? '★ ' + u.rating : '—'}</td>
                  <td style={{ padding: '13px 22px', color: t.ter, fontFamily: t.mono, fontSize: 12 }}>{M().desde(u.createdAt)}</td>
                  <td style={{ padding: '13px 22px', textAlign: 'right' }}>
                    <button disabled={busyId === u.id} onClick={() => toggle(u)} style={{ ...window.btnGhost(t), color: u.estado === 'suspendido' ? t.success : t.danger, opacity: busyId === u.id ? .5 : 1 }}>
                      {u.estado === 'suspendido' ? 'Activar' : 'Suspender'}</button></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      ) : <window.EmptyState icon="Users" title="Sin usuarios en este filtro" sub="Aún no hay cuentas que coincidan."/>}
    </window.Panel>
  );
}

// ── COMISIONES (real) ────────────────────────────────────────────────────────
function ComisionesView({ dash }) {
  const t = window.WC, I = window.WI;
  const isMobile = window.useIsMobile();
  const { data: com, loading, error, reload } = window.useAsync(() => api().comisiones(), []);

  if (loading || !dash) return <window.Loading label="Cargando comisiones…"/>;
  if (error) return <window.ErrState error={error} onRetry={reload}/>;

  const k = dash.kpis || {};
  const categorias = dash.categorias || [];
  const pct = (com && com.comisionPct) != null ? com.comisionPct : (k.comisionPct || 10);
  const porCat = (com && com.comisionPorCategoria) || {};

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(3,1fr)', gap: 16 }}>
        <window.KpiCard label="Comisión acumulada" value={window.fmtK(k.comisionTotal || 0)} icon={<I.Wallet/>} accent={t.success}/>
        <window.KpiCard label="Tasa base" value={pct + '%'} icon={<I.Percent/>} accent={t.brand}/>
        <window.KpiCard label="Volumen total (GMV)" value={window.fmtK(k.gmv || 0)} icon={<I.Trend/>} accent={t.purple}/>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1.4fr 1fr', gap: 18 }}>
        <window.Panel title="Comisión por categoría" sub="Tasa efectiva por tipo de carga (base si no hay override)">
          {categorias.length ? (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
              {categorias.map((c, i, a) => (
                <div key={c.l} style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '14px 0',
                  borderBottom: i < a.length - 1 ? `1px solid ${t.grid}` : 'none' }}>
                  <span style={{ flex: 1, fontWeight: 600, color: t.text, fontSize: 14 }}>{c.l}</span>
                  <span style={{ fontSize: 12, color: t.ter, fontFamily: t.mono }}>{c.v} servicio(s)</span>
                  <span style={{ fontSize: 13, fontWeight: 700, fontFamily: t.mono, color: t.brand, background: t.brand + '12', padding: '3px 11px', borderRadius: 7 }}>
                    {(porCat[c.l] != null ? porCat[c.l] : pct)}%</span>
                </div>
              ))}
            </div>
          ) : <window.EmptyState icon="Tag" title="Sin servicios por categoría todavía"/>}
        </window.Panel>
        <window.Panel title="Distribución" sub="Servicios por categoría">
          {categorias.length ? (
            <div style={{ display: 'flex', justifyContent: 'center', paddingTop: 6 }}>
              <window.DonutChart data={categorias} size={180} center={{ big: window.fmtN(categorias.reduce((s, x) => s + x.v, 0)), small: 'Servicios' }} fmt={window.fmtN}/>
            </div>
          ) : <window.ChartEmpty h={180}/>}
        </window.Panel>
      </div>
      <window.Panel title="Tasa base de comisión" sub="Se aplica cuando una categoría no define la suya · se guarda en el servidor">
        <ComisionSlider t={t} pct={pct} onSaved={reload}/>
      </window.Panel>
    </div>
  );
}

function ComisionSlider({ t, pct, onSaved }) {
  const [val, setVal] = React.useState(pct);
  const [busy, setBusy] = React.useState(false);
  const [ok, setOk] = React.useState(false);
  React.useEffect(() => { setVal(pct); }, [pct]);
  const dirty = val !== pct;
  const guardar = async () => {
    setBusy(true); setOk(false);
    try { await api().setComisiones({ comisionPct: val }); setOk(true); setTimeout(() => setOk(false), 1800); onSaved && onSaved(); }
    catch (e) { alert(e.message || 'No se pudo guardar'); }
    setBusy(false);
  };
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 18, flexWrap: 'wrap' }}>
      <span style={{ fontFamily: t.mono, fontWeight: 800, fontSize: 34, color: t.brand, minWidth: 92 }}>{val}%</span>
      <div style={{ flex: 1, minWidth: 200 }}>
        <input type="range" min="0" max="20" step="0.5" value={val} onChange={(e) => setVal(+e.target.value)} style={{ width: '100%', accentColor: t.brand }}/>
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10.5, color: t.ter, fontFamily: t.mono, marginTop: 3 }}><span>0%</span><span>20%</span></div>
      </div>
      <button onClick={guardar} disabled={!dirty || busy} style={{ ...wcBtn(t, ok ? 'success' : 'primary'), opacity: !dirty && !ok ? .5 : 1 }}>
        {ok ? <><window.WI.Check/> Guardado</> : busy ? 'Guardando…' : 'Guardar tasa'}</button>
    </div>
  );
}

// ── PAGOS / TESORERÍA (real) ─────────────────────────────────────────────────
// Cierra el flujo de dinero manual: confirma pagos en efectivo/transferencia, acredita
// recargas y confirma/rechaza retiros en revisión. Todo contra /admin/pagos + /admin/recargas
// + /admin/retiros (backend real) — nunca simulado ni local.
const money = (n) => 'Q' + Number(n || 0).toLocaleString('es-GT', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const nombreDe = (x) => (x && typeof x === 'object') ? (x.nombre || '—') : (x || '—');
const TIPO_MOV = { recarga: 'Recarga', cobro_servicio: 'Cobro', pago_proveedor: 'Pago a proveedor', comision: 'Comisión', retiro: 'Retiro', reembolso: 'Reembolso' };
const ESTADO_MOV = { confirmado: 'Confirmado', liquidado: 'Liquidado', pendiente: 'Pendiente', en_revision: 'En revisión', rechazado: 'Rechazado' };

function PagosView() {
  const t = window.WC, I = window.WI;
  const isMobile = window.useIsMobile();
  const { data, loading, error, reload } = window.useAsync(() => api().pagos(), []);
  const [busyId, setBusyId] = React.useState(null);

  if (loading) return <window.Loading label="Cargando pagos y tesorería…"/>;
  if (error) return <window.ErrState error={error} onRetry={reload}/>;

  const pendientes = (data && data.pendientes) || [];
  const recargas = (data && data.recargasPendientes) || [];
  const retiros = (data && data.retirosPendientes) || [];
  const movimientos = (data && data.movimientos) || [];
  const totalRecargas = recargas.reduce((s, m) => s + m.monto, 0);
  const totalRetiros = retiros.reduce((s, m) => s + m.monto, 0);

  const run = async (id, fn) => {
    setBusyId(id);
    try { await fn(); await reload(); } catch (e) { alert(e.message || 'No se pudo completar la acción'); }
    setBusyId(null);
  };
  const txRows = movimientos.map((m) => ({
    id: 'MV-' + String(m.id).slice(-5).toUpperCase(), tipo: TIPO_MOV[m.tipo] || m.tipo,
    desc: m.descripcion || '', usuario: nombreDe(m.usuario) !== '—' ? nombreDe(m.usuario) : (m.usuarioNombre || 'LOLA'),
    monto: m.monto, signo: m.signo, estado: ESTADO_MOV[m.estado] || m.estado,
    fecha: new Date(m.createdAt).toLocaleString('es-GT', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit' }),
  }));

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr 1fr' : 'repeat(3,1fr)', gap: 16 }}>
        <window.KpiCard label="Pagos pendientes" value={String(pendientes.length)} icon={<I.Tag/>} accent={t.brand}/>
        <window.KpiCard label="Recargas en revisión" value={money(totalRecargas)} icon={<I.Wallet/>} accent={t.warn}/>
        <window.KpiCard label="Retiros en revisión" value={money(totalRetiros)} icon={<I.Trend/>} accent={t.purple}/>
      </div>

      <window.Panel title="Pagos pendientes" sub="Efectivo y transferencia esperan tu confirmación · tarjeta se liquida sola por su pasarela" pad={0}>
        {pendientes.length ? (
          <div style={{ overflowX: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13.5, minWidth: 640 }}>
              <thead><tr style={{ background: '#FAFBFC' }}>
                {['Cliente', 'Proveedor', 'Método', 'Monto', 'Estado', ''].map((h) => (
                  <th key={h} style={{ textAlign: 'left', padding: '12px 20px', fontFamily: t.mono, fontSize: 10.5, letterSpacing: 1, textTransform: 'uppercase', color: t.ter, fontWeight: 700, borderBottom: `1px solid ${t.border}` }}>{h}</th>
                ))}
              </tr></thead>
              <tbody>
                {pendientes.map((p, i) => {
                  const offline = ['efectivo', 'transferencia'].includes(p.metodo) && p.provider !== 'stripe';
                  return (
                    <tr key={p.id} style={{ borderBottom: i < pendientes.length - 1 ? `1px solid ${t.grid}` : 'none' }}>
                      <td style={{ padding: '12px 20px', fontWeight: 600, color: t.text }}>{nombreDe(p.cliente)}</td>
                      <td style={{ padding: '12px 20px', color: t.sec }}>{nombreDe(p.proveedor)}</td>
                      <td style={{ padding: '12px 20px', textTransform: 'capitalize' }}>{p.metodo}</td>
                      <td style={{ padding: '12px 20px', fontFamily: t.mono, fontWeight: 700 }}>{money(p.monto)}</td>
                      <td style={{ padding: '12px 20px' }}>
                        {offline
                          ? <span style={{ fontSize: 11, fontWeight: 700, color: t.warn, background: t.warn + '16', padding: '3px 9px', borderRadius: 999, fontFamily: t.mono }}>Por confirmar</span>
                          : <span style={{ fontSize: 11, fontWeight: 700, color: t.brand, background: t.brand + '14', padding: '3px 9px', borderRadius: 999, fontFamily: t.mono }}>Vía pasarela</span>}
                      </td>
                      <td style={{ padding: '12px 20px', textAlign: 'right' }}>
                        {offline
                          ? <button disabled={busyId === p.id} onClick={() => run(p.id, () => api().confirmarPago(p.id))} style={{ ...wcBtn(t, 'success'), padding: '7px 14px', fontSize: 12.5, opacity: busyId === p.id ? .6 : 1 }}>{busyId === p.id ? 'Confirmando…' : 'Confirmar'}</button>
                          : <span style={{ fontSize: 11.5, color: t.ter }}>Automático</span>}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        ) : <window.EmptyState icon="Tag" title="Sin pagos pendientes" sub="Los pagos en efectivo o transferencia que esperan confirmación aparecerán aquí."/>}
      </window.Panel>

      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr', gap: 18 }}>
        <window.Panel title="Recargas en revisión" sub="Depósitos/transferencias de billetera sin acreditar" pad={0}>
          {recargas.length ? recargas.map((m, i) => (
            <div key={m.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 18px', borderBottom: i < recargas.length - 1 ? `1px solid ${t.grid}` : 'none' }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 700, color: t.text, fontSize: 13.5 }}>{nombreDe(m.usuario)}</div>
                <div style={{ fontSize: 11.5, color: t.ter, fontFamily: t.mono }}>{M().fecha(m.createdAt)}</div>
              </div>
              <span style={{ fontFamily: t.mono, fontWeight: 800, color: t.text }}>{money(m.monto)}</span>
              <button disabled={busyId === m.id} onClick={() => run(m.id, () => api().confirmarRecarga(m.id))} style={{ ...wcBtn(t, 'success'), padding: '7px 14px', fontSize: 12.5, opacity: busyId === m.id ? .6 : 1 }}>{busyId === m.id ? '…' : 'Acreditar'}</button>
            </div>
          )) : <window.EmptyState icon="Wallet" title="Sin recargas pendientes"/>}
        </window.Panel>

        <window.Panel title="Retiros en revisión" sub="Solicitudes con el saldo ya reservado" pad={0}>
          {retiros.length ? retiros.map((m, i) => (
            <div key={m.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '13px 18px', borderBottom: i < retiros.length - 1 ? `1px solid ${t.grid}` : 'none', flexWrap: 'wrap' }}>
              <div style={{ flex: 1, minWidth: 120 }}>
                <div style={{ fontWeight: 700, color: t.text, fontSize: 13.5 }}>{nombreDe(m.usuario)}</div>
                <div style={{ fontSize: 11.5, color: t.ter, fontFamily: t.mono }}>{M().fecha(m.createdAt)}{m.descripcion ? ' · ' + m.descripcion : ''}</div>
              </div>
              <span style={{ fontFamily: t.mono, fontWeight: 800, color: t.text }}>{money(m.monto)}</span>
              <div style={{ display: 'flex', gap: 6 }}>
                <button disabled={busyId === m.id} onClick={() => run(m.id, () => api().confirmarRetiro(m.id))} style={{ ...wcBtn(t, 'success'), padding: '7px 12px', fontSize: 12.5, opacity: busyId === m.id ? .6 : 1 }}>Confirmar</button>
                <button disabled={busyId === m.id} onClick={() => { const motivo = window.prompt('Motivo del rechazo (se reembolsa el saldo):'); if (motivo === null) return; run(m.id, () => api().rechazarRetiro(m.id, motivo)); }} style={{ ...wcBtn(t, 'danger-outline'), padding: '7px 12px', fontSize: 12.5, opacity: busyId === m.id ? .6 : 1 }}>Rechazar</button>
              </div>
            </div>
          )) : <window.EmptyState icon="Trend" title="Sin retiros pendientes"/>}
        </window.Panel>
      </div>

      <window.Panel title="Movimientos recientes" sub="Libro mayor de la plataforma · últimos 100" pad={0}>
        {txRows.length ? <div style={{ maxHeight: 440, overflowY: 'auto' }}><window.TxTable rows={txRows}/></div>
          : <window.EmptyState icon="Book" title="Sin movimientos todavía" sub="Los cobros, comisiones, recargas y retiros aparecerán aquí cuando haya operación."/>}
      </window.Panel>
    </div>
  );
}

// La sección "Auditoría" real vive en web/bitacora.jsx y "Configuración" en
// web/configuracion.jsx (ambos cargan después de este archivo y sobrescriben
// window.BitacoraView / window.ConfiguracionView a propósito — no dupliques esas vistas aquí).

function wcBtn(t, kind) {
  const base = { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8, cursor: 'pointer',
    padding: '11px 18px', borderRadius: 10, fontFamily: t.font, fontSize: 14, fontWeight: 700, border: '1px solid transparent' };
  if (kind === 'primary') return { ...base, background: t.brand, color: '#fff' };
  if (kind === 'success') return { ...base, background: t.success, color: '#fff' };
  if (kind === 'danger-outline') return { ...base, background: '#fff', color: t.danger, borderColor: t.danger + '55' };
  return { ...base, background: '#fff', color: t.sec, borderColor: t.border };
}

Object.assign(window, { AprobacionesView, UsuariosView, ComisionesView, PagosView, wcBtn });
