// Modales / overlays

function ModalNuevaSolicitud() {
  const close = () => window._desasfCloseModal && window._desasfCloseModal();
  const u     = DesasfAPI.getCurrentUser() || {};
  const esCliente = u.rol === 'cliente';

  const [step,         setStep]         = React.useState(1);
  const [empresas,     setEmpresas]     = React.useState([]);
  const [productos,    setProductos]    = React.useState([]);
  const [loading,      setLoading]      = React.useState(true);
  const [saving,       setSaving]       = React.useState(false);
  const [error,        setError]        = React.useState('');
  const [empresaId,    setEmpresaId]    = React.useState('');
  const [empresaSearch, setEmpresaSearch] = React.useState('');
  const [productoId,   setProductoId]   = React.useState('');
  const [volumen,      setVolumen]      = React.useState('');
  const [unidad,       setUnidad]       = React.useState('m³');
  const [ocNumero,     setOcNumero]     = React.useState('');
  const [proyecto,     setProyecto]     = React.useState('');
  const [diasVenc,     setDiasVenc]     = React.useState('');
  const [creditoProy,  setCreditoProy]  = React.useState('');
  const [direccionObra,setDireccionObra]= React.useState('');
  const [ocArchivo,    setOcArchivo]    = React.useState(null);
  const [eta,          setEta]          = React.useState('');
  const [notas,        setNotas]        = React.useState('');
  const [notaCliente,  setNotaCliente]  = React.useState('');
  const fileInputRef                    = React.useRef(null);

  React.useEffect(() => {
    Promise.all([
      esCliente
        ? DesasfAPI.get('/auth/me/empresas').catch(() => ({ rows: [] }))
        : DesasfAPI.get('/clientes?limit=200').catch(() => ({ rows: [] })),
      DesasfAPI.get('/catalogo?activo=1&limit=100').catch(() => ({ rows: [] })),
    ]).then(([emp, prod]) => {
      const lista = emp.rows || [];
      setEmpresas(lista);
      setProductos(prod.rows || []);
      if (esCliente && lista.length === 1) setEmpresaId(lista[0].id);
    }).finally(() => setLoading(false));
  }, []);

  const empresaSel  = empresas.find(e => e.id === Number(empresaId));
  const productoSel = productos.find(p => p.id === Number(productoId));
  const empresasFiltradas = !empresaSearch.trim()
    ? empresas.slice(0, 12)
    : empresas.filter(e =>
        e.razon_social.toLowerCase().includes(empresaSearch.toLowerCase()) ||
        (e.ruc || '').includes(empresaSearch)
      ).slice(0, 12);

  const precioUnit = productoSel ? Number(productoSel.precio_base) : 0;
  const volNum     = parseFloat(volumen) || 0;
  const subtotal   = precioUnit * volNum;
  const igvPct     = Number(window._appConfig?.igv_porcentaje ?? 18);
  const igv        = subtotal * (igvPct / 100);
  const total      = subtotal + igv;

  React.useEffect(() => { if (productoSel?.unidad) setUnidad(productoSel.unidad); }, [productoId]);

  function canNext() {
    if (step === 1) return !!empresaId;
    if (step === 2) return !!productoId && volNum >= 0.1;
    if (step === 3) return true;
    return false;
  }

  async function submit() {
    if (!empresaId || !productoId || !volumen) {
      setError('Completa cliente, producto y volumen.');
      return;
    }
    setError(''); setSaving(true);
    try {
      const payload = {
        empresa_id:     Number(empresaId),
        producto_id:    Number(productoId),
        volumen:        volNum,
        oc_numero:      ocNumero.trim()  || null,
        notas_tecnicas: notas.trim()     || null,
        notas_cliente:  notaCliente.trim()|| null,
        eta:            eta              || null,
      };
      if (!esCliente) {
        payload.proyecto         = proyecto.trim() || null;
        payload.dias_vencimiento = diasVenc !== '' ? Number(diasVenc) : null;
        payload.credito_proyecto = creditoProy !== '' ? Number(creditoProy) : null;
        payload.direccion_obra   = direccionObra.trim() || null;
      }
      const res = await DesasfAPI.post('/solicitudes', payload);

      if (ocArchivo) {
        try {
          const fd = new FormData();
          fd.append('file', ocArchivo);
          fd.append('tipo', 'orden_compra');
          await DesasfAPI.upload(`/solicitudes/${res.id}/documentos`, fd);
        } catch (e) {
          console.error('Error subiendo OC:', e);
          alert('La solicitud se creó pero no se pudo adjuntar el archivo de OC: ' + e.message);
        }
      }

      close();
      if (window._desasfNavigate) {
        window._desasfCurrentSolicitud = res.id;
        window._desasfNavigate('solicitud-detalle');
      }
    } catch (err) {
      setError(err.message || 'No se pudo crear la solicitud.');
    } finally {
      setSaving(false);
    }
  }

  function onOcFile(e) {
    const f = e.target.files?.[0];
    if (!f) { setOcArchivo(null); return; }
    if (f.size > 50 * 1024 * 1024) {
      setError('El archivo supera 50 MB.');
      e.target.value = '';
      return;
    }
    setError('');
    setOcArchivo(f);
  }

  function clearOcFile() {
    setOcArchivo(null);
    if (fileInputRef.current) fileInputRef.current.value = '';
  }

  function fmtBytes(n) {
    if (!n) return '0 B';
    if (n < 1024)        return `${n} B`;
    if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
    return `${(n / 1024 / 1024).toFixed(2)} MB`;
  }

  function fmt(n) { return Number(n || 0).toLocaleString('es-PE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }

  return (
    <div style={{ width: 920, maxHeight: '90vh', background: '#fff', borderRadius: 12, boxShadow: '0 30px 80px rgba(0,0,0,0.4)', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
      <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div>
          <div style={{ fontSize: 11, color: 'var(--ink-5)', textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 600 }}>Nueva solicitud · Paso {step} de 3</div>
          <div style={{ fontFamily: 'var(--cond)', fontSize: 20, fontWeight: 700, marginTop: 2 }}>
            {step === 1 && 'Cliente'}
            {step === 2 && 'Producto y volumen'}
            {step === 3 && 'Logística y confirmación'}
          </div>
        </div>
        <div className="icon-btn" style={{ fontSize: 18 }} onClick={close}>×</div>
      </div>

      <div style={{ padding: '14px 22px', borderBottom: '1px solid var(--line)', background: 'var(--ink-9)' }}>
        <div className="steps">
          {[
            { l: '1. Cliente',  state: step > 1 ? 'done' : step === 1 ? 'active' : '' },
            { l: '2. Producto', state: step > 2 ? 'done' : step === 2 ? 'active' : '' },
            { l: '3. Confirmar', state: step === 3 ? 'active' : '' },
          ].map((s, i) => (
            <div key={i} className={`step ${s.state}`}>
              <div className="bar"/>
              <div className="lbl">{s.l}</div>
            </div>
          ))}
        </div>
      </div>

      <div style={{ padding: 22, overflow: 'auto', flex: 1 }}>
        {loading && <div style={{ padding: 24, textAlign: 'center', color: 'var(--ink-5)' }}>Cargando…</div>}

        {!loading && step === 1 && (
          <div>
            {esCliente ? (
              empresas.length === 0 ? (
                <div style={{ padding: 14, background: 'var(--status-danger-bg)', color: 'var(--status-danger)', borderRadius: 8 }}>
                  No tienes empresas asociadas. Contacta al administrador para que te asigne al menos una empresa.
                </div>
              ) : empresas.length === 1 ? (
                <div style={{ padding: 14, background: 'var(--ink-9)', borderRadius: 8 }}>
                  <div style={{ fontSize: 11, color: 'var(--ink-5)', marginBottom: 4 }}>Cliente</div>
                  <div style={{ fontWeight: 600 }}>{empresas[0].razon_social}</div>
                  {empresas[0].ruc && <div style={{ fontSize: 11, color: 'var(--ink-5)', fontFamily: 'var(--mono)', marginTop: 2 }}>RUC {empresas[0].ruc}</div>}
                </div>
              ) : (
                <>
                  <label className="label">Selecciona la empresa para esta solicitud</label>
                  <div style={{ marginTop: 4, maxHeight: 360, overflowY: 'auto', border: '1px solid var(--line)', borderRadius: 6 }}>
                    {empresas.map(e => (
                      <div key={e.id} onClick={() => setEmpresaId(e.id)}
                        style={{ padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', borderBottom: '1px solid var(--line)', background: Number(empresaId) === e.id ? 'var(--ink-9)' : '#fff' }}>
                        <div style={{ width: 32, height: 32, borderRadius: 6, background: 'var(--ink-2)', color: '#fff', display: 'grid', placeItems: 'center', fontSize: 11, fontWeight: 700 }}>
                          {(e.razon_social || '?').slice(0, 2).toUpperCase()}
                        </div>
                        <div style={{ flex: 1 }}>
                          <div style={{ fontSize: 13, fontWeight: 600 }}>{e.razon_social}</div>
                          {e.ruc && <div style={{ fontSize: 11, color: 'var(--ink-5)', fontFamily: 'var(--mono)' }}>RUC {e.ruc}</div>}
                        </div>
                        {Number(empresaId) === e.id && <div style={{ color: 'var(--status-ok)' }}>{Icon.check}</div>}
                      </div>
                    ))}
                  </div>
                </>
              )
            ) : (
              <>
                <label className="label">Buscar cliente por nombre o RUC</label>
                <input className="input" placeholder="Razón social o RUC…"
                  value={empresaSearch} onChange={e => setEmpresaSearch(e.target.value)}/>
                <div style={{ marginTop: 12, maxHeight: 360, overflowY: 'auto', border: '1px solid var(--line)', borderRadius: 6 }}>
                  {empresasFiltradas.length === 0 && (
                    <div style={{ padding: 16, color: 'var(--ink-5)', fontSize: 12, textAlign: 'center' }}>Sin coincidencias.</div>
                  )}
                  {empresasFiltradas.map(e => (
                    <div key={e.id} onClick={() => setEmpresaId(e.id)}
                      style={{ padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', borderBottom: '1px solid var(--line)', background: Number(empresaId) === e.id ? 'var(--ink-9)' : '#fff' }}>
                      <div style={{ width: 32, height: 32, borderRadius: 6, background: 'var(--ink-2)', color: '#fff', display: 'grid', placeItems: 'center', fontSize: 11, fontWeight: 700 }}>
                        {(e.razon_social || '?').slice(0, 2).toUpperCase()}
                      </div>
                      <div style={{ flex: 1 }}>
                        <div style={{ fontSize: 13, fontWeight: 600 }}>{e.razon_social}</div>
                        <div style={{ fontSize: 11, color: 'var(--ink-5)', fontFamily: 'var(--mono)' }}>RUC {e.ruc}{e.sector ? ` · ${e.sector}` : ''}</div>
                      </div>
                      {Number(empresaId) === e.id && <div style={{ color: 'var(--status-ok)' }}>{Icon.check}</div>}
                    </div>
                  ))}
                </div>
              </>
            )}
          </div>
        )}

        {!loading && step === 2 && (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 18 }}>
            <div>
              <label className="label">Producto del catálogo</label>
              <select className="input" value={productoId} onChange={e => setProductoId(e.target.value)}>
                <option value="">— Selecciona un producto —</option>
                {productos.map(p => (
                  <option key={p.id} value={p.id}>{p.codigo} · {p.nombre}</option>
                ))}
              </select>
              {productoSel && (
                <div style={{ marginTop: 10, padding: 12, background: 'var(--ink-9)', borderRadius: 6 }}>
                  <div style={{ fontSize: 11, color: 'var(--ink-5)', marginBottom: 2 }}>{productoSel.codigo} · {productoSel.especificacion || productoSel.categoria}</div>
                  <div style={{ fontSize: 13, fontWeight: 600 }}>{productoSel.nombre}</div>
                  <div style={{ fontSize: 11, color: 'var(--ink-5)', marginTop: 4 }}>
                    Precio: <b>S/ {Number(productoSel.precio_base).toLocaleString('es-PE')}/{productoSel.unidad}</b>
                  </div>
                </div>
              )}

              <label className="label" style={{ marginTop: 16 }}>Volumen requerido</label>
              <div className="row" style={{ gap: 8 }}>
                <input className="input k" type="number" step="0.1" min="0.1" placeholder="Ej: 12"
                  value={volumen} onChange={e => setVolumen(e.target.value)} style={{ flex: 1 }}/>
                <span className="chip" style={{ height: 38, borderRadius: 6 }}>{unidad}</span>
              </div>
              {productoSel && volNum > 0 && (
                <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>
                  ≈ {(volNum * 1090).toLocaleString('es-PE')} kg estimados
                </div>
              )}
            </div>

            <div>
              <label className="label">Notas técnicas (opcional)</label>
              <textarea className="input" rows="4" style={{ height: 'auto', padding: 10, resize: 'vertical' }}
                placeholder="Especificaciones de obra, condiciones, certificaciones…"
                value={notas} onChange={e => setNotas(e.target.value)}/>

              {productoSel && volNum > 0 && (
                <div style={{ marginTop: 16, padding: 14, background: 'var(--ink-9)', borderRadius: 8 }}>
                  <div style={{ fontSize: 11, color: 'var(--ink-5)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600, marginBottom: 8 }}>Estimado preliminar</div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, marginBottom: 4 }}>
                    <span>Subtotal</span><span className="num">S/ {fmt(subtotal)}</span>
                  </div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, marginBottom: 4 }}>
                    <span>IGV ({igvPct}%)</span><span className="num">S/ {fmt(igv)}</span>
                  </div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 15, fontWeight: 700, borderTop: '1px solid var(--line)', paddingTop: 6, marginTop: 6 }}>
                    <span>Total</span><span className="num">S/ {fmt(total)}</span>
                  </div>
                </div>
              )}
            </div>
          </div>
        )}

        {!loading && step === 3 && (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 18 }}>
            <div>
              {!esCliente && (
                <>
                  <label className="label">Nombre del proyecto (opcional)</label>
                  <input className="input" placeholder="Ej: Carretera Panamericana km 47"
                    maxLength={120}
                    value={proyecto} onChange={e => setProyecto(e.target.value)}
                    style={{ marginBottom: 12 }}/>

                  <label className="label">Dirección de la obra (opcional)</label>
                  <input className="input" placeholder="Lugar exacto de entrega del asfalto"
                    maxLength={255}
                    value={direccionObra} onChange={e => setDireccionObra(e.target.value)}
                    style={{ marginBottom: 12 }}/>

                  <div className="row" style={{ gap: 10, marginBottom: 16 }}>
                    <div style={{ flex: 1 }}>
                      <label className="label">Días de vencimiento (opcional)</label>
                      <input className="input num" type="number" min="0" placeholder="Ej: 30"
                        value={diasVenc} onChange={e => setDiasVenc(e.target.value)}/>
                    </div>
                    <div style={{ flex: 1 }}>
                      <label className="label">Crédito del proyecto (S/) (opcional)</label>
                      <input className="input num" type="number" step="0.01" min="0" placeholder="Ej: 25000"
                        value={creditoProy} onChange={e => setCreditoProy(e.target.value)}/>
                    </div>
                  </div>
                </>
              )}

              <label className="label">N° orden de compra (opcional)</label>
              <input className="input k" placeholder="Ej: OC-2026-0142"
                value={ocNumero} onChange={e => setOcNumero(e.target.value)}/>

              <label className="label" style={{ marginTop: 16 }}>Documento de orden de compra (opcional)</label>
              <input ref={fileInputRef} type="file" onChange={onOcFile}
                accept=".pdf,.jpg,.jpeg,.png,.webp,.gif,.xls,.xlsx,.doc,.docx,.csv,.txt,.zip"
                style={{ display: 'none' }}/>
              {!ocArchivo ? (
                <div onClick={() => fileInputRef.current?.click()}
                  style={{ border: '1px dashed var(--line-strong)', borderRadius: 6, padding: 14,
                    display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer',
                    background: 'var(--ink-9)', color: 'var(--ink-3)' }}>
                  <div style={{ width: 32, height: 32, borderRadius: 6, background: '#fff', border: '1px solid var(--line)',
                    display: 'grid', placeItems: 'center', color: 'var(--ink-3)' }}>{Icon.upload || Icon.plus}</div>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink-1)' }}>Subir archivo</div>
                    <div style={{ fontSize: 11, color: 'var(--ink-5)' }}>PDF, imagen, Excel, Word… (máx 50 MB)</div>
                  </div>
                </div>
              ) : (
                <div style={{ border: '1px solid var(--line)', borderRadius: 6, padding: 10,
                    display: 'flex', alignItems: 'center', gap: 10, background: 'var(--ink-9)' }}>
                  <div style={{ width: 32, height: 32, borderRadius: 5, background: '#fff', border: '1px solid var(--line)',
                    display: 'grid', placeItems: 'center', color: 'var(--ink-3)' }}>{Icon.doc}</div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 12, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{ocArchivo.name}</div>
                    <div style={{ fontSize: 11, color: 'var(--ink-5)' }}>{fmtBytes(ocArchivo.size)}</div>
                  </div>
                  <div className="icon-btn" title="Quitar" onClick={clearOcFile}
                    style={{ fontSize: 16, color: 'var(--status-danger)' }}>×</div>
                </div>
              )}

              <label className="label" style={{ marginTop: 16 }}>Vencimiento de crédito (opcional)</label>
              <input className="input" type="date" value={eta} onChange={e => setEta(e.target.value)}/>

              <label className="label" style={{ marginTop: 16 }}>Nota (opcional)</label>
              <textarea className="input" rows="3" maxLength={1000} style={{ height: 'auto', padding: 10, resize: 'vertical' }}
                placeholder="Comentarios para esta solicitud (instrucciones de coordinación, contactos, observaciones del cliente…)"
                value={notaCliente} onChange={e => setNotaCliente(e.target.value)}/>

              <div style={{ marginTop: 18, padding: 14, background: 'var(--status-pending-bg)', borderRadius: 8, color: 'var(--status-pending)' }}>
                <div style={{ fontSize: 12, fontWeight: 700, marginBottom: 4 }}>! Importante</div>
                <div style={{ fontSize: 11, lineHeight: 1.5 }}>
                  La solicitud entra a "Recepción". Operaciones validará el diseño de mezcla y agendará producción y despacho.
                </div>
              </div>
            </div>

            <div style={{ padding: 14, background: 'var(--ink-9)', borderRadius: 8 }}>
              <div style={{ fontSize: 11, color: 'var(--ink-5)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 600, marginBottom: 10 }}>Resumen</div>
              <dl className="dl">
                <dt>Cliente</dt>
                <dd>{empresaSel?.razon_social || 'Tu empresa'}</dd>
                {empresaSel?.ruc && <><dt>RUC</dt><dd className="k">{empresaSel.ruc}</dd></>}
                <dt>Producto</dt>
                <dd>{productoSel?.nombre}</dd>
                <dt>Volumen</dt>
                <dd className="num">{volNum} {unidad}</dd>
                <dt>Subtotal</dt>
                <dd className="num">S/ {fmt(subtotal)}</dd>
                <dt>IGV ({igvPct}%)</dt>
                <dd className="num">S/ {fmt(igv)}</dd>
                {!esCliente && proyecto.trim() && <><dt>Proyecto</dt><dd>{proyecto.trim()}</dd></>}
                {!esCliente && direccionObra.trim() && <><dt>Dirección obra</dt><dd>{direccionObra.trim()}</dd></>}
                {!esCliente && diasVenc && <><dt>Vencimiento</dt><dd>{diasVenc} días</dd></>}
                {!esCliente && creditoProy && <><dt>Crédito proy.</dt><dd className="num">S/ {Number(creditoProy).toLocaleString('es-PE')}</dd></>}
                {ocNumero.trim() && <><dt>N° OC</dt><dd className="k">{ocNumero.trim()}</dd></>}
                {ocArchivo && <><dt>Archivo OC</dt><dd>{ocArchivo.name} <span className="muted">({fmtBytes(ocArchivo.size)})</span></dd></>}
                {notaCliente.trim() && <><dt>Nota</dt><dd style={{ whiteSpace: 'pre-wrap' }}>{notaCliente.trim()}</dd></>}
              </dl>
              <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 16, fontWeight: 700, borderTop: '1px solid var(--line)', paddingTop: 8, marginTop: 8 }}>
                <span>Total estimado</span><span className="num">S/ {fmt(total)}</span>
              </div>
            </div>
          </div>
        )}

        {error && (
          <div style={{ marginTop: 14, padding: 10, background: 'var(--status-danger-bg, #fef0f0)', color: 'var(--status-danger)', borderRadius: 6, fontSize: 12 }}>
            {error}
          </div>
        )}
      </div>

      <div style={{ padding: 16, borderTop: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        {step > 1 ? (
          <button className="btn btn--ghost" onClick={() => setStep(step - 1)} disabled={saving}>‹ Atrás</button>
        ) : <span/>}
        <div className="row">
          <button className="btn btn--ghost" onClick={close} disabled={saving}>Cancelar</button>
          {step < 3 ? (
            <button className="btn btn--primary" onClick={() => setStep(step + 1)} disabled={!canNext()}>
              Siguiente →
            </button>
          ) : (
            <button className="btn btn--accent" onClick={submit} disabled={saving || !canNext()}>
              {Icon.check}<span>{saving ? 'Creando…' : 'Crear solicitud'}</span>
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

function ModalValidarVoucher() {
  const close = () => window._desasfCloseModal && window._desasfCloseModal();
  const u     = DesasfAPI.getCurrentUser() || {};
  const puedeValidar = DesasfAPI.hasPerm('pagos.validar', { strict: true });
  const [pago,    setPago]    = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [obs,     setObs]     = React.useState('');
  const [saving,  setSaving]  = React.useState(false);
  const [checks,  setChecks]  = React.useState([true, true, false, false]);

  React.useEffect(() => {
    const id = window._desasfCurrentPago;
    if (!id) { setLoading(false); return; }
    DesasfAPI.get('/pagos/' + id)
      .then(p => { setPago(p); setObs(p.observaciones || ''); })
      .catch(console.error)
      .finally(() => setLoading(false));
  }, []);

  async function handleValidar() {
    if (!pago) return;
    setSaving(true);
    try {
      await DesasfAPI.put('/pagos/' + pago.id + '/validar', { observaciones: obs });
      if (window._desasfRefreshPagos) window._desasfRefreshPagos();
      close();
    } catch (err) {
      alert('Error: ' + err.message);
    } finally { setSaving(false); }
  }

  async function handleRechazar() {
    if (!pago) return;
    if (!obs.trim()) { alert('Ingresa una observación para poder rechazar'); return; }
    setSaving(true);
    try {
      await DesasfAPI.put('/pagos/' + pago.id + '/rechazar', { observaciones: obs });
      if (window._desasfRefreshPagos) window._desasfRefreshPagos();
      close();
    } catch (err) {
      alert('Error: ' + err.message);
    } finally { setSaving(false); }
  }

  if (loading) return (
    <div style={{ width: 880, background: '#fff', borderRadius: 12, padding: 60, textAlign: 'center', color: 'var(--ink-5)' }}>
      Cargando voucher…
    </div>
  );

  if (!pago) return (
    <div style={{ width: 480, background: '#fff', borderRadius: 12, padding: 32, textAlign: 'center' }}>
      <div style={{ color: 'var(--ink-5)', marginBottom: 14 }}>No se especificó un voucher.</div>
      <button className="btn btn--ghost" onClick={close}>Cerrar</button>
    </div>
  );

  const monto         = Number(pago.monto || 0);
  const montoFactura  = Number(pago.monto_factura || pago.monto_factura_sol || 0);
  const matchMonto    = montoFactura > 0 && Math.abs(monto - montoFactura) < 0.01;
  const yaProcesado   = pago.estado !== 'por_validar';

  function fmtMoney(n) { return 'S/ ' + n.toLocaleString('es-PE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
  function toggleCheck(i) { setChecks(c => c.map((v, idx) => idx === i ? !v : v)); }

  return (
    <div style={{ width: 880, background: '#fff', borderRadius: 12, boxShadow: '0 30px 80px rgba(0,0,0,0.4)', overflow: 'hidden' }}>
      <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div>
          <div style={{ fontSize: 11, color: 'var(--ink-5)', textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 600 }}>
            Pago · {pago.voucher_ref}
          </div>
          <div style={{ fontFamily: 'var(--cond)', fontSize: 20, fontWeight: 700, marginTop: 2 }}>
            {yaProcesado
              ? `Voucher ${pago.estado === 'confirmado' ? 'confirmado' : 'rechazado'}`
              : (puedeValidar ? 'Validar voucher de pago' : 'Voucher en revisión')}
          </div>
        </div>
        <div className="icon-btn" style={{ fontSize: 18 }} onClick={close}>×</div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 0 }}>
        {/* Comprobante */}
        <div style={{ padding: 22, background: 'var(--ink-9)' }}>
          <div style={{ background: '#fff', border: '1px solid var(--line)', borderRadius: 6, padding: 18, fontFamily: 'var(--mono)', fontSize: 12, lineHeight: 1.7 }}>
            <div style={{ borderBottom: '1px dashed var(--line-strong)', paddingBottom: 8, marginBottom: 8 }}>
              <div style={{ fontFamily: 'var(--sans)', fontWeight: 700, fontSize: 14 }}>{pago.banco || 'Banco no especificado'}</div>
              <div style={{ color: 'var(--ink-5)', fontSize: 11 }}>Constancia de operación</div>
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>N° operación</span><span style={{ fontWeight: 600, color: 'var(--ink-1)' }}>{pago.operacion_num || '—'}</span></div>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>Fecha</span><span>{new Date(pago.cargado_at).toLocaleString('es-PE', { day:'2-digit', month:'2-digit', year:'numeric', hour:'2-digit', minute:'2-digit' })}</span></div>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>De</span><span style={{ textTransform: 'uppercase' }}>{(pago.cliente_nombre || '').slice(0, 24)}</span></div>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>Para</span><span>{window._appConfig?.empresa_nombre || window._appConfig?.panel_nombre || 'Empresa'}</span></div>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>Cta. destino</span><span>{pago.cuenta_destino || '—'}</span></div>
            <div style={{ display: 'flex', justifyContent: 'space-between', borderTop: '1px dashed var(--line-strong)', marginTop: 8, paddingTop: 8, fontSize: 14 }}>
              <span style={{ fontWeight: 700 }}>Total</span>
              <span style={{ fontWeight: 700, color: 'var(--ink-0)' }}>{fmtMoney(monto)}</span>
            </div>
            <div style={{ marginTop: 12, padding: 8, background: 'var(--ink-9)', borderRadius: 4, textAlign: 'center', fontSize: 10 }}>
              ▮▌▮▮▌▌▮▌▮▮▌▮ — {pago.voucher_path ? 'archivo adjunto' : 'sin archivo'}
            </div>
          </div>
          <div className="row" style={{ marginTop: 12, gap: 8 }}>
            <a className="btn btn--ghost btn--sm"
               href={'/api/pagos/' + pago.id + '/descargar'}
               onClick={(e) => {
                 e.preventDefault();
                 const tk = DesasfAPI.getToken();
                 fetch('/api/pagos/' + pago.id + '/descargar', { headers: { Authorization: 'Bearer ' + tk } })
                   .then(r => r.blob())
                   .then(b => {
                     const u = URL.createObjectURL(b);
                     const a = document.createElement('a');
                     a.href = u; a.download = pago.voucher_ref + '.pdf';
                     document.body.appendChild(a); a.click(); a.remove();
                     URL.revokeObjectURL(u);
                   })
                   .catch(() => alert('No se pudo descargar el voucher'));
               }}>
              {Icon.download}<span>Descargar</span>
            </a>
            {pago.voucher_path && <span className="muted" style={{ fontSize: 11, alignSelf: 'center' }}>archivo en servidor</span>}
          </div>
        </div>

        {/* Detalle / validación */}
        <div style={{ padding: 22 }}>
          <div className="row" style={{ marginBottom: 14 }}>
            <Pill kind={pago.estado === 'confirmado' ? 'ok' : pago.estado === 'rechazado' ? 'danger' : 'review'}>
              {pago.estado === 'confirmado' ? 'Confirmado' : pago.estado === 'rechazado' ? 'Rechazado' : 'Por validar'}
            </Pill>
            <span className="muted" style={{ fontSize: 11 }}>
              Cargado {formatRelativeTime(pago.cargado_at)}{pago.cargado_por_nombre ? ` por ${pago.cargado_por_nombre}` : ''}
            </span>
          </div>

          <dl className="dl">
            <dt>Solicitud</dt><dd className="k" style={{ fontWeight: 600, color: 'var(--ink-1)' }}>{pago.ticket}</dd>
            <dt>Cliente</dt><dd>{pago.cliente_nombre}</dd>
            {montoFactura > 0 && <>
              <dt>Monto factura</dt><dd className="num" style={{ fontWeight: 600 }}>{fmtMoney(montoFactura)}</dd>
            </>}
            <dt>Monto voucher</dt>
            <dd className="num" style={{ fontWeight: 600, color: matchMonto ? 'var(--status-ok)' : 'var(--ink-1)' }}>
              {fmtMoney(monto)}{matchMonto ? ' ✓' : ''}
            </dd>
            <dt>Banco</dt><dd>{pago.banco || '—'}{pago.cuenta_destino ? ` · ${pago.cuenta_destino}` : ''}</dd>
            <dt>N° operación</dt><dd className="k">{pago.operacion_num || '—'}</dd>
            {pago.validado_por_nombre && <>
              <dt>Validado por</dt><dd>{pago.validado_por_nombre} · {formatRelativeTime(pago.validado_at)}</dd>
            </>}
          </dl>

          {!yaProcesado && (
            <div style={{ marginTop: 14, padding: 12, background: 'var(--status-pending-bg)', borderRadius: 6, display: 'flex', alignItems: 'flex-start', gap: 10, color: 'var(--status-pending)' }}>
              <span style={{ width: 20, height: 20, borderRadius: '50%', background: 'var(--status-pending)', color: '#fff', display: 'grid', placeItems: 'center', fontSize: 12, flexShrink: 0, marginTop: 1 }}>!</span>
              <div style={{ fontSize: 12 }}>
                <b>Requiere revisión manual</b>
                <div style={{ color: 'var(--ink-3)', fontSize: 11 }}>
                  La confirmación del pago la realiza el equipo de Finanzas. Nunca se valida automáticamente.
                </div>
              </div>
            </div>
          )}

          {!yaProcesado && puedeValidar && (
            <div style={{ marginTop: 10, padding: 10, background: 'var(--ink-9)', borderRadius: 6, fontSize: 11, color: 'var(--ink-4)' }}>
              <b style={{ color: 'var(--ink-2)' }}>Checklist de validación manual</b>
              <div style={{ marginTop: 6, display: 'grid', gap: 4 }}>
                {[
                  'N° de operación verificado en banca',
                  'Monto coincide con factura',
                  'Cuenta destino confirmada',
                  'Fecha y hora razonables',
                ].map((label, i) => (
                  <label key={i} className="row" style={{ gap: 6, cursor: 'pointer' }}>
                    <input type="checkbox" checked={checks[i]} onChange={() => toggleCheck(i)}/>
                    {label}
                  </label>
                ))}
              </div>
            </div>
          )}

          {(puedeValidar || pago.observaciones) && (
            <>
              <label className="label" style={{ marginTop: 16 }}>Observaciones {(!yaProcesado && puedeValidar) ? '(requeridas si rechazas)' : ''}</label>
              <textarea className="input" rows="3"
                        style={{ height: 'auto', padding: 10 }}
                        value={obs}
                        onChange={e => setObs(e.target.value)}
                        disabled={yaProcesado || !puedeValidar}
                        placeholder={puedeValidar ? 'Notas internas para el equipo de cobranzas…' : ''}/>
            </>
          )}

          {yaProcesado || !puedeValidar ? (
            <div className="row" style={{ marginTop: 18 }}>
              <button className="btn btn--ghost" style={{ flex: 1, justifyContent: 'center' }} onClick={close}>Cerrar</button>
            </div>
          ) : (
            <div className="row" style={{ marginTop: 18, gap: 8 }}>
              <button className="btn btn--ghost"
                      style={{ flex: 1, justifyContent: 'center' }}
                      onClick={handleRechazar}
                      disabled={saving}>
                {saving ? 'Procesando…' : 'Rechazar'}
              </button>
              <button className="btn btn--accent"
                      style={{ flex: 2, justifyContent: 'center' }}
                      onClick={handleValidar}
                      disabled={saving}>
                {Icon.check}<span>{saving ? 'Validando…' : 'Validar y confirmar pago'}</span>
              </button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function ModalSubirVoucher() {
  const close = () => window._desasfCloseModal && window._desasfCloseModal();
  const u     = DesasfAPI.getCurrentUser() || {};
  const esCliente = u.rol === 'cliente';

  const [empresas,    setEmpresas]    = React.useState([]);
  const [solicitudes, setSolicitudes] = React.useState([]);
  const [loading,     setLoading]     = React.useState(true);
  const [saving,      setSaving]      = React.useState(false);
  const [error,       setError]       = React.useState('');

  const [empresaId,    setEmpresaId]    = React.useState(esCliente ? u.empresa_id : '');
  const [solicitudId,  setSolicitudId]  = React.useState('');
  const [lockContext,  setLockContext]  = React.useState(false);
  const [banco,        setBanco]        = React.useState('');
  const [cuentaDest,   setCuentaDest]   = React.useState('');
  const [operacionNum, setOperacionNum] = React.useState('');
  const [monto,        setMonto]        = React.useState('');
  const [montoFact,    setMontoFact]    = React.useState('');
  const [archivo,      setArchivo]      = React.useState(null);
  const fileRef = React.useRef(null);

  React.useEffect(() => {
    const preSol = window._desasfCurrentSolicitud;
    const tasks = [];
    tasks.push(
      DesasfAPI.get(esCliente
        ? '/solicitudes?limit=200'
        : `/solicitudes?limit=200${empresaId ? '&empresa_id=' + empresaId : ''}`
      ).catch(() => ({ rows: [] }))
    );
    if (!esCliente) {
      tasks.push(DesasfAPI.get('/clientes?limit=200').catch(() => ({ rows: [] })));
    }
    Promise.all(tasks).then(([sols, emp]) => {
      const list = sols.rows || [];
      setSolicitudes(list);
      if (!esCliente && emp) setEmpresas(emp.rows || []);
      if (preSol && list.find(s => s.id === Number(preSol))) {
        setSolicitudId(Number(preSol));
        setLockContext(true);
        const found = list.find(s => s.id === Number(preSol));
        if (found && !esCliente) setEmpresaId(found.empresa_id);
        if (found?.precio_total) {
          const saldo = Math.max(0, Number(found.precio_total) - Number(found.pagado_total || 0));
          setMonto(String(saldo > 0 ? saldo.toFixed(2) : found.precio_total));
        }
      }
    }).finally(() => setLoading(false));
  }, []);

  React.useEffect(() => {
    // lockContext = empresa/solicitud precargadas desde el contexto; no
    // refiltrar ni limpiar la selección que el primer efecto acaba de fijar.
    if (esCliente || !empresaId || lockContext) return;
    DesasfAPI.get(`/solicitudes?limit=200&empresa_id=${empresaId}`)
      .then(r => setSolicitudes(r.rows || []))
      .catch(() => setSolicitudes([]));
    setSolicitudId('');
  }, [empresaId]);

  const solSel = solicitudes.find(s => s.id === Number(solicitudId));

  function onFile(e) {
    const f = e.target.files?.[0];
    if (!f) { setArchivo(null); return; }
    if (f.size > 10 * 1024 * 1024) {
      setError('El archivo supera 10 MB.');
      e.target.value = '';
      return;
    }
    const ok = ['application/pdf','image/jpeg','image/png'].includes(f.type);
    if (!ok) {
      setError('Formato no permitido. Usa PDF, JPG o PNG.');
      e.target.value = '';
      return;
    }
    setError('');
    setArchivo(f);
  }

  function clearArchivo() {
    setArchivo(null);
    if (fileRef.current) fileRef.current.value = '';
  }

  function fmtBytes(n) {
    if (!n) return '0 B';
    if (n < 1024)        return `${n} B`;
    if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
    return `${(n / 1024 / 1024).toFixed(2)} MB`;
  }

  function canSave() {
    return !!solicitudId && !!banco.trim() && !!operacionNum.trim()
        && parseFloat(monto) > 0 && !!archivo;
  }

  async function submit() {
    if (!canSave()) {
      setError('Completa los campos requeridos y adjunta el voucher.');
      return;
    }
    setError(''); setSaving(true);
    try {
      const empId = esCliente ? u.empresa_id : (empresaId || solSel?.empresa_id);
      const fd = new FormData();
      fd.append('voucher',        archivo);
      fd.append('solicitud_id',   String(solicitudId));
      fd.append('empresa_id',     String(empId));
      fd.append('banco',          banco.trim());
      fd.append('cuenta_destino', cuentaDest.trim());
      fd.append('operacion_num',  operacionNum.trim());
      fd.append('monto',          String(parseFloat(monto)));
      if (montoFact.trim()) fd.append('monto_factura', String(parseFloat(montoFact)));

      await DesasfAPI.upload('/pagos', fd);
      if (window._desasfRefreshPagos) window._desasfRefreshPagos();
      close();
    } catch (err) {
      setError(err.message || 'No se pudo subir el voucher.');
    } finally {
      setSaving(false);
    }
  }

  return (
    <div style={{ width: 640, maxHeight: '90vh', background: '#fff', borderRadius: 12, boxShadow: '0 30px 80px rgba(0,0,0,0.4)', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
      <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div>
          <div style={{ fontSize: 11, color: 'var(--ink-5)', textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 600 }}>Pago de solicitud</div>
          <div style={{ fontFamily: 'var(--cond)', fontSize: 20, fontWeight: 700, marginTop: 2 }}>Subir constancia de depósito</div>
        </div>
        <div className="icon-btn" style={{ fontSize: 18 }} onClick={close}>×</div>
      </div>

      <div style={{ padding: 22, overflow: 'auto', flex: 1 }}>
        {loading ? (
          <div style={{ padding: 24, textAlign: 'center', color: 'var(--ink-5)' }}>Cargando…</div>
        ) : (
          <>
            <div style={{ marginBottom: 14, padding: 10, background: 'var(--status-pending-bg)', color: 'var(--status-pending)', borderRadius: 6, fontSize: 12 }}>
              Tu voucher quedará <b>en revisión</b>. El equipo de Finanzas validará el pago manualmente.
            </div>

            {lockContext && (
              <div style={{ marginBottom: 14, padding: '8px 12px', background: 'var(--ink-9)', border: '1px solid var(--line)', borderRadius: 6, fontSize: 12, color: 'var(--ink-5)', display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--hi-vis)' }}/>
                Cliente y solicitud cargados desde el contexto. Cierra el modal si necesitas elegir otra solicitud.
              </div>
            )}

            {!esCliente && (
              <>
                <label className="label">Cliente</label>
                <select className="input" value={empresaId} onChange={e => setEmpresaId(e.target.value)} disabled={lockContext}>
                  <option value="">— Selecciona cliente —</option>
                  {empresas.map(e => <option key={e.id} value={e.id}>{e.razon_social}</option>)}
                </select>
              </>
            )}

            <label className="label" style={{ marginTop: 14 }}>Solicitud</label>
            <select className="input" value={solicitudId} onChange={e => {
              const id = e.target.value; setSolicitudId(id);
              const s = solicitudes.find(x => x.id === Number(id));
              if (s?.precio_total) {
                const saldo = Math.max(0, Number(s.precio_total) - Number(s.pagado_total || 0));
                setMonto(String(saldo > 0 ? saldo.toFixed(2) : s.precio_total));
              }
            }} disabled={lockContext || (!esCliente && !empresaId)}>
              <option value="">— Selecciona solicitud —</option>
              {solicitudes.map(s => (
                <option key={s.id} value={s.id}>
                  {s.ticket}{s.proyecto ? ' · ' + s.proyecto : ''} · {s.producto_nombre || ''} · S/ {Number(s.precio_total || 0).toLocaleString('es-PE')}
                </option>
              ))}
            </select>
            {solSel && (() => {
              const tot = Number(solSel.precio_total || 0);
              const pag = Number(solSel.pagado_total || 0);
              const sal = Math.max(0, tot - pag);
              const yaPago = pag > 0;
              return (
                <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>
                  Cliente: {solSel.cliente_nombre || (esCliente ? u.empresa_nombre || '' : '')} · Total: S/ {tot.toLocaleString('es-PE')}
                  {yaPago && (
                    <>
                      {' · '}
                      <span style={{ color: 'var(--status-ok)' }}>Pagado: S/ {pag.toLocaleString('es-PE', { minimumFractionDigits: 2 })}</span>
                      {' · '}
                      <span style={{ color: 'var(--status-pending)', fontWeight: 600 }}>Saldo: S/ {sal.toLocaleString('es-PE', { minimumFractionDigits: 2 })}</span>
                    </>
                  )}
                </div>
              );
            })()}

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginTop: 14 }}>
              <div>
                <label className="label">Banco</label>
                <input className="input" placeholder="Ej: BCP, Interbank, BBVA"
                  value={banco} onChange={e => setBanco(e.target.value)}/>
              </div>
              <div>
                <label className="label">Cuenta destino (opcional)</label>
                <input className="input k" placeholder="Ej: 194-xxxxx-x-xx"
                  value={cuentaDest} onChange={e => setCuentaDest(e.target.value)}/>
              </div>
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12, marginTop: 12 }}>
              <div>
                <label className="label">N° operación</label>
                <input className="input k" placeholder="Ej: 0098231"
                  value={operacionNum} onChange={e => setOperacionNum(e.target.value)}/>
              </div>
              <div>
                <label className="label">Monto pagado (S/)</label>
                <input className="input k" type="number" step="0.01" placeholder="0.00"
                  value={monto} onChange={e => setMonto(e.target.value)}/>
              </div>
              <div>
                <label className="label">Monto factura (opcional)</label>
                <input className="input k" type="number" step="0.01" placeholder="0.00"
                  value={montoFact} onChange={e => setMontoFact(e.target.value)}/>
              </div>
            </div>

            <label className="label" style={{ marginTop: 14 }}>Voucher / constancia</label>
            <input ref={fileRef} type="file" accept=".pdf,.jpg,.jpeg,.png" onChange={onFile} style={{ display: 'none' }}/>
            {!archivo ? (
              <div onClick={() => fileRef.current?.click()}
                style={{ border: '1px dashed var(--line-strong)', borderRadius: 6, padding: 14,
                  display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer',
                  background: 'var(--ink-9)', color: 'var(--ink-3)' }}>
                <div style={{ width: 32, height: 32, borderRadius: 6, background: '#fff', border: '1px solid var(--line)',
                  display: 'grid', placeItems: 'center', color: 'var(--ink-3)' }}>{Icon.upload}</div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink-1)' }}>Adjuntar voucher</div>
                  <div style={{ fontSize: 11, color: 'var(--ink-5)' }}>PDF, JPG o PNG (máx 10 MB)</div>
                </div>
              </div>
            ) : (
              <div style={{ border: '1px solid var(--line)', borderRadius: 6, padding: 10,
                  display: 'flex', alignItems: 'center', gap: 10, background: 'var(--ink-9)' }}>
                <div style={{ width: 32, height: 32, borderRadius: 5, background: '#fff', border: '1px solid var(--line)',
                  display: 'grid', placeItems: 'center', color: 'var(--ink-3)' }}>{Icon.doc}</div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{archivo.name}</div>
                  <div style={{ fontSize: 11, color: 'var(--ink-5)' }}>{fmtBytes(archivo.size)}</div>
                </div>
                <div className="icon-btn" title="Quitar" onClick={clearArchivo}
                  style={{ fontSize: 16, color: 'var(--status-danger)' }}>×</div>
              </div>
            )}

            {error && (
              <div style={{ marginTop: 12, padding: 10, background: 'var(--status-danger-bg, #fef0f0)', color: 'var(--status-danger)', borderRadius: 6, fontSize: 12 }}>
                {error}
              </div>
            )}
          </>
        )}
      </div>

      <div style={{ padding: 16, borderTop: '1px solid var(--line)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
        <button className="btn btn--ghost" onClick={close} disabled={saving}>Cancelar</button>
        <button className="btn btn--accent" onClick={submit} disabled={saving || !canSave()}>
          {Icon.check}<span>{saving ? 'Subiendo…' : 'Guardar y enviar a revisión'}</span>
        </button>
      </div>
    </div>
  );
}

function EstadoVacio() {
  return (
    <div className="app">
      <AppSidebar active="solicitudes"/>
      <Topbar crumbs={['Solicitudes']}/>
      <main className="main" style={{ display: 'grid', placeItems: 'center' }}>
        <div style={{ textAlign: 'center', maxWidth: 480 }}>
          <div style={{ width: 96, height: 96, margin: '0 auto 20px', background: 'var(--ink-9)', borderRadius: 16, display: 'grid', placeItems: 'center', position: 'relative' }}>
            <div style={{ position: 'absolute', inset: -1, background: 'repeating-linear-gradient(-45deg, transparent 0 6px, var(--hi-vis) 6px 8px)', opacity: 0.4, borderRadius: 16, mask: 'linear-gradient(#000, #000) content-box, linear-gradient(#000, #000)', WebkitMaskComposite: 'xor', maskComposite: 'exclude', padding: 4 }}/>
            <span style={{ color: 'var(--ink-3)', position: 'relative' }}><svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M3 7a2 2 0 012-2h14a2 2 0 012 2v3a2 2 0 100 4v3a2 2 0 01-2 2H5a2 2 0 01-2-2v-3a2 2 0 100-4V7z"/></svg></span>
          </div>
          <h2 style={{ fontFamily: 'var(--cond)', fontSize: 22, fontWeight: 700, margin: '0 0 8px' }}>Aún no tienes solicitudes</h2>
          <p style={{ color: 'var(--ink-5)', margin: '0 0 20px' }}>Cuando tu asistente técnico comercial o tú creen una nueva solicitud aparecerá aquí, con su línea de tiempo desde recepción hasta entrega.</p>
          <div className="row" style={{ justifyContent: 'center', gap: 8 }}>
            <button className="btn btn--ghost">Ver guía rápida</button>
            <button className="btn btn--accent" onClick={() => openModal('nueva-solicitud')}>{Icon.plus}<span>Crear primera solicitud</span></button>
          </div>
        </div>
      </main>
    </div>
  );
}

function ModalProductoDetalle() {
  const close = () => window._desasfCloseModal && window._desasfCloseModal();
  const id    = window._desasfCurrentProducto;
  const u     = DesasfAPI.getCurrentUser() || {};
  const isCliente = u.rol === 'cliente';

  const [producto, setProducto] = React.useState(null);
  const [archivos, setArchivos] = React.useState([]);
  const [loading,  setLoading]  = React.useState(true);

  React.useEffect(() => {
    if (!id) { setLoading(false); return; }
    Promise.all([
      DesasfAPI.get('/catalogo/' + id),
      DesasfAPI.get('/catalogo/' + id + '/archivos').catch(() => []),
    ]).then(([p, a]) => {
      setProducto(p || null);
      setArchivos(Array.isArray(a) ? a : []);
    }).catch(() => {}).finally(() => setLoading(false));
  }, []);

  function descargar(arch) {
    const tk  = DesasfAPI.getToken();
    const url = `/uploads/catalogo/${id}/${arch.filename}?token=${encodeURIComponent(tk)}`;
    const a   = document.createElement('a');
    a.href = url; a.download = arch.nombre || arch.filename; a.target = '_blank';
    document.body.appendChild(a); a.click(); a.remove();
  }

  function fmtSize(b) {
    b = Number(b || 0);
    if (b >= 1024 * 1024) return (b / 1024 / 1024).toFixed(1) + ' MB';
    if (b >= 1024) return (b / 1024).toFixed(0) + ' KB';
    return b + ' B';
  }

  const catLbl = { asfalto_modificado: 'Asfaltos modificados', cemento_asfaltico: 'Cementos asfálticos',
                   emulsion: 'Emulsiones', slurry: 'Tratamientos', reciclado: 'Reciclados',
                   aditivo: 'Aditivos', otro: 'Otros' };

  if (loading) return (
    <div style={{ width: 720, background: '#fff', borderRadius: 12, padding: 60, textAlign: 'center', color: 'var(--ink-5)' }}>
      Cargando producto…
    </div>
  );
  if (!producto) return (
    <div style={{ width: 480, background: '#fff', borderRadius: 12, padding: 32, textAlign: 'center' }}>
      <div style={{ color: 'var(--ink-5)', marginBottom: 14 }}>No se pudo cargar el producto.</div>
      <button className="btn btn--ghost" onClick={close}>Cerrar</button>
    </div>
  );

  const imagenes = archivos.filter(a => a.tipo === 'imagen');
  const docs     = archivos.filter(a => a.tipo !== 'imagen');

  return (
    <div style={{ width: 720, maxHeight: '92vh', background: '#fff', borderRadius: 12, boxShadow: '0 30px 80px rgba(0,0,0,0.4)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
      <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between' }}>
        <div>
          <div style={{ fontSize: 11, color: 'var(--ink-5)', fontFamily: 'var(--mono)', marginBottom: 2 }}>{producto.codigo}</div>
          <div style={{ fontFamily: 'var(--cond)', fontSize: 20, fontWeight: 700 }}>{producto.nombre}</div>
        </div>
        <div className="icon-btn" style={{ fontSize: 18 }} onClick={close}>×</div>
      </div>

      <div style={{ padding: 22, overflow: 'auto', flex: 1 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14, marginBottom: 18 }}>
          <div>
            <div className="meta" style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Categoría</div>
            <div style={{ fontWeight: 600, fontSize: 13 }}>{catLbl[producto.categoria] || producto.categoria || '—'}</div>
          </div>
          <div>
            <div className="meta" style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Precio</div>
            <div style={{ fontWeight: 600, fontFamily: 'var(--mono)', fontSize: 13 }}>S/ {Number(producto.precio_base).toLocaleString('es-PE')}/{producto.unidad || 'm³'}</div>
          </div>
          {producto.tag_especial && (
            <div>
              <div className="meta" style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Etiqueta</div>
              <span style={{ display: 'inline-block', background: 'var(--hi-vis)', color: 'var(--ink-0)', fontSize: 11, fontWeight: 700, padding: '3px 7px', borderRadius: 3, letterSpacing: '0.06em', textTransform: 'uppercase' }}>{producto.tag_especial}</span>
            </div>
          )}
        </div>

        {producto.especificacion && (
          <div style={{ marginBottom: 14 }}>
            <div className="meta" style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Especificación técnica</div>
            <div style={{ fontSize: 13, lineHeight: 1.6 }}>{producto.especificacion}</div>
          </div>
        )}
        {producto.descripcion && (
          <div style={{ marginBottom: 18 }}>
            <div className="meta" style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>Descripción comercial</div>
            <div style={{ fontSize: 13, lineHeight: 1.6, color: 'var(--ink-3)' }}>{producto.descripcion}</div>
          </div>
        )}

        {imagenes.length > 0 && (
          <div style={{ marginBottom: 18 }}>
            <div className="meta" style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6 }}>Imágenes</div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              {imagenes.map(img => (
                <img key={img.id}
                  src={`/uploads/catalogo/${id}/${img.filename}?token=${encodeURIComponent(DesasfAPI.getToken())}`}
                  alt={img.nombre}
                  title={img.nombre + ' · click para descargar'}
                  style={{ width: 160, height: 110, objectFit: 'cover', borderRadius: 6, border: '1px solid var(--line)', cursor: 'pointer' }}
                  onClick={() => descargar(img)}/>
              ))}
            </div>
          </div>
        )}

        <div>
          <div className="meta" style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6 }}>
            Archivos asociados ({docs.length})
          </div>
          {docs.length === 0 ? (
            <div style={{ padding: 16, textAlign: 'center', color: 'var(--ink-5)', fontSize: 12, border: '1px dashed var(--line)', borderRadius: 6 }}>
              Sin documentos adicionales para este producto.
            </div>
          ) : (
            <div style={{ border: '1px solid var(--line)', borderRadius: 6, overflow: 'hidden' }}>
              {docs.map((d, i) => (
                <div key={d.id} style={{ padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 10, borderBottom: i < docs.length - 1 ? '1px solid var(--line)' : 0, background: '#fff' }}>
                  <div style={{ color: 'var(--ink-4)' }}>{Icon.doc}</div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.nombre}</div>
                    <div className="muted" style={{ fontSize: 11 }}>{fmtSize(d.size_bytes)}{d.mime_type ? ' · ' + d.mime_type : ''}</div>
                  </div>
                  <button className="btn btn--ghost btn--sm" onClick={() => descargar(d)}>
                    {Icon.download}<span>Descargar</span>
                  </button>
                </div>
              ))}
            </div>
          )}
        </div>
      </div>

      <div style={{ padding: '14px 22px', borderTop: '1px solid var(--line)', display: 'flex', justifyContent: 'flex-end' }}>
        <button className="btn btn--ghost" onClick={close}>Cerrar</button>
      </div>
    </div>
  );
}

window.ModalNuevaSolicitud = ModalNuevaSolicitud;
window.ModalValidarVoucher = ModalValidarVoucher;
window.ModalSubirVoucher   = ModalSubirVoucher;
window.ModalProductoDetalle = ModalProductoDetalle;
window.EstadoVacio = EstadoVacio;
