/* ui.jsx — kit de componentes compartido. Las pantallas usan SOLO esto para verse coherentes.
   Babel/JSX. Expone window.CR.ui y el hook window.CR.useStore. */
(function () {
  window.CR = window.CR || {};
  var React = window.React;
  var h = React.createElement;
  var useState = React.useState, useEffect = React.useEffect;

  // hook: re-render cuando el store cambia
  function useStore() {
    var s = useState(0);
    useEffect(function () { return window.CR.store.subscribe(function () { s[1](function (x) { return x + 1; }); }); }, []);
    return s[0];
  }

  function cx() { return Array.prototype.filter.call(arguments, Boolean).join(' '); }

  // Sufijo compartido para candidatos. El backend puede omitir estos campos durante el despliegue
  // coordinado: los valores ausentes o desconocidos simplemente no se muestran.
  function candAttrs(c) {
    c = c || {};
    var antiguedad = {
      'FLOTA NUEVA': 'nueva',
      '25 A 15 AÑOS': '15-25a',
      '+25 AÑOS': '+25a'
    }[c.antiguedad];
    // por prefijo y no por string exacto: la base trae variantes ('ACTIVO ROSARIO' y las que vengan).
    // Un candidato SIEMPRE es disponible (lo deriva el backend) → sólo puede ser ACTIVO* o EVENTUAL OK*.
    var e = c.estado || '';
    var estado = /^ACTIVO/.test(e) ? 'activo' : (/^EVENTUAL OK/.test(e) ? 'eventual' : null);




    var km = (c.cercaniaKm != null ? ' ·' + Math.round(c.cercaniaKm) + ' km' : '');
    var sinLoc = (c.cercaniaKm == null && c.cercaniaMotivo === 'sin_localidad') ? ' ·sin localidad' : '';
    return (antiguedad ? ' ·' + antiguedad : '') +
      (c.tarifaDiferencial ? ' ·tarifa-dif' : '') +
      (estado ? ' ·' + estado : '') + km + sinLoc;
  }

  function Button(p) {
    var variant = p.variant || 'default';
    var cls = cx('btn', variant !== 'default' && 'btn--' + variant, p.size && 'btn--' + p.size, p.className);
    // `style` pasa derecho: el boton del cierre operativo se agranda sin inventar variantes CSS
    /* `aria-label` PASA. Sin esto un boton solo se podia encontrar por su texto: los arneses
       terminaban buscando por contenido —que cambia con cada retoque de copy— o declarando
       `<button>` planos al lado de los ui.Button, con dos estilos de boton en la misma card. */



    return h('button', { className: cls, onClick: p.onClick, disabled: p.disabled,
      type: p.type || 'button', title: p.title, 'aria-describedby': p['aria-describedby'],
      'aria-label': p['aria-label'] || undefined,
      'data-novedad': p['data-novedad'] || undefined,
      style: p.style }, p.icon, p.children);
  }

  function Badge(p) {
    return h('span', { className: cx('badge', 'badge--' + (p.color || 'neutral'), p.className) },
      p.dot && h('span', { className: 'dot' }), p.children);
  }

  function Card(p) {
    /* `data-novedad` pasa, como en Button y Field: la card «Día a día» de Reportes es el destino del
       «Mostrame dónde» de la novedad de v1.0.15, y sin esto el resaltado no la encuentra. */
    return h('div', { className: cx('card', p.className), 'data-novedad': p['data-novedad'] || undefined },
      (p.title || p.actions) && h('div', { className: 'card-h' },
        h('h3', null, p.title), p.actions && h('div', null, p.actions)),
      p.children);
  }

  // count-up del valor numérico (respeta reduced-motion)
  function CountUp(props) {
    /* Se anima SOLO la parte entera; el resto viaja como sufijo y se imprime tal cual. Antes la coma
       se comia como separador de miles —logica en ingles— y "8,4" terminaba mostrandose como 84: un
       promedio de antiguedad diez veces mayor, en una tarjeta que se ve perfecta. Ninguna pantalla
       lo habia pisado porque los importes salen de `money()` y arrancan con "$", asi que no
       matcheaban el patron; el KPI de antiguedad fue el primer decimal sin prefijo. Lo encontro el
       arnes, no la lectura. */
    var m = String(props.value == null ? '' : props.value).match(/^(\d+)(.*)$/);
    var target = m ? parseInt(m[1], 10) : null;
    var suffix = m ? m[2] : '';
    var st = useState(target == null ? null : 0); var val = st[0], set = st[1];
    useEffect(function () {
      if (target == null) return;
      var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
      if (reduce) { set(target); return; }
      var t0 = null, dur = 650, raf;
      function step(ts) { if (t0 == null) t0 = ts; var k = Math.min(1, (ts - t0) / dur);
        set(Math.round(target * (1 - Math.pow(1 - k, 3)))); if (k < 1) raf = requestAnimationFrame(step); }
      raf = requestAnimationFrame(step);
      // rAF se congela en tabs de fondo / ventanas ocluidas / ahorro de batería -> el número quedaba
      // clavado en 0. El timeout garantiza el valor final aunque la animación nunca corra.
      var to = setTimeout(function () { set(target); }, dur + 150);
      return function () { if (raf) cancelAnimationFrame(raf); clearTimeout(to); };
    }, [target]);
    if (target == null) return String(props.value == null ? '' : props.value);
    return (val == null ? 0 : val) + suffix;
  }







  function StatCard(p) {
    var cuerpo = [
      h('div', { className: 'lbl', key: 'l' }, p.label),
      h('div', { className: 'val tnum', key: 'v' }, h(CountUp, { value: p.value })),
      p.sub ? h('div', { className: 'sub', key: 's' }, p.sub) : null
    ];
    if (!p.onClick) return h('div', { className: cx('stat', p.tone && 'stat--' + p.tone) }, cuerpo);
    return h('button', {
      type: 'button',
      className: cx('stat', 'stat--btn', p.tone && 'stat--' + p.tone, p.activo && 'stat--activo'),
      'aria-pressed': p.activo ? 'true' : 'false',
      title: p.titulo || ('Filtrar por ' + p.label),
      onClick: p.onClick
    }, cuerpo);
  }

  // DataTable({columns:[{key,label,render?,align?}], rows, empty, rowKey})
  function DataTable(p) {
    var cols = p.columns || [];
    if (!p.rows || p.rows.length === 0) return h(EmptyState, { title: p.empty || 'Sin datos', icon: p.emptyIcon });
    return h('div', { className: 'tablewrap' },
      h('table', { className: 'tbl' },
        h('thead', null, h('tr', null, cols.map(function (c) {
          return h('th', { key: c.key, className: c.className, style: c.align ? { textAlign: c.align } : null }, c.label);
        }))),
        h('tbody', null, p.rows.map(function (row, i) {
          return h('tr', { key: p.rowKey ? row[p.rowKey] : i }, cols.map(function (c) {
            return h('td', { key: c.key, className: c.className, style: c.align ? { textAlign: c.align } : null },
              c.render ? c.render(row, i) : row[c.key]);
          }));
        }))));
  }

  /* `data-novedad` pasa: es donde apunta el «Mostrame dónde» del popup de novedades (v1.0.13). */
  function Field(p) {
    return h('div', { className: cx('field', p.className), 'data-novedad': p['data-novedad'] || undefined },
      p.label && h('label', null, p.label),
      p.children);
  }

  /* `aria-label` y `title` se reenvian igual que en Select. No lo hacia: TODOS los `aria-label` que
     las pantallas le pasaban se descartaban en silencio, asi que un lector de pantalla no anunciaba
     ninguno de esos campos. Se noto armando la grilla de tarifas de MELI —24 campos numericos que
     sin etiqueta son 24 cajas identicas— pero el arreglo vale para toda la app. */
  function Input(p) {
    return h('input', { className: 'input', type: p.type || 'text', value: p.value == null ? '' : p.value,
      placeholder: p.placeholder, 'aria-label': p['aria-label'] || undefined, title: p.title || undefined,
      onChange: function (e) { p.onChange && p.onChange(e.target.value); }, disabled: p.disabled });
  }

  function Select(p) {
    return h('select', { className: 'select', value: p.value == null ? '' : p.value,
      'aria-label': p['aria-label'] || undefined, title: p.title || undefined,
      onChange: function (e) { p.onChange && p.onChange(e.target.value); }, disabled: p.disabled },
      (p.placeholder ? [h('option', { key: '_', value: '' }, p.placeholder)] : []).concat(
        (p.options || []).map(function (o) {
          var val = typeof o === 'object' ? o.value : o;
          var lab = typeof o === 'object' ? o.label : o;
          var dis = typeof o === 'object' ? !!o.disabled : false;
          return h('option', { key: val, value: val, disabled: dis }, lab);
        })));
  }

  function Tabs(p) {
    return h('div', { className: 'tabs' }, (p.tabs || []).map(function (t) {
      var val = typeof t === 'object' ? t.value : t;
      var lab = typeof t === 'object' ? t.label : t;
      return h('button', { key: val, className: cx('tab', p.value === val && 'active'),
        onClick: function () { p.onChange && p.onChange(val); } }, lab);
    }));
  }

  function Modal(p) {
    if (!p.open) return null;
    return h('div', { className: 'modal-bg', onClick: p.onClose },
      h('div', { className: 'modal', onClick: function (e) { e.stopPropagation(); } },
        h('div', { className: 'modal-h' }, h('h3', null, p.title),
          h('button', { className: 'btn btn--ghost btn--sm', onClick: p.onClose }, '✕')),
        h('div', { className: 'modal-b' }, p.children),
        p.footer && h('div', { className: 'modal-f' }, p.footer)));
  }

  function EmptyState(p) {
    return h('div', { className: 'empty' },
      h('h3', null, p.title || 'Nada por acá todavía'),
      p.children && h('div', { className: 'muted' }, p.children),
      p.action);
  }

  function Page(p) {
    return h('div', null,
      h('div', { className: 'page-head' }, h('h2', null, p.title), p.subtitle && h('p', null, p.subtitle)),
      p.children);
  }

  // Toolbar: fila de acciones con spacer
  function Toolbar(p) { return h('div', { className: 'toolbar' }, p.children); }

  // mini gráfico de barras horizontal {data:[{label,value,color?}], max?}
  function BarChart(p) {
    var data = p.data || [];
    var max = p.max || Math.max.apply(null, data.map(function (d) { return d.value; }).concat([1]));
    return h('div', { style: { display: 'flex', flexDirection: 'column', gap: '10px' } },
      data.map(function (d, i) {
        return h('div', { key: i },
          h('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '12px', marginBottom: '4px' } },
            h('span', { className: 'muted' }, d.label), h('b', { className: 'tnum' }, d.value)),
          h('div', { className: 'bar' }, h('span', { style: { width: (max ? (d.value / max * 100) : 0) + '%', backgroundColor: d.color || 'var(--primary)' } })));
      }));
  }

  window.CR.ui = { Button: Button, Badge: Badge, Card: Card, StatCard: StatCard, DataTable: DataTable,
    Field: Field, Input: Input, Select: Select, Tabs: Tabs, Modal: Modal, EmptyState: EmptyState,
    Page: Page, Toolbar: Toolbar, BarChart: BarChart, cx: cx };
  window.CR.useStore = useStore;
  window.CR.candAttrs = candAttrs;
})();
