/* Panel de discrepancias — agrupado por TIPO, ordenado por gravedad y RESOLUBLE desde acá.
   Antes era una lista sábana de hasta 40 ítems sin acciones: el planificador leía el problema
   pero tenía que ir a buscar la ruta a mano. Ahora cada grupo trae su acción de 1 clic y, cuando
   la corrección es mecánica (sacar tarifa-dif, bajar rotación), un botón que resuelve el grupo entero.
   window.CR.Discrepancias */
(function () {
  var React = window.React;
  var ui = window.CR.ui;
  var h = React.createElement;

  // Metadata por tipo. `accion`:
  //   'elegir'  -> el planificador elige el chofer de una lista (no hay corrección automática correcta)
  //   'auto'    -> hay un candidato objetivamente mejor según la regla -> botón de 1 clic + resolver grupo
  //   null      -> informativo, no se arregla desde la UI
  var TIPO = {
    servicio_incompatible: {
      icon: '⚠', titulo: 'Servicio fuera de las condiciones de esta programación', accion: null, abiertoPorDefecto: true,
      ayuda: 'Este aviso compara el servicio de la ruta con las condiciones guardadas al crear la programación. Los cambios en Flota se aplican a nuevas programaciones. Si la jornada está abierta, podés revisar las opciones y aceptar una excepción manual; este aviso por sí solo no bloquea confirmar ni cerrar.'
    },
    doble_ciclo_partido: {
      icon: '⛓', titulo: 'Dobles ciclos partidos', accion: 'auto', abiertoPorDefecto: true,
      cta: 'Unificar al chofer del C1', bulk: 'Unificar los pares que pueda',
      ayuda: 'Las dos mitades de un doble ciclo van con el MISMO chofer: termina una vuelta, descarga y arranca la otra. Estas quedaron con choferes distintos o una sin asignar. “Unificar” pone la otra mitad con el chofer del C1.'
    },
    sin_recurso: {
      icon: '⛔', titulo: 'Rutas sin cubrir', accion: 'elegir', abiertoPorDefecto: true,
      ayuda: 'Si hay una unidad libre compatible la elegís acá mismo; si no, podés FORZAR una fuera de regla (sección ⚠ del desplegable), sumar flota en "Flota (MELI)", o confirmar igual y dejarla pendiente para mañana (el sistema te avisa antes).'
    },
    chofer_inexistente: {
      icon: '👻', titulo: 'Choferes que ya no están en la flota', accion: 'elegir', abiertoPorDefecto: true,
      ayuda: 'Estas rutas tenían un chofer que desapareció de la base de flota (probablemente se re-subió el archivo). Elegí el reemplazo acá.'
    },
    chofer_duplicado: {
      icon: '👥', titulo: 'Choferes en dos rutas a la vez', accion: 'elegir', abiertoPorDefecto: true,
      ayuda: 'Un chofer no puede llevar dos rutas el mismo día. El sistema dejó la primera y liberó esta: elegile otro chofer.'
    },
    asignacion_invalida: {
      icon: '🚫', titulo: 'Asignaciones que violan una regla dura', accion: 'elegir', abiertoPorDefecto: true,
      ayuda: 'La unidad asignada dejó de cumplir una regla que no se negocia (disponibilidad, la unidad que pidió MELI, o la separación de Rosario). Suele pasar cuando se re-sube la flota con datos nuevos. Cambiala antes de confirmar — o forzala a propósito desde el desplegable de la ruta.'
    },
    asignacion_forzada: {
      icon: '💪', titulo: 'Asignaciones forzadas por vos (fuera de regla)', accion: 'elegir',
      ayuda: 'Vos elegiste esta unidad sabiendo que rompe una regla (zona de Rosario o unidad menor a la pedida). Vale y no bloquea — queda listada para que no se te pierda de vista. Si aparece una unidad de regla, cambiala acá.'
    },
    backup_manual: {
      icon: '📦', titulo: 'BackUp — se asignan a mano', accion: 'elegir',
      ayuda: 'El pedido de flota para BackUp llega por mail y no figura en el sistema, así que el motor no las asigna solo. Elegí el chofer acá cuando tengas el dato.'
    },
    tarifa_mal_amortizada: {
      icon: '💸', titulo: 'Tarifa diferencial mal amortizada', accion: 'auto',
      cta: 'Usar unidad sin tarifa-dif', bulk: 'Sacar la tarifa-dif de las que pueda',
      ayuda: 'La tarifa diferencial amortiza solo entre 51 y 100 km EFECTIVOS (los km de MELI + la descarga al centro de esa ruta — calculada con la ubicación REAL del centro cuando el ID lo trae, ej. ARBA02; ~30 estimados si no). Menos de 51: se paga caro al pedo. Más de 100: se paga el ADICIONAL por exceso — pérdida directa. Y en rutas E_ (pagan 23% menos) nunca conviene.'
    },
    tarifa_sin_km: {
      icon: '❓', titulo: 'Tarifa diferencial sin km para verificar', accion: 'auto',
      cta: 'Usar unidad sin tarifa-dif', bulk: 'Sacar la tarifa-dif de las que pueda',
      ayuda: 'El export de MELI no trae los km de estas rutas (pasa con las FULL), así que no se puede saber si la tarifa diferencial amortiza. Si tenés una unidad común libre, conviene usarla.'
    },
    sobre_rotacion: {
      icon: '🔁', titulo: 'Choferes con mucha rotación', accion: 'auto',
      cta: 'Cambiar a chofer con menos días', bulk: 'Repartir las que pueda',
      ayuda: 'Estos choferes ya trabajaron 5 días esta semana. La regla de equidad los deja descansar si hay alguien disponible con menos días.'
    },
    tarifa_proveedor_pendiente: {
      icon: '🧾', titulo: 'Rutas sin tarifa de proveedor aplicable', accion: null,
      ayuda: 'El tipo de unidad figura en Flota. Consultá la tarifa de la patente y su vigencia en Tarifa de proveedores.'
    },
    tarifa_sin_unidad: {
      // sin `cta` ni `bulk`: los dos sólo se leen cuando accion === 'auto' (ver nAuto y dg__bulk).
      // Ponerlos acá sería configuración muerta que hace creer que hay resolución masiva.
      icon: '🧾', titulo: 'Rutas que no cotizan (unidad sin reconocer)', accion: 'elegir',
      ayuda: 'Revisá el tipo de unidad en Flota MELI. Si está vacío o fuera del catálogo y la patente tampoco tiene tarifa aplicable, la ruta queda sin costo estimado.'
    },
    zona_sin_clasificar: {
      icon: '🗺', titulo: 'Barrios sin macro-zona', accion: null,
      ayuda: 'El barrio que trae MELI todavía no está mapeado a una macro-zona (CABA/Norte/Oeste/Sur/Rosario). La ruta se asignó igual por las otras reglas, pero no suma al mapa ni al criterio de "zona propia". Pasanos el barrio y lo mapeamos.'
    }
  };
  var SEV_ORDEN = { alta: 0, media: 1, baja: 2 };
  var TOPE = 12;   // ítems visibles por grupo antes del "ver todas" (nada se oculta en silencio)

  function metaDe(tipo) {
    return TIPO[tipo] || { icon: '⚠', titulo: String(tipo).replace(/_/g, ' '), accion: null };
  }

  function Grupo(props) {
    var g = props.grupo, meta = metaDe(g.tipo);
    var abiertoState = React.useState(!!meta.abiertoPorDefecto || !!g.bloqueante);
    var abierto = abiertoState[0], setAbierto = abiertoState[1];
    var todasState = React.useState(false);
    var todas = todasState[0], setTodas = todasState[1];

    var items = todas ? g.items : g.items.slice(0, TOPE);
    var ocultas = g.items.length - items.length;
    // cuántas resuelve el botón de grupo. Sale del PLAN (simula la unicidad chofer↔ruta), no de contar
    // ítems con candidato: dos rutas pueden querer el mismo chofer y sólo una se lo lleva.
    var nAuto = meta.accion === 'auto' ? Object.keys(props.planGrupo(g.tipo)).length : 0;

    var bodyId = 'dgb-' + g.tipo;
    return h('section', { className: 'dg dg--' + g.severidad + (abierto ? ' dg--open' : '') },
      h('button', { type: 'button', className: 'dg__head', 'aria-expanded': abierto, 'aria-controls': bodyId, onClick: function () { setAbierto(!abierto); } },
        h('span', { className: 'dg__ico', 'aria-hidden': true }, meta.icon),
        h('span', { className: 'dg__tit' }, meta.titulo),
        h('span', { className: 'dg__n' }, g.items.length),
        g.bloqueante ? h('span', { className: 'badge badge--danger', style: { fontSize: 11 } }, 'bloquea confirmar') : null,
        h('span', { className: 'dg__chev', 'aria-hidden': true }, '▾')),

      abierto ? h('div', { className: 'dg__body', id: bodyId },
        meta.ayuda ? h('p', { className: 'dg__ayuda' }, meta.ayuda) : null,

        nAuto > 1 ? h('div', { className: 'dg__bulk' },
          h(ui.Button, { size: 'sm', variant: 'primary', disabled: props.busy, onClick: function () { props.onResolverGrupo(g.tipo); } },
            (meta.bulk || 'Resolver') + ' (' + nAuto + ')'),
          nAuto < g.items.length
            ? h('span', { className: 'muted', style: { fontSize: 12 } },
              (g.items.length - nAuto) === 1
                ? 'La otra no tiene reemplazo libre que cumpla la regla.'
                : 'Las otras ' + (g.items.length - nAuto) + ' no tienen reemplazo libre que cumpla la regla.')
            : null) : null,

        h('ul', { className: 'dg__list', role: 'list' }, items.map(function (d, i) {
          return h(Item, { key: d.rutaId + '_' + i, d: d, meta: meta, ruta: props.rutaDe(d.rutaId), sugerido: props.sugerido,
            usadoPorOtro: props.usadoPorOtro, opcionesConForzadas: props.opcionesConForzadas, busy: props.busy, onPick: props.onPick, onCargarOpciones: props.onCargarOpciones, onVer: props.onVer });
        })),

        ocultas > 0
          ? h('button', { type: 'button', className: 'dg__mas', onClick: function () { setTodas(true); } },
            ocultas === 1 ? 'Ver la restante' : 'Ver las ' + ocultas + ' restantes')
          : (todas && g.items.length > TOPE
            ? h('button', { type: 'button', className: 'dg__mas', onClick: function () { setTodas(false); } }, 'Ver menos')
            : null)) : null);
  }

  function Item(props) {
    var d = props.d, meta = props.meta, r = props.ruta;
    var cand = meta.accion === 'auto' ? props.sugerido(d) : null;


    var pendState = React.useState(null); var pendiente = pendState[0], setPendiente = pendState[1];
    React.useEffect(function () { if (!props.busy) setPendiente(null); }, [props.busy]);
    function pick(candId, etiqueta) {
      setPendiente(etiqueta);
      // La selección puede abrir una advertencia sin iniciar una mutación (busy no cambia).
      return Promise.resolve().then(function () { return props.onPick(d.rutaId, candId); })
        .then(function () { setPendiente(null); }, function () { setPendiente(null); });
    }

    var dias = function (n) { return n === 1 ? '1 día' : n + ' días'; };
    var acciones = [];
    if (pendiente) {
      acciones.push(h('span', { key: 'pend', className: 'dgi__pend' }, '⏳ Asignando ' + pendiente + '…'));
    } else if (meta.accion === 'elegir') {
      var opts = ((r && r.candidatos) || []).filter(function (c) { return !props.usadoPorOtro(c, d.rutaId); }).map(function (c) {
        return { value: c.id, label: c.patente + ' · ' + c.nombre + ' (' + c.unidad + ')' + window.CR.candAttrs(c) };
      });
      // si el pool válido no alcanza, el mismo desplegable ofrece FORZAR una unidad fuera de regla
      if (r && props.opcionesConForzadas) opts = props.opcionesConForzadas(r, opts);
      acciones.push(opts.length
        ? h(ui.Select, { key: 'sel', value: '', placeholder: opts.some(function (o) { return String(o.value).charAt(0) !== '_' && !/^⚠/.test(o.label); }) ? 'Elegir chofer…' : 'Forzar fuera de regla…', disabled: props.busy, options: opts,
          'aria-label': 'Elegir chofer para la ruta ' + d.idRuta,
          onChange: function (v) {
            if (!v || String(v).charAt(0) === '_') return;   // separadores (_sep, _sepv, _sepmore) no son elegibles
            var c = ((r && r.candidatos) || []).filter(function (x) { return x.id === v; })[0];
            pick(v, c ? c.patente + ' · ' + c.nombre : 'el reemplazo');
          } })
        : h('span', { key: 'no', className: 'dgi__no' }, 'Sin unidad libre compatible'));
    } else if (meta.accion === 'auto') {
      acciones.push(cand
        ? h(ui.Button, { key: 'fix', size: 'sm', variant: 'ghost', disabled: props.busy, title: 'Pasa a ' + cand.patente + ' · ' + cand.nombre,
          onClick: function () { pick(cand.id, cand.patente + ' · ' + cand.nombre); } }, meta.cta)
        : h('span', { key: 'no', className: 'dgi__no' }, 'Sin reemplazo libre'));
    }
    if (props.onCargarOpciones) acciones.push(h(ui.Button, { key: 'opciones', size: 'sm', variant: 'ghost',
      disabled: props.busy, onClick: function () { props.onCargarOpciones(d.rutaId); } }, 'Consultar opciones'));
    acciones.push(h('button', { key: 'ver', type: 'button', className: 'dgi__ver', title: 'Ir a esta ruta en la lista', onClick: function () { props.onVer(d.rutaId); } }, 'Ver ruta'));

    return h('li', { className: 'dgi' },
      h('div', { className: 'dgi__txt' },
        h('b', { className: 'dgi__id' }, d.idRuta),
        h('span', { className: 'dgi__det' }, d.detalle),
        d.sugerencia ? h('span', { className: 'dgi__sug' }, '💡 ' + d.sugerencia) : null,
        cand ? h('span', { className: 'dgi__cand' }, '→ propone ' + cand.patente + ' · ' + cand.nombre + (cand.dias != null ? ' (' + dias(cand.dias) + ')' : '')) : null),
      h('div', { className: 'dgi__act' }, acciones));
  }

  function Discrepancias(props) {
    var disc = props.disc || [];
    if (!disc.length) {
      return h(ui.Card, { 'data-novedad': props['data-novedad'] }, h('div', { className: 'dg__ok' }, '✓ Sin discrepancias. La programación está lista para confirmar.'));
    }
    // agrupar por tipo, ordenar por gravedad y luego por cantidad
    var m = {};
    disc.forEach(function (d) {
      var g = m[d.tipo] || (m[d.tipo] = { tipo: d.tipo, severidad: d.severidad || 'media', bloqueante: false, items: [] });
      g.items.push(d);
      if (d.bloqueante) g.bloqueante = true;
    });
    var grupos = Object.keys(m).map(function (k) { return m[k]; }).sort(function (a, b) {
      return (SEV_ORDEN[a.severidad] - SEV_ORDEN[b.severidad]) || (b.items.length - a.items.length);
    });
    var nBloq = disc.filter(function (d) { return d.bloqueante; }).length;

    return h(ui.Card, { title: 'Discrepancias — revisá antes de confirmar', 'data-novedad': props['data-novedad'] },
      // anuncio para lectores de pantalla: el estado del panel cambia tras cada resolución
      h('div', { className: 'sr-only', role: 'status', 'aria-live': 'polite' },
        props.busy ? 'Recalculando la programación…'
          : disc.length + ' discrepancias, ' + nBloq + ' bloqueante' + (nBloq === 1 ? '' : 's') + '.'),
      h('div', { className: 'dg__resumen' },
        nBloq
          ? h('span', { className: 'badge badge--danger', dot: true }, nBloq + ' bloqueante' + (nBloq === 1 ? '' : 's'))
          : h('span', { className: 'badge badge--ok', dot: true }, 'Sin bloqueantes'),
        h('span', { className: 'badge badge--warn', dot: true }, (disc.length - nBloq) + ' de calidad'),
        h('span', { className: 'muted', style: { fontSize: 12 } }, 'Agrupadas por tipo. Abrí un grupo para resolverlas.')),
      grupos.map(function (g) {
        return h(Grupo, { key: g.tipo, grupo: g, busy: props.busy, rutaDe: props.rutaDe, sugerido: props.sugerido,
          planGrupo: props.planGrupo, usadoPorOtro: props.usadoPorOtro, opcionesConForzadas: props.opcionesConForzadas,
          onPick: props.onPick, onCargarOpciones: props.onCargarOpciones, onResolverGrupo: props.onResolverGrupo, onVer: props.onVer });
      }));
  }

  window.CR.Discrepancias = Discrepancias;
})();
