// ─────────────────────────────────────────────────────
// Catálogo de productos vendibles del presupuestador.
// Artículo = foto + nombre + descripción con partes VARIABLES.
// CRUD sobre /api/articulos. Expuesto como window.CatalogoProductosView.
// Las variables ([campo] en la plantilla) se eligen luego como
// desplegables/inputs al añadir una línea de presupuesto.
// ─────────────────────────────────────────────────────

const ART_FAMILIAS = [
  { value: 'cristal', label: 'Cristal' },
  { value: 'pergola_techo', label: 'Pérgola / Techo' },
];
const artFamiliaLabel = (f) => (ART_FAMILIAS.find(x => x.value === f) || {}).label || f || '—';

// Genera la descripción final sustituyendo [campo] por su valor (o un hueco).
function artRenderDescripcion(template, values, { placeholder = '____' } = {}) {
  if (!template) return '';
  return template.replace(/\[([a-zA-Z0-9_]+)\]/g, (m, campo) => {
    const v = values && values[campo];
    return (v != null && String(v).trim() !== '') ? String(v) : placeholder;
  });
}

// Editor de una variable (campo / label / tipo / opciones).
const ArtVariableRow = ({ row, onChange, onRemove }) => (
  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.2fr 0.9fr 1.6fr 26px', gap: 6, alignItems: 'center' }}>
    <input placeholder="campo" value={row.campo}
      onChange={e => onChange({ ...row, campo: e.target.value.replace(/[^a-zA-Z0-9_]/g, '').toLowerCase() })} />
    <input placeholder="Etiqueta" value={row.label} onChange={e => onChange({ ...row, label: e.target.value })} />
    <select value={row.tipo} onChange={e => onChange({ ...row, tipo: e.target.value })}>
      <option value="select">Lista</option>
      <option value="text">Texto</option>
    </select>
    <input placeholder={row.tipo === 'select' ? 'opción1, opción2…' : '(texto libre)'}
      value={row.opcionesText} disabled={row.tipo !== 'select'}
      onChange={e => onChange({ ...row, opcionesText: e.target.value })} />
    <button type="button" className="btn ghost" style={{ color: 'var(--err)', padding: '2px 6px' }} onClick={onRemove}>×</button>
  </div>
);

const ArtModal = ({ articulo, onClose, onSaved, onToast }) => {
  const isEdit = !!articulo;
  const [form, setForm] = React.useState({
    nombre: articulo?.nombre || '',
    familia: articulo?.familia || '',
    descripcion_template: articulo?.descripcion_template || '',
    imagen_url: articulo?.imagen_url || '',
  });
  const [vars, setVars] = React.useState(
    (articulo?.variables || []).map(v => ({
      campo: v.campo || '', label: v.label || '', tipo: v.tipo === 'text' ? 'text' : 'select',
      opcionesText: (v.opciones || []).join(', '),
    }))
  );
  const [file, setFile] = React.useState(null);
  const [preview, setPreview] = React.useState(articulo?.imagen_url || '');
  const [saving, setSaving] = React.useState(false);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const addVar = () => setVars(vs => [...vs, { campo: '', label: '', tipo: 'select', opcionesText: '' }]);
  const updVar = (i, v) => setVars(vs => vs.map((r, idx) => idx === i ? v : r));
  const rmVar = (i) => setVars(vs => vs.filter((_, idx) => idx !== i));

  // Inserta [campo] al final de la plantilla para variables aún no referenciadas.
  const insertToken = (campo) => set('descripcion_template', `${form.descripcion_template || ''} [${campo}]`.trim());

  const onPickFile = (f) => {
    setFile(f);
    if (f) setPreview(URL.createObjectURL(f));
  };

  const buildVariables = () => vars
    .filter(v => v.campo.trim())
    .map(v => ({
      campo: v.campo.trim(), label: v.label.trim() || v.campo.trim(), tipo: v.tipo,
      opciones: v.tipo === 'select'
        ? v.opcionesText.split(',').map(s => s.trim()).filter(Boolean) : [],
    }));

  // Valores de muestra para la previsualización (primera opción / etiqueta).
  const sampleValues = {};
  buildVariables().forEach(v => { sampleValues[v.campo] = v.tipo === 'select' ? (v.opciones[0] || `«${v.label}»`) : `«${v.label}»`; });

  const submit = async (e) => {
    e.preventDefault();
    if (!form.nombre.trim()) return onToast('El nombre es obligatorio', true);
    setSaving(true);
    const payload = {
      nombre: form.nombre.trim(),
      familia: form.familia || null,
      descripcion_template: form.descripcion_template || null,
      variables: buildVariables(),
    };
    try {
      const saved = isEdit
        ? await API.put(`/api/articulos/${articulo.id}`, payload)
        : await API.post('/api/articulos', payload);
      if (file) {
        const fd = new FormData();
        fd.append('imagen', file);
        await API.upload(`/api/articulos/${saved.id}/imagen`, fd);
      }
      onToast(isEdit ? 'Artículo actualizado ✓' : 'Artículo creado ✓');
      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(720)}>
        <SysModalHeader title={isEdit ? 'Editar artículo' : 'Nuevo artículo'} onClose={onClose} />
        <form onSubmit={submit} autoComplete="off">
          <div className="fields-grid" style={{ padding: '16px 18px' }}>
            <div className="field" style={{ gridRow: 'span 2', display: 'flex', flexDirection: 'column', gap: 6 }}>
              <label>Foto</label>
              <div style={{ width: '100%', aspectRatio: '1', border: '1px dashed var(--line)', borderRadius: 8,
                display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden', background: 'var(--surface-2,#fafafa)' }}>
                {preview
                  ? <img src={preview} alt="" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} />
                  : <Icon name="package" size={28} />}
              </div>
              <label className="btn ghost" style={{ cursor: 'pointer', textAlign: 'center', fontSize: 12 }}>
                {preview ? 'Cambiar foto' : 'Subir foto'}
                <input type="file" accept="image/*" style={{ display: 'none' }}
                  onChange={e => onPickFile(e.target.files[0])} />
              </label>
            </div>
            <div className="field">
              <label>Nombre *</label>
              <input value={form.nombre} onChange={e => set('nombre', e.target.value)} required autoFocus placeholder="Cortina de cristal…" />
            </div>
            <div className="field">
              <label>Familia</label>
              <select value={form.familia} onChange={e => set('familia', e.target.value)}>
                <option value="">— Sin familia —</option>
                {ART_FAMILIAS.map(f => <option key={f.value} value={f.value}>{f.label}</option>)}
              </select>
            </div>

            <div className="field full">
              <label>Descripción (usa [campo] para las partes variables)</label>
              <textarea rows="4" value={form.descripcion_template} onChange={e => set('descripcion_template', e.target.value)}
                placeholder="Ud Cortina de Cristal… Color: [color]. Apertura: [apertura]." />
            </div>

            <div className="field full">
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 }}>
                <span style={{ fontSize: 11, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '.05em' }}>Variables</span>
                <button type="button" className="btn ghost" style={{ fontSize: 12 }} onClick={addVar}>+ Añadir variable</button>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                {vars.length === 0 && <div className="muted" style={{ fontSize: 12 }}>Sin variables. Añade las opciones que cambian la descripción (Color, Apertura, Nº postes…).</div>}
                {vars.map((v, i) => (
                  <div key={i} style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                    <ArtVariableRow row={v} onChange={val => updVar(i, val)} onRemove={() => rmVar(i)} />
                    {v.campo && !(form.descripcion_template || '').includes(`[${v.campo}]`) && (
                      <button type="button" className="btn ghost" style={{ fontSize: 10, alignSelf: 'flex-start', padding: '0 4px', color: 'var(--accent,#06c)' }}
                        onClick={() => insertToken(v.campo)}>insertar [{v.campo}] en la descripción</button>
                    )}
                  </div>
                ))}
              </div>
            </div>

            <div className="field full">
              <label>Vista previa</label>
              <div style={{ fontSize: 12.5, lineHeight: 1.5, background: 'var(--surface-2,#fafafa)', border: '1px solid var(--line)', borderRadius: 6, padding: '8px 10px' }}>
                {artRenderDescripcion(form.descripcion_template, sampleValues) || <span className="muted">La descripción aparecerá aquí…</span>}
              </div>
            </div>
          </div>
          <SysModalFooter onClose={onClose} saving={saving} label={isEdit ? 'Guardar' : 'Crear artículo'} />
        </form>
      </div>
    </div>
  );
};

const CatalogoProductosView = ({ onToast }) => {
  const [articulos, setArticulos] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [search, setSearch] = React.useState('');
  const [familiaF, setFamiliaF] = React.useState('');
  const [modal, setModal] = React.useState(null); // null | 'new' | articulo
  const timer = React.useRef(null);

  const load = async (q) => {
    setLoading(true);
    try {
      const params = { incluir_inactivos: 'true' };
      if (q) params.search = q;
      const rows = await API.get('/api/articulos', params);
      setArticulos(Array.isArray(rows) ? rows : []);
    } catch (e) {
      onToast(e.message || 'Error', true);
    } finally {
      setLoading(false);
    }
  };
  React.useEffect(() => { load(); }, []);

  const onSearch = (v) => {
    setSearch(v);
    clearTimeout(timer.current);
    timer.current = setTimeout(() => load(v), 300);
  };

  const del = async (art) => {
    if (!confirm(`¿Eliminar el artículo "${art.nombre}"?`)) return;
    try { await API.del(`/api/articulos/${art.id}`); onToast('Eliminado'); load(search); }
    catch (e) { onToast(e.message || 'Error al eliminar', true); }
  };

  const visible = familiaF ? articulos.filter(a => a.familia === familiaF) : articulos;

  return (
    <div style={{ padding: '16px 24px 24px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
        <h2 style={{ margin: 0, fontSize: 18 }}>Catálogo de productos</h2>
        <span className="muted" style={{ fontSize: 12 }}>{visible.length} artículos</span>
        <div style={{ flex: 1 }} />
        <div className="tb-search">
          <Icon name="search" />
          <input placeholder="Buscar por nombre…" value={search} onChange={e => onSearch(e.target.value)} />
        </div>
        <select className="cfg-select" value={familiaF} onChange={e => setFamiliaF(e.target.value)} style={{ width: 160 }}>
          <option value="">Todas las familias</option>
          {ART_FAMILIAS.map(f => <option key={f.value} value={f.value}>{f.label}</option>)}
        </select>
        <button className="btn primary" onClick={() => setModal('new')}><Icon name="plus" /> Nuevo artículo</button>
      </div>

      {loading && <div className="muted" style={{ padding: 24, textAlign: 'center' }}>Cargando…</div>}
      {!loading && (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: 12 }}>
          {visible.map(a => (
            <div key={a.id} className="panel" style={{ display: 'flex', flexDirection: 'column', overflow: 'hidden', cursor: 'pointer' }}
              onClick={e => { if (!e.target.closest('button')) setModal(a); }}>
              <div style={{ height: 130, background: 'var(--surface-2,#fafafa)', display: 'flex', alignItems: 'center', justifyContent: 'center', borderBottom: '1px solid var(--line)' }}>
                {a.imagen_url
                  ? <img src={a.imagen_url} alt="" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} />
                  : <Icon name="package" size={28} />}
              </div>
              <div style={{ padding: '10px 12px', display: 'flex', flexDirection: 'column', gap: 4, flex: 1 }}>
                <strong style={{ fontSize: 13 }}>{a.nombre}</strong>
                <span className="muted" style={{ fontSize: 11 }}>{artFamiliaLabel(a.familia)} · {(a.variables || []).length} variables</span>
                <div style={{ flex: 1 }} />
                <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
                  <button className="btn ghost" style={{ fontSize: 12 }} onClick={() => setModal(a)}>Editar</button>
                  <button className="btn ghost" style={{ fontSize: 12, color: 'var(--err)' }} onClick={() => del(a)}>Eliminar</button>
                </div>
              </div>
            </div>
          ))}
          {!visible.length && <div className="muted" style={{ padding: 24, gridColumn: '1/-1', textAlign: 'center' }}>Sin artículos.</div>}
        </div>
      )}

      {modal && (
        <ArtModal
          articulo={modal === 'new' ? null : modal}
          onClose={() => setModal(null)}
          onSaved={() => load(search)}
          onToast={onToast}
        />
      )}
    </div>
  );
};

window.CatalogoProductosView = CatalogoProductosView;
// Reutilizados por el presupuestador (alta inline + helpers).
window.ArtModal = ArtModal;
window.artRenderDescripcion = artRenderDescripcion;
window.artFamiliaLabel = artFamiliaLabel;
window.ART_FAMILIAS = ART_FAMILIAS;
