// ─────────────────────────────────────────────────────
// INC-001 (Juanjo 8 oct) — «Que cuando añadamos materiales estén creados, y que lo
// único que te deje añadir sea comentario, para que tire del stock». Las líneas de
// materiales se eligen del catálogo de artículos; el texto libre va en la observación.
// INC-001 reabierta (Juanjo 26 oct) — «necesito que el artículo se cree en la pestaña de
// artículos, para que añadan todo, proveedor, referencias… En caso contrario, que se
// añada como comentario, para poder crearlo en condiciones». Fuera el alta rápida.
//
//   useMatCatalogo()          artículos activos (con proveedores), compartidos entre
//                             pantallas; `agregar(m)` mete uno recién creado.
//   <MatArticuloPicker value={material_id} onChange={(articulo|null) => …}
//       inicial={{ nombre, referencia, unidad }} onComentario={(texto) => …} />
//                             buscador por código o nombre (sin familias) +
//                             «Crear artículo en Artículos»: abre Catálogo de artículos
//                             en otra pestaña con la ficha completa (proveedores,
//                             referencias, forma de pedir…) rellena con lo escrito; al
//                             guardarla allí, el artículo queda elegido aquí.
//                             Con `onComentario`, además «añadir como comentario»: la
//                             línea va sin artículo (pendiente de crearlo).
//   matAbrirAltaArticulo(inicial, alCrear)
//                             lo mismo sin el buscador (lo usa el picker).
//
// La validación de verdad está en el servidor (src/services/materialesArticulo.js).
// ─────────────────────────────────────────────────────

let matCatalogoCache = null;
let matCatalogoPromesa = null;
const matCatalogoSubs = new Set();
const matCatalogoAvisar = () => matCatalogoSubs.forEach((fn) => fn(matCatalogoCache));
const matCatalogoCargar = (forzar) => {
  if (matCatalogoPromesa && !forzar) return matCatalogoPromesa;
  matCatalogoPromesa = API.get('/api/materiales', { activo: 'true', with_proveedores: 'true' })
    .then((rows) => { matCatalogoCache = Array.isArray(rows) ? rows : []; matCatalogoAvisar(); return matCatalogoCache; })
    .catch((e) => { matCatalogoPromesa = null; throw e; });
  return matCatalogoPromesa;
};

function useMatCatalogo() {
  const [items, setItems] = React.useState(matCatalogoCache || []);
  React.useEffect(() => {
    matCatalogoSubs.add(setItems);
    matCatalogoCargar().catch(() => {});
    return () => { matCatalogoSubs.delete(setItems); };
  }, []);
  const agregar = (m) => {
    matCatalogoCache = [...(matCatalogoCache || []).filter((x) => String(x.id) !== String(m.id)), m];
    matCatalogoAvisar();
  };
  return { items, agregar, recargar: () => matCatalogoCargar(true) };
}

// Opciones del buscador: artículos colgando de su familia; las familias (con hijos) no
// se eligen. Los sueltos (raíz sin hijos) van al final, en «Sin familia».
function matCatalogoOpciones(materiales) {
  const out = [];
  const opt = (m, group) => ({ id: m.id, mono: m.referencia || m.codigo || '', label: m.kit_componentes > 0 ? `${m.nombre} (kit)` : m.nombre, group });
  const hijosDe = new Map();
  for (const m of materiales) if (m.parent_id) {
    const k = String(m.parent_id);
    if (!hijosDe.has(k)) hijosDe.set(k, []);
    hijosDe.get(k).push(m);
  }
  const sueltos = [];
  const huerfanos = [];
  const ids = new Set(materiales.map((m) => String(m.id)));
  for (const f of materiales.filter((m) => !m.parent_id)) {
    const hijos = hijosDe.get(String(f.id));
    if (hijos && hijos.length) hijos.forEach((m) => out.push(opt(m, f.nombre)));
    else sueltos.push(f);
  }
  // Hijos cuya familia está dada de baja (no viene en la lista): siguen siendo elegibles.
  for (const [k, hijos] of hijosDe) if (!ids.has(k)) hijos.forEach((m) => huerfanos.push(m));
  [...huerfanos, ...sueltos].forEach((m) => out.push(opt(m, m.categoria_nombre || 'Sin familia')));
  return out;
}

// Categoría sugerida para el alta (misma heurística que clasificaSeccion() en bom.js).
// La usa la ficha de Catálogo de artículos al abrirse desde Materiales.
function matCategoriaSugerida({ nombre, referencia }, categorias) {
  const cod = String(referencia || '').trim().toUpperCase();
  const nom = String(nombre || '').toUpperCase();
  let familia = '';
  if (/JUNTA/.test(nom)) familia = 'junta';
  else if (/GOMA/.test(nom)) familia = 'goma';
  else if (/CANTONERA/.test(nom)) familia = 'cantonera';
  else if (cod.startsWith('V-') || /VIDRIO|CRISTAL|TEMPLADO|LAMINADO|C[ÁA]MARA/.test(nom)) familia = 'vidrio';
  else if (/^\d{3,4}[A-Z]?$/.test(cod) || /PERFIL/.test(nom)) familia = 'perfil';
  if (!familia) return '';
  const n = (s) => String(s || '').toLowerCase();
  const hit = categorias.find((c) => n(c.familia).includes(familia) || n(c.nombre).includes(familia));
  return hit ? String(hit.id) : '';
}

// ── Alta en Catálogo de artículos (otra pestaña) ──
// Se abre «#catalogo/nuevo?…» (app.jsx → CatalogoView abre la ficha de «Nuevo artículo»
// con nombre / referencia / unidad). Al guardar, esa pestaña avisa por BroadcastChannel
// con el `origen` que le pasamos y se cierra; aquí se recarga el catálogo y el artículo
// queda elegido en la línea que lo pidió. Si la pestaña no se puede abrir (bloqueador),
// se navega a Artículos en esta misma.
const MAT_CANAL = 'erp-articulos';
const matAltasPendientes = new Map(); // origen → (articulo) => void
let matCanal = null;
const matCanalAbrir = () => {
  if (matCanal || typeof BroadcastChannel === 'undefined') return;
  matCanal = new BroadcastChannel(MAT_CANAL);
  matCanal.onmessage = async (e) => {
    const d = e.data || {};
    if (d.tipo !== 'articulo_creado' || !d.articulo) return;
    const rows = await matCatalogoCargar(true).catch(() => matCatalogoCache || []);
    const cb = matAltasPendientes.get(d.origen);
    if (!cb) return;
    matAltasPendientes.delete(d.origen);
    cb((rows || []).find((m) => String(m.id) === String(d.articulo.id)) || d.articulo);
  };
};
// Aviso desde la pestaña de Artículos (catalogo.jsx).
const matAvisarArticuloCreado = (origen, articulo) => {
  if (typeof BroadcastChannel === 'undefined') return;
  const c = new BroadcastChannel(MAT_CANAL);
  c.postMessage({ tipo: 'articulo_creado', origen: origen || null, articulo });
  c.close();
};
// Sin aviso (navegador sin BroadcastChannel): al volver a esta pestaña con un alta
// abierta se recarga el catálogo para poder elegirlo a mano.
window.addEventListener('focus', () => { if (matAltasPendientes.size) matCatalogoCargar(true).catch(() => {}); });

// app.jsx deja en window si el usuario puede entrar en Catálogo de artículos.
const matPuedeCatalogo = () => window.__erpPuedeCatalogo !== false;

function matAbrirAltaArticulo(inicial = {}, alCrear) {
  matCanalAbrir();
  const origen = `alta-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
  if (alCrear) matAltasPendientes.set(origen, alCrear);
  const q = new URLSearchParams();
  if (inicial.nombre) q.set('nombre', inicial.nombre);
  if (inicial.referencia) q.set('referencia', inicial.referencia);
  if (inicial.unidad) q.set('unidad', inicial.unidad);
  q.set('origen', origen);
  const w = window.open(`${window.location.pathname}${window.location.search}#catalogo/nuevo?${q}`, '_blank');
  if (!w) { matAltasPendientes.delete(origen); window.location.hash = `catalogo/nuevo?${q}`; }
}

// ── Selector de artículo (obligatorio) con «Crear artículo en Artículos» ──
const MatArticuloPicker = ({ value, onChange, inicial, onComentario, disabled, style, placeholder = 'Busca por código o nombre…' }) => {
  const { items } = useMatCatalogo();
  const opciones = React.useMemo(() => matCatalogoOpciones(items), [items]);
  const elegir = (it) => onChange(it ? items.find((m) => String(m.id) === String(it.id)) || null : null);
  // onChange más reciente: el aviso de la otra pestaña llega cuando el usuario vuelve.
  const onChangeRef = React.useRef(onChange);
  onChangeRef.current = onChange;
  const vivo = React.useRef(true);
  React.useEffect(() => () => { vivo.current = false; }, []);
  const puede = matPuedeCatalogo();
  const datos = (texto) => {
    const base = inicial || {};
    // Lo escrito: si parece un código (sin espacios y con cifras) va a referencia.
    const esRef = texto && !/\s/.test(texto) && /\d/.test(texto);
    return { ...base, ...(texto ? (esRef ? { referencia: texto } : { nombre: texto }) : {}) };
  };
  const abrirAlta = (texto) => matAbrirAltaArticulo(datos(texto), (m) => { if (vivo.current) onChangeRef.current(m); });
  const acciones = [
    ...(puede ? [{ key: 'alta', label: (t) => `＋ Crear artículo en Artículos${t ? ` «${t}»` : ''}…`, onClick: abrirAlta }] : []),
    ...(onComentario ? [{ key: 'coment', label: (t) => `✎ No está en el catálogo: añadir como comentario${t ? ` «${t}»` : ''}`, onClick: (t) => onComentario(t), color: 'var(--warn, #b45309)' }] : []),
  ];
  return (
    <div style={{ display: 'flex', gap: 4, alignItems: 'center', ...(style || {}) }}>
      <ComboBuscador value={value || ''} items={opciones} onChange={elegir} disabled={disabled}
        placeholder={placeholder} acciones={acciones} style={{ flex: 1, minWidth: 0 }} />
      {puede && (
        <button type="button" className="btn ghost sm tip" disabled={disabled}
          data-tip="Abre Catálogo de artículos en otra pestaña con la ficha completa (proveedores, referencias, forma de pedir…). Al guardarlo queda elegido aquí."
          onClick={() => abrirAlta('')} style={{ whiteSpace: 'nowrap' }}><Icon name="plus" size={12} /> Crear en Artículos</button>
      )}
    </div>
  );
};

// ── Línea «como comentario» (INC-001 reabierta) ──
// Sustituye al buscador cuando el artículo aún no existe: se escribe qué material es y la
// línea entra sin artículo (marca naranja), sin pedirse ni tirar de stock hasta enlazarla.
const MatComentarioCampo = ({ value, onChange, onVolver, style }) => (
  <div style={{ display: 'flex', gap: 4, alignItems: 'center', ...(style || {}) }}>
    <input autoFocus value={value} onChange={(e) => onChange(e.target.value)} style={{ flex: 1, minWidth: 0, borderColor: 'var(--warn, #b45309)' }}
      placeholder="Qué material es (pendiente de crear el artículo)…"
      title="Línea como comentario: no se pide ni controla stock hasta que se cree el artículo en Catálogo de artículos y se enlace la línea" />
    <button type="button" className="btn ghost sm tip" data-tip="Volver a elegir un artículo del catálogo" onClick={onVolver} style={{ whiteSpace: 'nowrap' }}>
      <Icon name="package" size={12} /> Elegir del catálogo
    </button>
  </div>
);

// Píldora «sin artículo de catálogo» para las líneas antiguas de texto libre.
const MatSinArticulo = ({ style }) => (
  <span className="pill warn" style={{ fontSize: 10.5, whiteSpace: 'nowrap', ...(style || {}) }}
    title="Línea sin artículo del catálogo (comentario pendiente de crear el artículo, o texto libre antiguo): no controla stock y no se puede pedir hasta enlazarla. Crea el artículo en Catálogo de artículos y enlázalo (botón del enlace o «Editar»).">
    <span className="d" />sin artículo de catálogo
  </span>
);

window.useMatCatalogo = useMatCatalogo;
window.matCatalogoOpciones = matCatalogoOpciones;
window.MatArticuloPicker = MatArticuloPicker;
window.matAbrirAltaArticulo = matAbrirAltaArticulo;
window.matAvisarArticuloCreado = matAvisarArticuloCreado;
window.matCategoriaSugerida = matCategoriaSugerida;
window.MatSinArticulo = MatSinArticulo;
window.MatComentarioCampo = MatComentarioCampo;
