





















(function () {
  var React = window.React;
  var h = React.createElement;
  var useState = React.useState;
  var useEffect = React.useEffect;

  /* Verde → rojo, en el orden en que el servidor manda los tramos. El color es lo ÚNICO que la
     pantalla decide sobre los tramos, y a propósito: es presentación, no definición. */
  var COLORES = ['#1a9d5a', '#7fbf3f', '#e8b62c', '#e8802c', '#d5372f'];
  var COLOR_HUECO = '#9aa4b2';

  var num = function (n) { return (n == null ? '—' : String(n).replace('.', ',')); };

  /* ---- DONA ---------------------------------------------------------------------------------
     SVG plano, sin librería. Cada tramo es un arco dibujado con stroke-dasharray sobre el mismo
     círculo; el offset acumula lo ya dibujado.
     `role="img"` + `aria-label` con el resumen completo NO es decoración: un lector de pantalla no
     puede leer arcos, y sin esa etiqueta el KPI entero es invisible para quien lo use. */
  function Dona(props) {
    var partes = (props.partes || []).filter(function (p) { return p.valor > 0; });
    var total = partes.reduce(function (a, p) { return a + p.valor; }, 0);
    var R = 54, C = 2 * Math.PI * R;
    var acumulado = 0;

    if (!total) {
      return h('div', { className: 'muted', style: { padding: '24px 0', textAlign: 'center' } },
        'Sin rutas en el período elegido.');
    }
    var resumen = partes.map(function (p) {
      return p.etiqueta + ': ' + p.valor + ' rutas (' + num(Math.round(p.valor * 1000 / total) / 10) + '%)';
    }).join('; ');

    return h('div', { className: 'dona-wrap', style: { display: 'flex', alignItems: 'center', gap: 20, flexWrap: 'wrap' } },
      h('svg', { width: 150, height: 150, viewBox: '0 0 150 150', role: 'img',
        'aria-label': 'Rutas por antigüedad de la unidad. ' + resumen },
        h('g', { transform: 'rotate(-90 75 75)' },
          partes.map(function (p, i) {
            var frac = p.valor / total;
            var el = h('circle', {
              key: p.clave, cx: 75, cy: 75, r: R, fill: 'none',
              stroke: p.color, strokeWidth: 26,
              strokeDasharray: (C * frac).toFixed(2) + ' ' + (C * (1 - frac)).toFixed(2),
              strokeDashoffset: (-C * acumulado).toFixed(2)
            });
            acumulado += frac;
            return el;
          })),
        h('text', { x: 75, y: 71, textAnchor: 'middle', fontSize: 22, fontWeight: 700, fill: 'var(--text)' }, String(total)),
        h('text', { x: 75, y: 90, textAnchor: 'middle', fontSize: 11, fill: 'var(--muted)' }, 'rutas')),
      h('ul', { className: 'dona-leyenda', style: { listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 6 } },
        partes.map(function (p) {
          return h('li', { key: p.clave, style: { display: 'flex', alignItems: 'center', gap: 8, fontSize: 13 } },
            h('span', { style: { width: 12, height: 12, borderRadius: 3, background: p.color, flex: '0 0 auto' } }),
            h('span', null, p.etiqueta),
            h('b', { className: 'tnum' }, String(p.valor)),
            h('span', { className: 'muted' }, '(' + num(Math.round(p.valor * 1000 / total) / 10) + '%)'));
        })));
  }

  function KpiAntiguedad() {
    var ui = window.CR.ui;
    var st = useState(null); var data = st[0], setData = st[1];
    var er = useState(null); var error = er[0], setError = er[1];
    var lo = useState(true); var cargando = lo[0], setCargando = lo[1];
    var fi = useState({ desde: '', hasta: '', servicio: '', centro: '', familia: '' });
    var filtro = fi[0], setFiltro = fi[1];

    useEffect(function () {
      var vivo = true;
      setCargando(true); setError(null);
      window.CR.backend.kpiAntiguedad(filtro).then(function (j) {
        if (!vivo) return;
        setData(j); setCargando(false);
      }).catch(function (e) {
        if (!vivo) return;
        setError(e.message || 'No pude traer el KPI.'); setCargando(false);
      });
      return function () { vivo = false; };
    }, [filtro.desde, filtro.hasta, filtro.servicio, filtro.centro, filtro.familia]);

    var cambiar = function (campo, valor) {
      setFiltro(function (f) { var n = Object.assign({}, f); n[campo] = valor; return n; });
    };
    /* Los rangos rápidos calculan la fecha en el HANDLER, nunca durante el render: un render que
       lee el reloj devuelve algo distinto en cada pasada y deja de ser reproducible. */
    var ultimos = function (dias) {
      var hoy = new Date();
      var desde = new Date(hoy.getTime() - (dias - 1) * 86400000);
      var iso = function (d) { return d.toISOString().slice(0, 10); };
      setFiltro(function (f) { return Object.assign({}, f, { desde: iso(desde), hasta: iso(hoy) }); });
    };

    if (error) {
      return h(ui.Page, { title: 'Antigüedad de flota' },
        h(ui.EmptyState, { title: 'No pude traer el KPI' }, error));
    }
    if (cargando && !data) {
      return h(ui.Page, { title: 'Antigüedad de flota' }, h('p', { className: 'muted' }, 'Cargando…'));
    }
    if (!data) return null;

    var tramos = data.tramos || [];
    var buckets = data.buckets || [];
    var t = data.totales || {};
    var colorDe = function (clave) {
      var i = tramos.findIndex(function (x) { return x.clave === clave; });
      return i >= 0 ? COLORES[i % COLORES.length] : COLOR_HUECO;
    };

    var partes = buckets.map(function (b) {
      return { clave: b.clave, etiqueta: b.etiqueta, valor: b.rutas, color: colorDe(b.clave) };
    });

    /* Los huecos, con su nombre y con lo que hay que hacer con cada uno. Se muestran SIEMPRE que
       existan, y no como un asterisco al pie: son rutas que el gráfico de arriba no cuenta. */
    var huecos = [];
    if (t.sinVehiculo) huecos.push({ clave: 'sin_vehiculo', n: t.sinVehiculo,
      texto: t.sinVehiculo + (t.sinVehiculo === 1 ? ' ruta todavía no tiene unidad asignada' : ' rutas todavía no tienen unidad asignada'),
      como: 'Se resuelven asignando desde Asignación.' });
    if (t.sinModelo) huecos.push({ clave: 'sin_modelo', n: t.sinModelo,
      texto: t.sinModelo + (t.sinModelo === 1 ? ' ruta va en una unidad sin año de modelo' : ' rutas van en unidades sin año de modelo'),
      como: 'Se resuelven completando el año en la ficha de la unidad, en Flota.' });
    /* Esta NO es una ruta perdida: es la explicación de un número que no cierra a simple vista.
       Medido el 19/08 sobre la base real, 35 unidades hicieron 116 rutas y hoy figuran de baja o
       como eventuales, así que "unidades que trabajaron" (143) da MÁS que la flota activa (129).
       Sin decirlo, esa diferencia se lee como un error del tablero. */



    if (t.desestimadas) huecos.push({ clave: 'desestimadas', n: t.desestimadas,
      texto: t.desestimadas + (t.desestimadas === 1 ? ' ruta desestimada no cuenta' : ' rutas desestimadas no cuentan'),
      como: 'No salieron: Mercado Libre las cubrió con otra empresa. No hay nada que resolver.' });
    if (t.unidadesFueraDeFlota) huecos.push({ clave: 'fuera_de_flota', n: t.unidadesFueraDeFlota,
      texto: t.unidadesFueraDeFlota + (t.unidadesFueraDeFlota === 1 ? ' unidad que trabajó' : ' unidades que trabajaron')
        + ' ya no figuran en la flota activa (' + t.rutasFueraDeFlota
        + (t.rutasFueraDeFlota === 1 ? ' ruta)' : ' rutas)'),
      como: 'Sus rutas cuentan igual: el KPI mide lo que salió a la calle. Por eso las unidades que trabajaron pueden ser más que la flota activa.' });

    var opciones = function (lista) {
      return [{ value: '', label: 'Todos' }].concat((lista || []).map(function (o) {
        return { value: o.valor, label: o.valor + ' (' + o.rutas + ')' };
      }));
    };

    var tendencia = data.tendencia || [];
    var puntosEdad = tendencia.map(function (d) {
      /* Edad promedio del día, ponderada por ruta: la misma cuenta que el total, día por día.
         Se calcula con los tramos que manda el servidor —tomando el punto medio de cada uno— y no
         con bordes escritos acá. El último tramo no tiene tope, así que se usa su piso. */
      var suma = 0, n = 0;
      tramos.forEach(function (tr) {
        var q = d.rutas[tr.clave] || 0;
        if (!q) return;
        var centro = tr.max == null ? tr.min : (tr.min + tr.max) / 2;
        suma += centro * q; n += q;
      });
      return { x: d.fecha, y: n ? Math.round(suma * 10 / n) / 10 : 0 };
    });

    return h(ui.Page, { title: 'Antigüedad de flota',
      subtitle: 'Rutas asignadas según la antigüedad de la unidad que las hizo' },

      h(ui.Toolbar, null,
        h(ui.Field, { label: 'Desde' },
          h(ui.Input, { type: 'date', value: filtro.desde, 'aria-label': 'Fecha desde',
            onChange: function (v) { cambiar('desde', v); } })),
        h(ui.Field, { label: 'Hasta' },
          h(ui.Input, { type: 'date', value: filtro.hasta, 'aria-label': 'Fecha hasta',
            onChange: function (v) { cambiar('hasta', v); } })),
        /* "Logística" y "Facility" son los nombres que usa MELI y los que usa la operación. Ponerles
           "servicio" y "centro de descarga" sería más claro para quien lee el código y más confuso
           para quien usa la pantalla todos los días. */
        h(ui.Field, { label: 'Logística' },
          h(ui.Select, { value: filtro.servicio, options: opciones(data.filtros && data.filtros.servicios),
            'aria-label': 'Filtrar por tipo de logística',
            onChange: function (v) { cambiar('servicio', v); } })),
        h(ui.Field, { label: 'Facility' },
          h(ui.Select, { value: filtro.centro, options: opciones(data.filtros && data.filtros.centros),
            'aria-label': 'Filtrar por centro de descarga',
            onChange: function (v) { cambiar('centro', v); } })),




        h(ui.Field, { label: 'Tipo de unidad' },
          h(ui.Select, { value: filtro.familia, options: opciones(data.filtros && data.filtros.familias),
            'aria-label': 'Filtrar por tipo de unidad',
            onChange: function (v) { cambiar('familia', v); } })),
        h(ui.Button, { variant: 'ghost', onClick: function () { ultimos(7); } }, 'Últimos 7 días'),
        h(ui.Button, { variant: 'ghost', onClick: function () { ultimos(30); } }, 'Últimos 30 días'),
        h(ui.Button, { variant: 'ghost',
          onClick: function () { setFiltro({ desde: '', hasta: '', servicio: '', centro: '', familia: '' }); } }, 'Todo')),

      h('div', { className: 'grid grid-4' },
        h(ui.StatCard, { label: 'Rutas en el período', value: t.rutas || 0,
          sub: (t.dias || 0) + (t.dias === 1 ? ' día' : ' días') }),
        h(ui.StatCard, { label: 'Antigüedad promedio (por ruta)',
          value: t.edadPromedioRuta == null ? '—' : num(t.edadPromedioRuta),
          sub: 'años — ponderado por rutas hechas' }),
        h(ui.StatCard, { label: 'Antigüedad promedio (flota)',
          value: t.edadPromedioFlota == null ? '—' : num(t.edadPromedioFlota),
          sub: 'años — sobre ' + (t.flota || 0) + ' unidades activas' }),
        /* El sub NO dice "de N activas": trabajaron 143 y la flota activa es 129, asi que ese
           "de" seria falso. Dice cuantas unidades tiene la flota hoy, que es otra cosa. */
        h(ui.StatCard, { label: 'Unidades que trabajaron', value: t.unidades || 0,
          sub: (t.flota || 0) + ' activas hoy en la flota' })),

      h(ui.Card, { title: 'Rutas por antigüedad de la unidad' },
        h(Dona, { partes: partes }),
        huecos.length
          ? h('div', { className: 'avisos', style: { marginTop: 14, display: 'flex', flexDirection: 'column', gap: 6 } },
              huecos.map(function (x) {
                return h('p', { key: x.clave, className: 'muted', style: { margin: 0, fontSize: 13 } },
                  h('b', null, x.texto), ' — ', x.como);
              }))
          : null),

      h(ui.Card, { title: 'Cada tramo: cuánto pesa en la calle y cuánto en el parque' },
        h(ui.DataTable, {
          rows: buckets.map(function (b) {
            return { clave: b.clave, etiqueta: b.etiqueta, rutas: b.rutas, pct: num(b.pct) + '%',
              unidades: b.unidades, flota: b.flota, flotaPct: num(b.flotaPct) + '%' };
          }),
          columns: [
            { key: 'etiqueta', label: 'Antigüedad' },
            { key: 'rutas', label: 'Rutas' },
            { key: 'pct', label: '% de las rutas' },
            { key: 'unidades', label: 'Unidades que trabajaron' },
            { key: 'flota', label: 'Unidades en la flota' },
            { key: 'flotaPct', label: '% de la flota' }
          ]
        }),
        /* La comparación de las dos últimas columnas contra las dos primeras ES el KPI. Dicho en una
           línea para que no haya que deducirlo de la tabla. */
        h('p', { className: 'muted', style: { fontSize: 13, marginTop: 10 } },
          'Si un tramo pesa mucho más en la flota que en las rutas, son unidades que están casi paradas.')),

      h(ui.Card, { title: 'Por tipo de unidad' },
        h(ui.DataTable, {
          rows: (data.porTipo || []).map(function (x) {
            var fila = { tipo: x.tipo, total: x.total };
            tramos.forEach(function (tr) { fila[tr.clave] = x.rutas[tr.clave] || 0; });
            return fila;
          }),
          columns: [{ key: 'tipo', label: 'Tipo' }]
            .concat(tramos.map(function (tr) { return { key: tr.clave, label: tr.etiqueta }; }))
            .concat([{ key: 'total', label: 'Total' }])
        })),

      h(ui.Card, { title: 'Antigüedad promedio, día por día' },
        puntosEdad.length >= 2
          ? h(window.CR.Tendencia, { puntos: puntosEdad, color: '#e8802c',
              formato: function (y) { return num(y) + ' años'; } })
          : h('p', { className: 'muted' },
              'Se necesitan al menos 2 días con rutas para dibujar la tendencia. En el período elegido hay '
              + puntosEdad.length + '.')),

      h(ui.Card, { title: 'Detalle por unidad' },
        h(ui.DataTable, {
          rows: (data.porPatente || []).map(function (p) {
            return { patente: p.patente || '(sin unidad)', tipo: p.tipo,
              anioModelo: p.anioModelo == null ? '—' : p.anioModelo,
              edad: p.edad == null ? '—' : p.edad,
              tramo: (tramos.find(function (tr) { return tr.clave === p.bucket; }) || {}).etiqueta
                || (p.bucket === 'sin_vehiculo' ? 'Sin unidad asignada' : 'Sin año de modelo'),
              chofer: p.chofer || '—', agencia: p.agencia || '—', rutas: p.rutas };
          }),
          columns: [
            { key: 'patente', label: 'Patente' },
            { key: 'tipo', label: 'Tipo' },
            { key: 'anioModelo', label: 'Modelo' },
            { key: 'edad', label: 'Años' },
            { key: 'tramo', label: 'Tramo' },
            { key: 'chofer', label: 'Chofer' },
            { key: 'agencia', label: 'Agencia' },
            { key: 'rutas', label: 'Rutas' }
          ]
        })));
  }

  window.CR.screens = window.CR.screens || {};
  window.CR.screens.KpiAntiguedad = KpiAntiguedad;
})();
