// ─────────────────────────────────────────────────────
// GUT-274 — Almacén: stock por artículo del catálogo y su histórico.
// Sobre /api/stock. El stock es la suma de los movimientos:
//   - Entradas: líneas de OC «para stock» al recibirlas (automático) y manuales.
//   - Salidas: líneas de materiales marcadas «De stock» (automático) y manuales.
//   - Ajustes: recuento manual (se apunta la diferencia).
// Stock negativo permitido, resaltado en rojo.
// Expuesto como window.AlmacenView.
// ─────────────────────────────────────────────────────

const ALM_TIPOS = {
  entrada: { label: 'Entrada', cls: 'ok' },
  salida:  { label: 'Salida',  cls: 'warn' },
  ajuste:  { label: 'Ajuste',  cls: 'info' },
};

const almNum = (n) => {
  const v = Number(n) || 0;
  return v.toLocaleString('es-ES', { maximumFractionDigits: 4 });
};
const almSigned = (n) => (Number(n) > 0 ? '+' : '') + almNum(n);
const almFecha = (f) => {
  if (!f) return '—';
  const d = new Date(f);
  return d.toLocaleDateString('es-ES', { day: '2-digit', month: '2-digit', year: 'numeric' })
    + ' ' + d.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' });
};

const AlmStock = ({ value, unidad, big }) => {
  const v = Number(value) || 0;
  return (
    <span style={{ fontWeight: 650, fontSize: big ? 22 : 13, color: v < 0 ? 'var(--err)' : v === 0 ? 'var(--ink-3)' : 'var(--ink)' }}
      title={v < 0 ? 'Stock negativo: ha salido más de lo que consta que entró' : undefined}>
      {almNum(v)}{unidad ? <span className="muted" style={{ fontWeight: 400, fontSize: big ? 13 : 11.5 }}> {unidad}</span> : null}
    </span>
  );
};

// Origen del movimiento con enlace a la OC / expediente cuando lo hay.
const AlmOrigen = ({ m }) => {
  const abrirOc = () => window.dispatchEvent(new CustomEvent('erp:open-orden', { detail: { id: m.compra_id } }));
  const abrirExp = () => window.dispatchEvent(new CustomEvent('erp:open-expediente', { detail: { pedidoId: m.exp_pedido_id } }));
  const link = { background: 'none', border: 0, padding: 0, color: 'var(--accent-ink, var(--info))', cursor: 'pointer', textDecoration: 'underline', font: 'inherit' };
  const exp = m.exp_pedido_id && (
    <span>
      <button type="button" style={link} onClick={abrirExp} title="Abrir expediente">Exp. {m.numero_expediente || m.exp_pedido_id}</button>
      {/* INC-018: el cliente lleva a su hoja (Materiales del expediente, con medidas). */}
      {m.nombre_cliente && <> · <ClienteLink nombre={m.nombre_cliente} pedidoId={m.exp_pedido_id} /></>}
    </span>
  );
  const proyecto = !m.exp_pedido_id && m.proyecto_numero && (
    <span>Proyecto {m.proyecto_numero}{m.proyecto_nombre && <> · <ClienteLink nombre={m.proyecto_nombre} proyectoId={m.exp_proyecto_id} /></>}</span>
  );
  if (m.origen === 'oc') {
    return (
      <span>
        {m.compra_id
          ? <button type="button" style={link} onClick={abrirOc} title="Abrir la orden a proveedor">OC {m.oc_numero || m.compra_id}</button>
          : 'OC'}
        {m.oc_proveedor && <span className="muted"> · {m.oc_proveedor}</span>}
      </span>
    );
  }
  if (m.origen === 'material') {
    return (
      <span>
        {exp || proyecto || <span className="muted">Línea de materiales</span>}
        {m.linea_nombre && <div className="muted" style={{ fontSize: 11 }}>{m.linea_nombre}</div>}
      </span>
    );
  }
  return <span className="muted">Manual</span>;
};

// Alta de movimiento manual.
const AlmMovModal = ({ articulo, tipoInicial, onClose, onSaved, onToast }) => {
  const [tipo, setTipo] = React.useState(tipoInicial || 'entrada');
  const [cantidad, setCantidad] = React.useState('');
  const [nota, setNota] = React.useState('');
  const [saving, setSaving] = React.useState(false);
  const unidad = articulo.unidad_medida || 'ud';

  const submit = async (e) => {
    e.preventDefault();
    setSaving(true);
    try {
      const body = { tipo, nota };
      if (tipo === 'ajuste') body.stock_real = cantidad; else body.cantidad = cantidad;
      await API.post(`/api/stock/${articulo.id}/movimientos`, body);
      onToast(tipo === 'entrada' ? 'Entrada registrada ✓' : tipo === 'salida' ? 'Salida registrada ✓' : 'Stock ajustado ✓');
      onSaved();
      onClose();
    } catch (err) {
      onToast(err.message || 'Error al guardar', true);
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="modal-bg open" {...sysOverlay(() => onClose())}>
      <div className="modal" {...sysModal(460)}>
        <SysModalHeader title={`Movimiento · ${articulo.nombre}`} onClose={onClose} />
        <form onSubmit={submit} autoComplete="off">
          <div className="fields-grid" style={{ padding: '16px 18px' }}>
            <div className="field full">
              <label>Tipo</label>
              <div className="seg">
                {Object.entries(ALM_TIPOS).map(([k, t]) => (
                  <button type="button" key={k} className={tipo === k ? 'on' : ''} onClick={() => setTipo(k)}>{t.label}</button>
                ))}
              </div>
            </div>
            <div className="field full">
              <label>{tipo === 'ajuste' ? `Stock real contado (${unidad})` : `Cantidad (${unidad})`}</label>
              <input type="number" step="any" min={tipo === 'ajuste' ? undefined : '0'} required autoFocus
                value={cantidad} onChange={e => setCantidad(e.target.value)} />
              <div className="muted" style={{ fontSize: 11.5, marginTop: 4 }}>
                Stock actual: {almNum(articulo.stock)} {unidad}.
                {tipo === 'ajuste' && cantidad !== '' && ` Se apunta un ajuste de ${almSigned((Number(cantidad) || 0) - (Number(articulo.stock) || 0))}.`}
                {tipo === 'salida' && cantidad !== '' && (Number(articulo.stock) || 0) - (Number(cantidad) || 0) < 0 && ' El stock quedará en negativo.'}
              </div>
            </div>
            <div className="field full">
              <label>Nota</label>
              <input value={nota} onChange={e => setNota(e.target.value)} placeholder="Recuento, rotura, devolución, material sobrante…" />
            </div>
          </div>
          <SysModalFooter onClose={onClose} saving={saving} label="Guardar" />
        </form>
      </div>
    </div>
  );
};

// Panel lateral con el histórico de un artículo.
// GUT-272: con `expediente` (filtro de la lista) se ven solo los movimientos de ese
// expediente / proyecto, con opción de ver todos.
const AlmDrawer = ({ materialId, expediente, onClose, onChanged, onToast }) => {
  const [data, setData] = React.useState(null);
  const [modal, setModal] = React.useState(null); // null | 'entrada' | 'salida' | 'ajuste'
  const [todos, setTodos] = React.useState(false);
  const filtroExp = !todos && expediente ? expediente : '';

  const load = async () => {
    try { setData(await API.get(`/api/stock/${materialId}`, filtroExp ? { expediente: filtroExp } : {})); }
    catch (e) { onToast(e.message || 'Error', true); }
  };
  React.useEffect(() => { setTodos(false); }, [materialId]);
  React.useEffect(() => { setData(null); if (materialId) load(); }, [materialId, filtroExp]);

  const borrar = async (m) => {
    if (!confirm(`¿Borrar este movimiento manual (${almSigned(m.cantidad)})?`)) return;
    try { await API.del(`/api/stock/movimientos/${m.id}`); onToast('Movimiento borrado'); load(); onChanged(); }
    catch (e) { onToast(e.message || 'Error al borrar', true); }
  };

  const open = !!materialId;
  const movs = (data && data.movimientos) || [];
  return (
    <>
      <div className={`drawer-bg ${open ? 'open' : ''}`} onClick={onClose} />
      <div className={`drawer ${open ? 'open' : ''}`} style={{ width: 'min(860px, 100%)' }}>
        <div className="dr-head">
          {data && data.referencia && <span className="id mono">{data.referencia}</span>}
          <h2>{data ? data.nombre : 'Cargando…'}</h2>
          <div className="actions">
            <button className="icon-btn" onClick={onClose}><Icon name="x" /></button>
          </div>
        </div>
        <div className="dr-body">
          {!data && <div style={{ padding: 24, textAlign: 'center', color: 'var(--ink-3)' }}>Cargando…</div>}
          {data && (
            <div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap', marginBottom: 14 }}>
                <div>
                  <div className="muted" style={{ fontSize: 11, textTransform: 'uppercase', letterSpacing: '.05em' }}>Stock libre</div>
                  <AlmStock value={data.stock} unidad={data.unidad_medida || 'ud'} big />
                </div>
                {/* INC-012: lo recibido para expedientes no es stock libre: queda apartado. */}
                {Number(data.reservado) > 0 && (
                  <div title="Recibido o apartado para expedientes y aún no enviado: no cuenta como stock libre">
                    <div className="muted" style={{ fontSize: 11, textTransform: 'uppercase', letterSpacing: '.05em' }}>Reservado</div>
                    <span style={{ fontWeight: 650, fontSize: 22, color: 'var(--warn, #b45309)' }}>{almNum(data.reservado)}</span>
                    <span className="muted" style={{ fontSize: 13 }}> {data.unidad_medida || 'ud'}</span>
                  </div>
                )}
                <div className="muted" style={{ fontSize: 12 }}>{data.categoria_nombre || data.familia || ''}</div>
                <div style={{ flex: 1 }} />
                <button className="btn primary sm" onClick={() => setModal('entrada')}><Icon name="plus" size={12} /> Entrada</button>
                <button className="btn ghost sm" onClick={() => setModal('salida')}>Salida</button>
                <button className="btn ghost sm" onClick={() => setModal('ajuste')} title="Recuento: pon el stock real y se apunta la diferencia">Ajuste</button>
              </div>

              {(data.reservas || []).length > 0 && (
                <>
                  <div className="section-title">Reservado para expedientes</div>
                  <div className="tbl-wrap" style={{ marginBottom: 16 }}>
                    <div className="tbl-scroll">
                      <table className="tbl">
                        <thead>
                          <tr>
                            <th>Expediente</th>
                            <th>Línea de materiales</th>
                            <th style={{ width: 100, textAlign: 'right' }}>Reservado</th>
                          </tr>
                        </thead>
                        <tbody>
                          {data.reservas.map((r, i) => (
                            <tr key={`${r.bom_linea_id || 'p'}-${r.exp_pedido_id || ''}-${i}`}>
                              <td><AlmOrigen m={{ ...r, origen: 'material', linea_nombre: null }} /></td>
                              <td className="muted" style={{ fontSize: 12 }}>
                                {r.linea_nombre || (r.bom_linea_id ? 'Línea' : 'Sin línea de materiales')}
                                {r.linea_dimensiones ? ` · ${r.linea_dimensiones}` : ''}
                                {r.linea_cantidad != null ? ` · necesita ${almNum(r.linea_cantidad)}` : ''}
                              </td>
                              <td style={{ textAlign: 'right', fontWeight: 600 }}>{almNum(r.uds)}</td>
                            </tr>
                          ))}
                        </tbody>
                      </table>
                    </div>
                  </div>
                </>
              )}

              <div className="section-title">
                Movimientos
                {expediente && (
                  <span style={{ fontWeight: 400, textTransform: 'none', letterSpacing: 0, marginLeft: 8, fontSize: 12 }}>
                    {filtroExp
                      ? <>solo de «{expediente}» · <a style={{ cursor: 'pointer' }} onClick={() => setTodos(true)}>Ver todos</a></>
                      : <>todos · <a style={{ cursor: 'pointer' }} onClick={() => setTodos(false)}>Solo de «{expediente}»</a></>}
                  </span>
                )}
              </div>
              {!movs.length && (
                <div className="muted" style={{ fontSize: 12, padding: '12px 0' }}>
                  {filtroExp ? `Sin movimientos de «${filtroExp}». ` : ''}Sin movimientos. Entra al recibir una OC «para stock» o con una entrada manual; sale al marcar «De stock» una línea de materiales con este artículo.
                </div>
              )}
              {movs.length > 0 && (
                <div className="tbl-wrap">
                  <div className="tbl-scroll">
                    <table className="tbl">
                      <thead>
                        <tr>
                          <th style={{ width: 120 }}>Fecha</th>
                          <th style={{ width: 80 }}>Tipo</th>
                          <th style={{ width: 80, textAlign: 'right' }}>Cantidad</th>
                          <th style={{ width: 80, textAlign: 'right' }}>Saldo</th>
                          <th>Origen</th>
                          <th style={{ width: 90 }}>Usuario</th>
                          <th>Nota</th>
                          <th style={{ width: 32 }}></th>
                        </tr>
                      </thead>
                      <tbody>
                        {movs.map(m => {
                          const t = ALM_TIPOS[m.tipo] || { label: m.tipo, cls: '' };
                          return (
                            <tr key={m.id}>
                              <td className="muted" style={{ whiteSpace: 'nowrap' }}>{almFecha(m.fecha)}</td>
                              <td><span className={`pill ${t.cls}`}><span className="d" />{t.label}</span></td>
                              <td style={{ textAlign: 'right', fontWeight: 600, color: m.cantidad < 0 ? 'var(--err)' : 'var(--ok)' }}>{almSigned(m.cantidad)}</td>
                              <td style={{ textAlign: 'right' }}><AlmStock value={m.saldo} /></td>
                              <td><AlmOrigen m={m} /></td>
                              <td className="muted">{m.usuario || (m.origen === 'manual' ? '—' : 'Automático')}</td>
                              <td className="muted" style={{ fontSize: 12 }}>{m.nota || ''}</td>
                              <td>
                                {m.origen === 'manual' && (
                                  <button className="icon-btn" style={{ color: 'var(--err)' }} title="Borrar movimiento manual" onClick={() => borrar(m)}><Icon name="trash" size={12} /></button>
                                )}
                              </td>
                            </tr>
                          );
                        })}
                      </tbody>
                    </table>
                  </div>
                </div>
              )}
            </div>
          )}
        </div>
      </div>
      {modal && data && (
        <AlmMovModal articulo={data} tipoInicial={modal} onClose={() => setModal(null)}
          onSaved={() => { load(); onChanged(); }} onToast={onToast} />
      )}
    </>
  );
};

const AlmacenView = ({ onToast }) => {
  const [articulos, setArticulos] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [search, setSearch] = React.useState('');
  const [expediente, setExpediente] = React.useState(''); // GUT-272: nº de expediente, cliente o proyecto
  const [soloMov, setSoloMov] = React.useState(() => { try { return localStorage.getItem('alm_solo_mov') === '1'; } catch { return false; } });
  const [abierto, setAbierto] = React.useState(null); // material_id del panel
  const [modal, setModal] = React.useState(null);     // { articulo, tipo }
  const [pestana, setPestana] = React.useState(() => { try { return localStorage.getItem('alm_pestana') === 'corte' ? 'corte' : 'stock'; } catch { return 'stock'; } });
  const onPestana = (v) => { setPestana(v); try { localStorage.setItem('alm_pestana', v); } catch {} };
  const searchTimer = React.useRef(null);

  const load = async (q = search, solo = soloMov, exp = expediente) => {
    setLoading(true);
    try {
      const params = {};
      if (q) params.search = q;
      if (solo) params.con_movimientos = 'true';
      if (exp.trim()) params.expediente = exp.trim();
      setArticulos(await API.get('/api/stock', params));
    } catch (e) {
      onToast(e.message || 'Error', true);
    } finally {
      setLoading(false);
    }
  };
  React.useEffect(() => { load(); }, []);

  const onSearch = (v) => {
    setSearch(v);
    clearTimeout(searchTimer.current);
    searchTimer.current = setTimeout(() => load(v), 300);
  };
  const onExpediente = (v) => {
    setExpediente(v);
    clearTimeout(searchTimer.current);
    searchTimer.current = setTimeout(() => load(search, soloMov, v), 300);
  };
  const onSoloMov = (v) => {
    setSoloMov(v);
    try { localStorage.setItem('alm_solo_mov', v ? '1' : '0'); } catch {}
    load(search, v);
  };

  const negativos = articulos.filter(a => a.stock < 0).length;

  // INC-008: pestaña «Órdenes de corte» (las que salen al recepcionar material por barra).
  const pestanas = (
    <div className="seg">
      <button className={pestana === 'stock' ? 'on' : ''} onClick={() => onPestana('stock')}>Stock</button>
      <button className={pestana === 'corte' ? 'on' : ''} onClick={() => onPestana('corte')}>Órdenes de corte</button>
    </div>
  );
  if (pestana === 'corte') {
    return (
      <div style={{ padding: '16px 24px 24px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14, flexWrap: 'wrap' }}>
          <h2 style={{ margin: 0, fontSize: 18 }}>Almacén</h2>
          {pestanas}
        </div>
        <OrdenesCorteView onToast={onToast} />
      </div>
    );
  }

  return (
    <div style={{ padding: '16px 24px 24px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14, flexWrap: 'wrap' }}>
        <h2 style={{ margin: 0, fontSize: 18 }}>Almacén</h2>
        {pestanas}
        <span className="muted" style={{ fontSize: 12 }}>{articulos.length} artículos</span>
        {negativos > 0 && <span className="pill err"><span className="d" />{negativos} en negativo</span>}
        <HelpTip label="stock del almacén" text="El stock de cada artículo es la suma de sus movimientos. Entra al recibir una línea de OC «para stock» (las OCs sin expediente van a stock solas) o con una entrada manual. Sale al marcar «De stock» una línea de materiales de un expediente o proyecto con este artículo del catálogo; si se desmarca o se borra la línea, vuelve. El stock negativo se permite y sale en rojo." />
        <div style={{ flex: 1 }} />
        <label className="muted" style={{ fontSize: 12, display: 'inline-flex', alignItems: 'center', gap: 5, cursor: 'pointer' }}>
          <input type="checkbox" checked={soloMov} onChange={e => onSoloMov(e.target.checked)} /> Solo con movimientos
        </label>
        <div className="tb-search">
          <Icon name="search" />
          <input placeholder="Buscar por referencia o descripción…" value={search} onChange={e => onSearch(e.target.value)} />
        </div>
        <div className="tb-search" title="Solo artículos con movimientos de este expediente (nº, cliente o proyecto)">
          <Icon name="search" />
          <input placeholder="Expediente o cliente…" value={expediente} onChange={e => onExpediente(e.target.value)} style={{ width: 150 }} />
        </div>
      </div>

      <div className="tbl-wrap">
        <div className="tbl-scroll">
          <table className="tbl">
            <thead>
              <tr>
                <th style={{ width: 120 }}>Referencia</th>
                <th>Descripción</th>
                <th style={{ width: 140 }}>Categoría</th>
                <th style={{ width: 110, textAlign: 'right' }}>Stock libre</th>
                <th style={{ width: 100, textAlign: 'right' }} title="Recibido o apartado para expedientes y aún no enviado (no es stock libre)">Reservado</th>
                <th style={{ width: 130 }}>Último movimiento</th>
                <th style={{ width: 170 }}></th>
              </tr>
            </thead>
            <tbody>
              {loading && <tr><td colSpan="7" style={{ padding: '24px 16px', textAlign: 'center', color: 'var(--ink-3)' }}>Cargando…</td></tr>}
              {!loading && articulos.map(a => (
                <tr key={a.id} onClick={e => { if (!e.target.closest('button')) setAbierto(a.id); }} style={{ cursor: 'pointer' }}>
                  <td><code style={{ fontSize: 12 }}>{a.referencia || a.codigo || '—'}</code></td>
                  <td className="strong">{a.nombre}{!a.activo && <span className="muted" style={{ fontWeight: 400 }}> (inactivo)</span>}</td>
                  <td className="muted">{a.categoria_nombre || a.familia || '—'}</td>
                  <td style={{ textAlign: 'right' }}><AlmStock value={a.stock} unidad={a.unidad_medida || 'ud'} /></td>
                  <td style={{ textAlign: 'right' }}>{Number(a.reservado) > 0 ? <span style={{ fontWeight: 600, color: 'var(--warn, #b45309)' }}>{almNum(a.reservado)}</span> : <span className="muted">—</span>}</td>
                  <td className="muted" style={{ fontSize: 12 }}>{a.ultimo_movimiento ? almFecha(a.ultimo_movimiento) : '—'}</td>
                  <td style={{ textAlign: 'right', whiteSpace: 'nowrap' }}>
                    <button className="btn ghost sm" onClick={() => setModal({ articulo: a, tipo: 'entrada' })}>+ Entrada</button>
                    <button className="btn ghost sm" style={{ marginLeft: 4 }} onClick={() => setModal({ articulo: a, tipo: 'salida' })}>− Salida</button>
                  </td>
                </tr>
              ))}
              {!loading && !articulos.length && (
                <tr><td colSpan="7" style={{ padding: '24px 16px', textAlign: 'center', color: 'var(--ink-3)' }}>{expediente.trim() ? `Ningún artículo con movimientos de «${expediente.trim()}».` : 'Sin artículos.'}</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      <AlmDrawer materialId={abierto} expediente={expediente.trim()} onClose={() => setAbierto(null)} onChanged={() => load()} onToast={onToast} />
      {modal && (
        <AlmMovModal articulo={modal.articulo} tipoInicial={modal.tipo} onClose={() => setModal(null)}
          onSaved={() => load()} onToast={onToast} />
      )}
    </div>
  );
};

window.AlmacenView = AlmacenView;
