// Vista del trabajador de Catálogo (operador comercial / producto)
// Enfocada en gestión de productos: agregar, editar precios, controlar stock, cargar fichas técnicas.

function VistaCatalogador() {
  const [tab,          setTab]          = React.useState('listado');
  const [prodsAPI,     setProdsAPI]     = React.useState([]);
  const [loading,      setLoading]      = React.useState(true);
  const [editProdId,   setEditProdId]   = React.useState(null);
  const [catFilter,    setCatFilter]    = React.useState('todos');
  const [estadoFilter, setEstadoFilter] = React.useState('todos');
  const [searchQ,      setSearchQ]      = React.useState('');
  const [menuOpen,     setMenuOpen]     = React.useState(null);
  const [reorderMode,  setReorderMode]  = React.useState(false);
  const [orderList,    setOrderList]    = React.useState([]); // arreglo de _id
  const [dragIdx,      setDragIdx]      = React.useState(null);

  function fetchProds() {
    setLoading(true);
    DesasfAPI.get('/catalogo?activo=1&limit=200')
      .then(r => setProdsAPI(r.rows || []))
      .catch(console.error)
      .finally(() => setLoading(false));
  }

  React.useEffect(fetchProds, []);

  React.useEffect(() => {
    if (window._desasfCatalogadorNuevo) {
      setEditProdId(null);
      setTab('agregar');
      delete window._desasfCatalogadorNuevo;
    } else if (window._desasfCurrentProducto) {
      setEditProdId(window._desasfCurrentProducto);
      setTab('agregar');
      delete window._desasfCurrentProducto;
    }
  }, []);

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

  const _token = DesasfAPI.getToken() || '';
  const productos = prodsAPI.map(p => ({
    sku:     p.codigo,
    n:       p.nombre,
    cat:     catLbl[p.categoria] || p.categoria,
    p:       Number(p.precio_base || 0),
    unidad:  p.unidad || 'kg',
    estado:  p.activo ? 'Publicado' : 'Borrador',
    upd:     window.formatRelativeTime ? window.formatRelativeTime(p.updated_at) : '—',
    fichaQ:  !!p.descripcion || !!p.especificacion,
    vol:     0,
    _id:     p.id,
    img:     p.imagen_filename ? `/uploads/catalogo/${p.id}/${p.imagen_filename}?token=${_token}` : null,
  }));

  async function handleEliminar(id) {
    if (!confirm('¿Desactivar este producto del catálogo?')) return;
    try {
      await DesasfAPI.delete('/catalogo/' + id);
      fetchProds();
    } catch (err) { alert('Error: ' + err.message); }
  }
  function startReorder() {
    setOrderList(productos.map(p => p._id));
    setDragIdx(null);
    setReorderMode(true);
  }
  function moveOrder(idx, dir) {
    setOrderList(list => {
      const ni = idx + dir;
      if (ni < 0 || ni >= list.length) return list;
      const copy = [...list];
      [copy[idx], copy[ni]] = [copy[ni], copy[idx]];
      return copy;
    });
  }
  function dropOrder(idx) {
    setOrderList(list => {
      if (dragIdx === null || dragIdx === idx) return list;
      const copy = [...list];
      const [moved] = copy.splice(dragIdx, 1);
      copy.splice(idx, 0, moved);
      return copy;
    });
    setDragIdx(null);
  }
  async function saveOrder() {
    try {
      await DesasfAPI.put('/catalogo/orden', { orden: orderList });
      setReorderMode(false);
      fetchProds();
    } catch (err) { alert('Error: ' + err.message); }
  }

  window._desasfCatalogadorRefresh = fetchProds;
  window._desasfCatalogadorEliminar = handleEliminar;

  const meRol = (DesasfAPI.getCurrentUser() || {}).rol;
  const canListPrice = ['dev', 'admin', 'gerente_general', 'gerente_comercial', 'finanzas'].includes(meRol);

  const filteredProds = productos
    .filter(p => catFilter === 'todos' || p.cat === catFilter)
    .filter(p => estadoFilter === 'todos' || p.estado === estadoFilter)
    .filter(p => !searchQ.trim() || p.n.toLowerCase().includes(searchQ.toLowerCase()) || (p.sku || '').toLowerCase().includes(searchQ.toLowerCase()));

  const activos    = productos.filter(p => p.estado === 'Publicado').length;
  const borradores = productos.filter(p => p.estado !== 'Publicado').length;

  const catCounts = {};
  productos.forEach(p => { catCounts[p.cat] = (catCounts[p.cat] || 0) + 1; });

  return (
    <div className="app">
      <Sidebar active="catalogo"/>
      <Topbar
        crumbs={['Información', 'Catálogo', 'Editor de productos']}
        cta={<button className="btn btn--accent" onClick={() => { setEditProdId(null); setTab('agregar'); }}>{Icon.plus}<span>Nuevo producto</span></button>}
      />
      <main className="main">

        <div className="page-head">
          <div>
            {(() => {
              const cu = DesasfAPI.getCurrentUser() || {};
              const parts = (cu.nombre || 'Usuario').trim().split(/\s+/);
              const ini   = parts.length >= 2 ? (parts[0][0]+parts[parts.length-1][0]).toUpperCase() : (parts[0]?.[0]||'?').toUpperCase();
              const rolDesc = { dev: 'Desarrollador', operador_planta: 'Operador planta', admin: 'Administrador', gerente_general: 'Gerente general', gerente_comercial: 'Gerente comercial', finanzas: 'Finanzas', vendedor: 'Asistente Técnico comercial' }[cu.rol] || cu.rol || 'Operador';
              const canPrice = ['dev', 'admin', 'gerente_general', 'gerente_comercial', 'finanzas'].includes(cu.rol);
              return (
                <div className="row" style={{ gap: 10, marginBottom: 4 }}>
                  <div className="avatar" style={{ width: 40, height: 40, fontSize: 14, background: 'var(--status-prod)', color: '#fff' }}>{ini}</div>
                  <div>
                    <h1 style={{ marginBottom: 2 }}>Editor de catálogo</h1>
                    <p>{cu.nombre || 'Usuario'} · {rolDesc} · puede crear / editar / publicar productos{canPrice ? '' : ' · NO puede modificar tarifas (eso lo hace Finanzas)'}</p>
                  </div>
                </div>
              );
            })()}
          </div>
          <div className="row" style={{ gap: 10 }}>
            <MiniKPI label="Activos"    value={String(activos)}    tone="ok"/>
            <MiniKPI label="Borradores" value={String(borradores)} tone="muted"/>
          </div>
        </div>

        {/* Tabs */}
        <div className="cfg-tabs">
          {[
            { id: 'listado', label: 'Listado de productos', count: productos.length || null },
            { id: 'agregar', label: 'Crear / editar producto' },
            { id: 'tarifas', label: 'Solicitudes de cambio de tarifa' },
          ].map(x => (
            <div key={x.id} className={`cfg-tab ${x.id === tab ? 'is-active' : ''}`} onClick={() => setTab(x.id)}>
              <span>{x.label}</span>
              {x.count != null && <span className="cfg-tab__count">{x.count}</span>}
            </div>
          ))}
        </div>

        {tab === 'listado' && !reorderMode && (
          <>
            <div className="filterbar">
              <input className="input" style={{ width: 180, height: 28, padding: '0 8px', fontSize: 12 }}
                placeholder="Buscar producto…" value={searchQ} onChange={e => setSearchQ(e.target.value)}/>
              <span className={`chip ${catFilter === 'todos' ? 'is-active' : ''}`}
                onClick={() => setCatFilter('todos')} style={{ cursor: 'pointer' }}>
                Todos <span className="n">{productos.length}</span>
              </span>
              {Object.entries(catCounts).map(([cat, n]) => (
                <span key={cat} className={`chip ${catFilter === cat ? 'is-active' : ''}`}
                  onClick={() => setCatFilter(catFilter === cat ? 'todos' : cat)} style={{ cursor: 'pointer' }}>
                  {cat} <span className="n">{n}</span>
                </span>
              ))}
              <div style={{ marginLeft: 'auto', display: 'flex', gap: 8, alignItems: 'center' }}>
                <select className="input" style={{ height: 28, padding: '0 8px', fontSize: 12 }}
                  value={estadoFilter} onChange={e => setEstadoFilter(e.target.value)}>
                  <option value="todos">Estado: todos</option>
                  <option value="Publicado">Publicado</option>
                  <option value="Borrador">Borrador</option>
                </select>
                <button className="btn btn--ghost btn--sm" onClick={startReorder} disabled={productos.length < 2}>
                  {Icon.more}<span>Editar orden</span>
                </button>
                <button className="btn btn--ghost btn--sm">{Icon.upload}<span>Importar CSV</span></button>
                <button className="btn btn--ghost btn--sm">{Icon.download}<span>Exportar</span></button>
              </div>
            </div>
            <div className="card" style={{ borderRadius: '0 0 var(--r-2) var(--r-2)', borderTop: 0 }}>
              <table className="tbl">
                <thead><tr>
                  <th style={{ width: 30 }}><input type="checkbox" readOnly/></th>
                  <th>SKU / Producto</th><th>Categoría</th>
                  <th style={{ textAlign: 'right' }}>Precio (S/)</th>
                  <th>Ficha técnica</th><th>Vol. mes</th><th>Estado</th><th>Actualizado</th><th></th>
                </tr></thead>
                <tbody>
                  {filteredProds.length === 0 && (
                    <tr><td colSpan={9} style={{ padding: 32, textAlign: 'center', color: 'var(--ink-5)' }}>Sin productos con los filtros aplicados.</td></tr>
                  )}
                  {filteredProds.map(p => (
                    <tr key={p._id}>
                      <td><input type="checkbox" readOnly/></td>
                      <td>
                        <div className="row" style={{ gap: 10 }}>
                          <div style={{ width: 36, height: 36, borderRadius: 6, overflow: 'hidden', background: 'var(--ink-2)', color: 'var(--hi-vis)', display: 'grid', placeItems: 'center', flexShrink: 0 }}>
                          {p.img
                            ? <img src={p.img} style={{ width: '100%', height: '100%', objectFit: 'cover' }} alt=""/>
                            : Icon.beaker
                          }
                        </div>
                          <div>
                            <div style={{ fontWeight: 600, color: 'var(--ink-0)' }}>{p.n}</div>
                            <div className="k muted" style={{ fontSize: 11 }}>{p.sku}</div>
                          </div>
                        </div>
                      </td>
                      <td>{p.cat}</td>
                      <td className="num" style={{ textAlign: 'right', fontWeight: 600 }}>
                        {p.p.toLocaleString('es-PE')}
                        {!canListPrice && <span className="tag" style={{ marginLeft: 6, fontSize: 9, padding: '0 4px', height: 16 }}>SOLO LEC.</span>}
                      </td>
                      <td>{p.fichaQ ? <Pill kind="ok">PDF · QC</Pill> : <Pill kind="pending">Falta</Pill>}</td>
                      <td className="num">{p.vol} {p.unidad}</td>
                      <td>
                        {p.estado === 'Publicado' && <Pill kind="ok">Publicado</Pill>}
                        {p.estado === 'Borrador' && <Pill kind="neutral">Borrador</Pill>}
                        {p.estado === 'Bajo pedido' && <Pill kind="review">Bajo pedido</Pill>}
                      </td>
                      <td className="num muted" style={{ fontSize: 11 }}>{p.upd}</td>
                      <td style={{ position: 'relative' }}>
                        <div className="row" style={{ gap: 4 }}>
                          <button className="btn btn--ghost btn--sm" onClick={() => { setEditProdId(p._id); setTab('agregar'); }}>Editar</button>
                          <div className="icon-btn" onClick={e => { e.stopPropagation(); setMenuOpen(menuOpen === p._id ? null : p._id); }}>{Icon.more}</div>
                        </div>
                        {menuOpen === p._id && (
                          <div style={{ position: 'absolute', top: '100%', right: 0, zIndex: 200, background: 'var(--surface)', border: '1px solid var(--line)', borderRadius: 8, padding: '4px 0', minWidth: 190, boxShadow: '0 4px 16px rgba(0,0,0,.18)' }}>
                            <div className="menu-item" onClick={() => { setEditProdId(p._id); setTab('agregar'); setMenuOpen(null); }}>
                              {Icon.doc}<span>Editar producto</span>
                            </div>
                            <div className="menu-item" style={{ color: 'var(--status-danger)' }} onClick={() => { setMenuOpen(null); handleEliminar(p._id); }}>
                              {Icon.x}<span>Desactivar</span>
                            </div>
                          </div>
                        )}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>

          </>
        )}

        {tab === 'listado' && reorderMode && (
          <div className="card">
            <div className="card__head">
              <h3>Reordenar productos del catálogo</h3>
              <div className="row" style={{ gap: 8 }}>
                <button className="btn btn--ghost btn--sm" onClick={() => setReorderMode(false)}>Cancelar</button>
                <button className="btn btn--accent btn--sm" onClick={saveOrder}>{Icon.check}<span>Guardar orden</span></button>
              </div>
            </div>
            <div style={{ padding: '10px 14px', fontSize: 12, color: 'var(--ink-5)', borderBottom: '1px solid var(--line)' }}>
              Arrastra cada fila o usa las flechas para definir el orden en que se mostrarán los productos.
            </div>
            <div className="card__body" style={{ padding: 0 }}>
              {orderList.map((id, idx) => {
                const p = productos.find(x => x._id === id);
                if (!p) return null;
                return (
                  <div key={id} draggable
                    onDragStart={() => setDragIdx(idx)}
                    onDragOver={e => e.preventDefault()}
                    onDrop={() => dropOrder(idx)}
                    style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px',
                             borderBottom: idx < orderList.length - 1 ? '1px solid var(--line)' : 0,
                             background: dragIdx === idx ? 'var(--ink-9)' : 'transparent', cursor: 'grab' }}>
                    <span style={{ color: 'var(--ink-6)', display: 'grid', placeItems: 'center' }}>{Icon.more}</span>
                    <span style={{ width: 24, textAlign: 'right', fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--ink-5)' }}>{idx + 1}</span>
                    <div style={{ width: 32, height: 32, borderRadius: 6, overflow: 'hidden', background: 'var(--ink-2)', color: 'var(--hi-vis)', display: 'grid', placeItems: 'center', flexShrink: 0 }}>
                      {p.img ? <img src={p.img} style={{ width: '100%', height: '100%', objectFit: 'cover' }} alt=""/> : Icon.beaker}
                    </div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontWeight: 600, color: 'var(--ink-0)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.n}</div>
                      <div className="muted" style={{ fontSize: 11 }}>{p.sku || '—'} · {p.cat}</div>
                    </div>
                    <div className="row" style={{ gap: 4 }}>
                      <button className="btn btn--ghost btn--sm" disabled={idx === 0} onClick={() => moveOrder(idx, -1)} title="Subir">↑</button>
                      <button className="btn btn--ghost btn--sm" disabled={idx === orderList.length - 1} onClick={() => moveOrder(idx, 1)} title="Bajar">↓</button>
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        )}

        {tab === 'agregar' && <FormProducto prodId={editProdId} onSaved={() => { fetchProds(); setTab('listado'); }}/>}

        {tab === 'tarifas' && <SolicitudesTarifa/>}

        {menuOpen && <div style={{ position: 'fixed', inset: 0, zIndex: 199 }} onClick={() => setMenuOpen(null)}/>}
      </main>
    </div>
  );
}

function FormProducto({ prodId, onSaved }) {
  const isEdit = !!prodId;
  const u      = DesasfAPI.getCurrentUser() || {};
  const canEditPrice = DesasfAPI.hasPerm('catalogo.editar');

  const EMPTY = { nombre: '', codigo: '', categoria: 'asfalto_modificado', unidad: 'kg',
                  descripcion: '', especificacion: '', precio_base: '', activo: true };

  const [form,      setForm]      = React.useState(EMPTY);
  const [historial, setHistorial] = React.useState([]);
  const [loading,   setLoading]   = React.useState(isEdit);
  const [saving,    setSaving]    = React.useState(false);
  const [archivos,  setArchivos]  = React.useState([]);
  const [uploading, setUploading] = React.useState(false);
  // Archivos en cola cuando aún se está creando el producto (sin id todavía).
  const [pendientes, setPendientes] = React.useState([]);
  // Unidades de venta configurables (gestionadas por el Dev en Configuración).
  const [unidades, setUnidades] = React.useState([]);

  React.useEffect(() => {
    DesasfAPI.get('/config/unidades').then(setUnidades).catch(() => setUnidades([]));
  }, []);

  React.useEffect(() => {
    if (!isEdit) { setForm(EMPTY); setHistorial([]); setArchivos([]); setPendientes([]); setLoading(false); return; }
    setLoading(true);
    Promise.all([
      DesasfAPI.get('/catalogo/' + prodId),
      DesasfAPI.get('/catalogo/' + prodId + '/historial').catch(() => []),
      DesasfAPI.get('/catalogo/' + prodId + '/archivos').catch(() => []),
    ]).then(([prod, hist, archs]) => {
      setForm({
        nombre:         prod.nombre || '',
        codigo:         prod.codigo || '',
        categoria:      prod.categoria || 'asfalto_modificado',
        unidad:         prod.unidad || 'kg',
        descripcion:    prod.descripcion || '',
        especificacion: prod.especificacion || '',
        precio_base:    prod.precio_base != null ? String(prod.precio_base) : '',
        activo:         prod.activo !== 0,
      });
      setHistorial(Array.isArray(hist) ? hist : []);
      setArchivos(Array.isArray(archs) ? archs : []);
    }).catch(console.error)
      .finally(() => setLoading(false));
  }, [prodId]);

  function field(key) { return form[key] ?? ''; }
  function setField(key, val) { setForm(f => ({ ...f, [key]: val })); }

  async function guardar(pub) {
    if (!form.nombre.trim()) {
      alert('El nombre del producto es obligatorio'); return;
    }
    const payload = {
      nombre:         form.nombre,
      codigo:         form.codigo || null,
      categoria:      form.categoria || 'otro',
      unidad:         form.unidad || 'kg',
      descripcion:    form.descripcion || null,
      especificacion: form.especificacion || null,
      precio_base:    parseFloat(form.precio_base) || 0,
      activo:         pub ? 1 : (form.activo ? 1 : 0),
    };
    setSaving(true);
    try {
      if (isEdit) {
        await DesasfAPI.put('/catalogo/' + prodId, payload);
      } else {
        const { id: nuevoId } = await DesasfAPI.post('/catalogo', payload);
        // Sube los archivos que se hayan adjuntado durante la creación.
        for (const pf of pendientes) {
          try {
            const fd = new FormData();
            fd.append('file', pf.file);
            await DesasfAPI.upload('/catalogo/' + nuevoId + '/archivos', fd);
          } catch (e) { console.error('No se pudo subir', pf.nombre, e); }
        }
      }
      onSaved && onSaved();
    } catch (err) { alert('Error: ' + err.message); }
    finally { setSaving(false); }
  }

  const token = DesasfAPI.getToken() || '';
  // En edición las fuentes vienen de la API; en creación, de la cola local.
  const imagen     = isEdit ? (archivos.find(a => a.tipo === 'imagen') || null)
                            : (pendientes.find(a => a.tipo === 'imagen') || null);
  const documentos = isEdit ? archivos.filter(a => a.tipo === 'documento')
                            : pendientes.filter(a => a.tipo === 'documento');
  // URL de la imagen a mostrar (servidor si está guardada, blob local si está en cola).
  const imagenSrc = imagen
    ? (imagen.local ? imagen.previewUrl : `/uploads/catalogo/${prodId}/${imagen.filename}?token=${token}`)
    : null;

  function formatBytes(b) {
    if (!b) return '—';
    if (b < 1024) return b + ' B';
    if (b < 1048576) return (b / 1024).toFixed(1) + ' KB';
    return (b / 1048576).toFixed(1) + ' MB';
  }

  async function handleUploadFile(e) {
    const file = e.target.files[0];
    if (!file) return;
    e.target.value = '';

    // Producto aún no creado: se encola para subir tras guardar.
    if (!isEdit) {
      const tipo = (file.type || '').startsWith('image/') ? 'imagen' : 'documento';
      const entry = {
        local:      true,
        id:         'tmp-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7),
        tipo,
        nombre:     file.name,
        size_bytes: file.size,
        file,
        previewUrl: tipo === 'imagen' ? URL.createObjectURL(file) : null,
      };
      setPendientes(prev =>
        tipo === 'imagen'
          ? [...prev.filter(a => a.tipo !== 'imagen'), entry]   // 1 sola imagen
          : [...prev, entry]
      );
      return;
    }

    setUploading(true);
    try {
      const fd = new FormData();
      fd.append('file', file);
      const result = await DesasfAPI.upload('/catalogo/' + prodId + '/archivos', fd);
      setArchivos(prev =>
        result.tipo === 'imagen'
          ? [...prev.filter(a => a.tipo !== 'imagen'), result]
          : [...prev, result]
      );
    } catch (err) { alert('Error al subir: ' + err.message); }
    finally { setUploading(false); }
  }

  async function handleDeleteArchivo(id) {
    // Archivo en cola (creación): solo se quita de la lista local.
    const local = pendientes.find(a => a.id === id);
    if (local) {
      if (local.previewUrl) URL.revokeObjectURL(local.previewUrl);
      setPendientes(prev => prev.filter(a => a.id !== id));
      return;
    }
    if (!confirm('¿Eliminar este archivo?')) return;
    try {
      await DesasfAPI.delete('/catalogo/' + prodId + '/archivos/' + id);
      setArchivos(prev => prev.filter(a => a.id !== id));
    } catch (err) { alert('Error: ' + err.message); }
  }

  if (loading) return <div style={{ padding: 40, textAlign: 'center', color: 'var(--ink-5)' }}>Cargando…</div>;

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 340px', gap: 16 }}>
      <div className="card">
        <div className="card__head">
          <h3>Datos del producto</h3>
          {isEdit && <span className="meta">Editando · {form.codigo || '—'}</span>}
        </div>
        <div className="card__body">
          <div className="row" style={{ gap: 12, alignItems: 'flex-start', marginBottom: 12 }}>
            <div style={{ width: 80, height: 80, borderRadius: 8, overflow: 'hidden', background: 'var(--ink-2)', color: 'var(--hi-vis)', display: 'grid', placeItems: 'center', flexShrink: 0 }}>
              {imagenSrc
                ? <img src={imagenSrc}
                    style={{ width: '100%', height: '100%', objectFit: 'cover' }} alt=""/>
                : <svg viewBox="0 0 24 24" width="34" height="34" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M9 3h6M10 3v6L4 19a2 2 0 002 2h12a2 2 0 002-2L14 9V3"/><path d="M7 14h10"/></svg>
              }
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ marginBottom: 12 }}>
                <label className="label">Nombre comercial *</label>
                <input className="input" value={field('nombre')} onChange={e => setField('nombre', e.target.value)} placeholder="Ej: Asfalto modificado PG 76-22"/>
              </div>
              <div className="row" style={{ gap: 12 }}>
                <div style={{ flex: 1 }}>
                  <label className="label">Código / SKU</label>
                  <input className="input k" value={field('codigo')} onChange={e => setField('codigo', e.target.value)} placeholder="P-0001"/>
                </div>
                <div style={{ flex: 1 }}>
                  <label className="label">Especificación</label>
                  <input className="input k" value={field('especificacion')} onChange={e => setField('especificacion', e.target.value)} placeholder="PG 76-22"/>
                </div>
              </div>
            </div>
          </div>

          <div className="row" style={{ gap: 12, marginBottom: 12 }}>
            <div style={{ flex: 1 }}>
              <label className="label">Categoría</label>
              <select className="input" value={field('categoria')} onChange={e => setField('categoria', e.target.value)}>
                <option value="asfalto_modificado">Asfaltos modificados</option>
                <option value="cemento_asfaltico">Cementos asfálticos</option>
                <option value="emulsion">Emulsiones</option>
                <option value="aditivo">Aditivos</option>
                <option value="otro">Otros</option>
              </select>
            </div>
            <div style={{ flex: 1 }}>
              <label className="label">Unidad de venta</label>
              <select className="input" value={field('unidad')} onChange={e => setField('unidad', e.target.value)}>
                {unidades.map(u => (
                  <option key={u.codigo} value={u.codigo}>{u.simbolo} — {u.nombre}</option>
                ))}
                {/* Conserva la unidad actual del producto aunque ya no esté en la lista. */}
                {field('unidad') && !unidades.some(u => u.codigo === field('unidad')) && (
                  <option value={field('unidad')}>{field('unidad')} (descontinuada)</option>
                )}
              </select>
            </div>
          </div>

          <div style={{ marginBottom: 12 }}>
            <label className="label">Descripción comercial</label>
            <textarea className="input" rows="3" style={{ height: 'auto', padding: 10, resize: 'vertical' }}
              value={field('descripcion')} onChange={e => setField('descripcion', e.target.value)}
              placeholder="Descripción para el catálogo de clientes…"/>
          </div>

          <div style={{ borderTop: '1px solid var(--line)', paddingTop: 14, marginTop: 4 }}>
            <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--ink-5)', marginBottom: 12 }}>Precio</div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 12 }}>
              <div>
                <label className="label">Precio base (S/ / {field('unidad') || 'kg'})</label>
                {canEditPrice
                  ? <input className="input k" type="number" min="0" step="0.01" value={field('precio_base')}
                      onChange={e => setField('precio_base', e.target.value)}/>
                  : <div className="input k" style={{ background: 'var(--ink-9)', cursor: 'not-allowed', display: 'flex', alignItems: 'center' }}>
                      {field('precio_base') ? `S/ ${Number(field('precio_base')).toLocaleString('es-PE')}` : '—'}
                      <span className="tag" style={{ marginLeft: 8, fontSize: 9 }}>SOLO LEC.</span>
                    </div>
                }
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* Sidebar derecha */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>

        {/* Imagen */}
        <div className="card" style={{ overflow: 'hidden' }}>
          <div className="card__head">
            <h3>Imagen</h3>
            <label className="btn btn--ghost btn--sm" style={{ cursor: 'pointer' }}>
              {uploading ? Icon.clock : Icon.upload}<span>{imagen ? 'Cambiar' : 'Subir'}</span>
              <input type="file" accept="image/jpeg,image/png,image/webp,image/gif" hidden
                onChange={handleUploadFile} disabled={uploading}/>
            </label>
          </div>
          {imagen ? (
            <div style={{ position: 'relative' }}>
              <img src={imagenSrc}
                style={{ width: '100%', maxHeight: 210, objectFit: 'cover', display: 'block' }} alt=""/>
              <button className="btn btn--sm"
                style={{ position: 'absolute', top: 8, right: 8, background: 'rgba(0,0,0,.55)', color: '#fff', border: 0, borderRadius: 6, padding: '2px 6px' }}
                onClick={() => handleDeleteArchivo(imagen.id)}>{Icon.x}</button>
            </div>
          ) : (
            <label style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '28px 16px', cursor: 'pointer', color: 'var(--ink-5)', borderTop: '2px dashed var(--line)', margin: '0 -1px -1px' }}>
              <svg viewBox="0 0 24 24" width="32" height="32" fill="none" stroke="currentColor" strokeWidth="1.4" style={{ color: 'var(--ink-7)', marginBottom: 8 }}>
                <rect x="3" y="3" width="18" height="18" rx="3"/>
                <circle cx="8.5" cy="8.5" r="1.5"/>
                <path d="M21 15l-5-5L5 21"/>
              </svg>
              <span style={{ fontSize: 12, textAlign: 'center', lineHeight: 1.5 }}>Arrastra o haz clic<br/>para subir imagen</span>
              <input type="file" accept="image/jpeg,image/png,image/webp,image/gif" hidden
                onChange={handleUploadFile} disabled={uploading}/>
            </label>
          )}
        </div>

        {/* Archivos / documentos */}
        <div className="card">
          <div className="card__head">
            <h3>Archivos</h3>
            <label className="btn btn--ghost btn--sm" style={{ cursor: 'pointer' }}>
              {uploading ? Icon.clock : Icon.upload}<span>{uploading ? 'Subiendo…' : 'Adjuntar'}</span>
              <input type="file" accept=".pdf,.xlsx,.xls,.doc,.docx,.csv,.txt,.zip" hidden
                onChange={handleUploadFile} disabled={uploading}/>
            </label>
          </div>
          <div className="card__body" style={{ padding: 0 }}>
            {!isEdit && (
              <div style={{ padding: '10px 14px', fontSize: 11, color: 'var(--ink-5)', borderBottom: documentos.length ? '1px solid var(--line)' : 0 }}>
                Los archivos se subirán al guardar el producto.
              </div>
            )}
            {documentos.length === 0 ? (
              <div style={{ padding: '14px', color: 'var(--ink-5)', fontSize: 12 }}>Sin documentos adjuntos.</div>
            ) : documentos.map((a, i) => (
              <div key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '9px 14px', borderBottom: i < documentos.length - 1 ? '1px solid var(--line)' : 0 }}>
                <div style={{ flexShrink: 0, color: 'var(--ink-5)' }}>{Icon.doc}</div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.nombre}</div>
                  <div style={{ fontSize: 10, color: 'var(--ink-5)' }}>{formatBytes(a.size_bytes)}</div>
                </div>
                {!a.local && (
                  <a href={`/uploads/catalogo/${prodId}/${a.filename}?token=${token}`} download={a.nombre}
                    className="btn btn--ghost btn--sm" title="Descargar">{Icon.download}</a>
                )}
                <button className="btn btn--ghost btn--sm" style={{ color: 'var(--status-danger)' }}
                  title="Eliminar" onClick={() => handleDeleteArchivo(a.id)}>{Icon.x}</button>
              </div>
            ))}
          </div>
        </div>

        <div className="card">
          <div className="card__head"><h3>Publicación</h3></div>
          <div className="card__body">
            <div className="row" style={{ marginBottom: 14, justifyContent: 'space-between' }}>
              <span style={{ fontSize: 12 }}>Estado</span>
              <select className="select-ghost" value={form.activo ? 'pub' : 'borrador'}
                onChange={e => setField('activo', e.target.value === 'pub')}>
                <option value="pub">Publicado</option>
                <option value="borrador">Borrador</option>
              </select>
            </div>
            <button className="btn btn--accent" style={{ width: '100%', justifyContent: 'center' }} disabled={saving}
              onClick={() => guardar(true)}>
              {Icon.check}<span>{saving ? 'Guardando…' : (isEdit ? 'Guardar cambios' : 'Crear y publicar')}</span>
            </button>
            <button className="btn btn--ghost btn--sm" style={{ width: '100%', justifyContent: 'center', marginTop: 6 }} disabled={saving}
              onClick={() => guardar(false)}>
              {isEdit ? 'Guardar borrador' : 'Crear borrador'}
            </button>
          </div>
        </div>

        {isEdit && (
          <div className="card">
            <div className="card__head"><h3>Historial</h3></div>
            <div className="card__body" style={{ padding: 0 }}>
              {historial.length === 0 ? (
                <div style={{ padding: '16px 14px', color: 'var(--ink-5)', fontSize: 13 }}>Sin registros de cambios.</div>
              ) : historial.map((h, i) => {
                let ctx = {};
                try { ctx = JSON.parse(h.contexto || '{}'); } catch {}
                const accionLabel = { ajuste_stock: 'Ajuste de stock', update: 'Edición', create: 'Creación' }[h.accion] || h.accion;
                const detalle = ctx.descripcion || ctx.delta != null ? `${ctx.delta > 0 ? '+' : ''}${ctx.delta} · ${ctx.descripcion || ''}` : accionLabel;
                return (
                  <div key={h.id} className="activity" style={{ padding: '10px 14px', borderBottom: i < historial.length - 1 ? '1px solid var(--line)' : 0 }}>
                    <span className="activity__dot"/>
                    <div className="activity__body">
                      <span className="activity__time" style={{ display: 'block' }}>
                        {window.formatRelativeTime ? window.formatRelativeTime(h.created_at) : h.created_at} · {h.usuario_nombre}
                      </span>
                      <span style={{ fontSize: 12 }}>{detalle}</span>
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function SolicitudesTarifa() {
  const u         = DesasfAPI.getCurrentUser() || {};
  const canEdit   = DesasfAPI.hasPerm('catalogo.editar');
  return (
    <div className="card">
      <div className="card__head">
        <h3>Solicitudes de cambio de tarifa</h3>
        {canEdit && <button className="btn btn--accent btn--sm">{Icon.plus}<span>Nueva solicitud</span></button>}
      </div>
      <div style={{ padding: '48px 24px', textAlign: 'center', color: 'var(--ink-5)' }}>
        <svg viewBox="0 0 24 24" width="40" height="40" fill="none" stroke="currentColor" strokeWidth="1.3" style={{ marginBottom: 12, color: 'var(--ink-7)' }}>
          <path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/>
          <path d="M9 12h6M9 16h4"/>
        </svg>
        <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--ink-3)', marginBottom: 6 }}>Sin solicitudes de cambio de tarifa</div>
        <div style={{ fontSize: 12, maxWidth: 360, margin: '0 auto' }}>
          Las solicitudes de ajuste de precios aparecerán aquí una vez que se implementen. Los cambios de tarifa deben ser aprobados por Finanzas o Gerencia.
        </div>
      </div>
    </div>
  );
}

window.VistaCatalogador = VistaCatalogador;
