


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

  var UNIDADES = ['CAMIONETA', 'CHASIS LIVIANO', 'CHASIS', 'CHASIS PESADO', 'FIORINO', 'SEMI'];
  function esChasisMediano(unidad) { return unidad === 'CHASIS' || unidad === 'CHASIS MEDIANO'; }
  function palaTexto(v) { return !esChasisMediano(v.unidad) ? 'No corresponde' : v.conPala === true ? 'Con pala' : v.conPala === false ? 'Sin pala' : 'Sin confirmar'; }
  function campoPala(f, cambiar, etiqueta) {
    if (!esChasisMediano(f.unidad)) return null;
    return h('label', null, h('span', null, 'Equipamiento de pala'),
      h('select', { className: 'input', 'aria-label': etiqueta, value: f.conPala === true ? 'si' : f.conPala === false ? 'no' : '',
        onChange: function(e) { cambiar('conPala')(e.target.value === '' ? null : e.target.value === 'si'); } },
        h('option', {value: ''}, 'Sin confirmar'), h('option', {value: 'si'}, 'Con pala'), h('option', {value: 'no'}, 'Sin pala')),
      h('small', {className: 'muted'}, 'Confirmá el equipamiento real. Sólo Con pala habilita cupos de chasis con pala en Last Mile.'));
  }













  /* ID CONDUCTOR ES DATO PERSONAL Y EL SERVIDOR LO BORRA. `idConductor` está en
     `PRIVATE_PII_FIELDS` (local/dev-server.cjs) y `minimize()` lo saca del payload de TODO rol que
     no tenga `pii: 'full'` — o sea de Coordinador, Planificador y Liquidaciones, tres de los cuatro
     roles que llegan a esta pantalla. Hasta hoy el botón les bajaba el Excel igual y la columna
     salía VACÍA: sin error, sin aviso, y con el archivo pareciendo completo. La clave de cruce
     contra logistics es justo esa, así que el operador cruzaba contra nada y "no cerraba".
     El gate del servidor está BIEN. Lo que estaba mal es ofrecer el mismo botón a quien no puede
     recibir la columna que le da sentido: se saca la columna y se dice, igual que el alta manual
     hace con el DNI. */
  var CSV_FLOTA = [
    { key: 'patente', label: 'Patente' },
    { key: 'nombre', label: 'Chofer' },
    { key: 'idConductor', label: 'ID conductor' },
    { key: 'modelo', label: 'Modelo' },
    { key: 'unidad', label: 'Unidad' },
    { key: 'conPala', label: 'Equipamiento de pala', csv: palaTexto },
    { key: 'pallets', label: 'Pallets' },
    { key: 'zona', label: 'Zona' },
    { key: 'localidadSalida', label: 'Localidad de salida' },
    { key: 'agencia', label: 'Agencia' },
    { key: 'antiguedad', label: 'Antiguedad' },
    { key: 'flotaNueva', label: 'Flota nueva', csv: function (v) { return v.flotaNueva ? 'Si' : 'No'; } },
    { key: 'tarifaDiferencial', label: 'Tarifa diferencial', csv: function (v) { return v.tarifaDiferencial ? 'Si' : 'No'; } },
    { key: 'estado', label: 'Estado' },
    { key: 'disponible', label: 'Disponible', csv: function (v) { return v.disponible ? 'Si' : 'No'; } },
    { key: 'altaManual', label: 'Alta manual', csv: function (v) { return v.altaManual ? 'Si' : 'No'; } }
  ];
  /* Se resuelve AL LLAMAR, no al cargar el módulo: `window.CR.canSeePii` lo escribe `app.jsx`
     cuando ya hay sesión, y este archivo se carga antes de que exista. Capturarlo arriba dejaría
     la decisión tomada con `undefined` para todos. */
  var columnasCsvFlota = function () {
    if (window.CR.canSeePii) return CSV_FLOTA;
    return CSV_FLOTA.filter(function (c) { return c.key !== 'idConductor'; });
  };
  // una sola fuente: antes esta lista vivia duplicada aca y en el backend, y una tercera
  // version equivocada (N/S/E/O) en const.js se colaba en Onboarding.
  var ZONAS = (window.CR.const.MACRO_ZONAS || []).map(function (z) { return z.k; });

  // formulario de alta manual — top-level para no perder estado en cada render de la pantalla
  function AltaVehiculo(props) {
    var vacio = { patente: '', nombre: '', unidad: '', conPala: null, localidadSalida: '', zona: '', telefono: '', agencia: '', estado: 'ACTIVO', modelo: '', pallets: '', dni: '', idConductor: '', tarifaDiferencial: false };
    var st = useState(vacio);
    var f = st[0], setF = st[1];
    var busyState = useState(false); var busy = busyState[0], setBusy = busyState[1];
    var errState = useState(null); var err = errState[0], setErr = errState[1];
    function campo(k) { return function (v) { var n = Object.assign({}, f); n[k] = v; if (k === 'unidad' && !esChasisMediano(v)) n.conPala = null; setF(n); }; }
    function input(k, ph, extra) {
      return h('input', Object.assign({ className: 'input', value: f[k], placeholder: ph,
        onChange: function (e) { campo(k)(e.target.value); } }, extra || {}));
    }
    function check(k, label) {
      return h('label', { className: 'fa__check' },
        h('input', { type: 'checkbox', checked: f[k], onChange: function (e) { campo(k)(e.target.checked); } }),
        h('span', null, label));
    }
    // la antigüedad se DERIVA del año (mismos cortes que la base): se muestra en vivo para que se entienda
    function antigDe(anio) {
      var n = parseInt(anio, 10); if (!n || n < 1950) return null;
      var edad = new Date().getFullYear() - n;
      return edad <= 15 ? 'FLOTA NUEVA' : (edad <= 24 ? '25 A 15 AÑOS' : '+25 AÑOS');
    }
    function guardar() {
      if (!f.patente.trim()) { setErr('Falta la patente.'); return; }
      if (!f.unidad) { setErr('Elegí la unidad.'); return; }



      if (!f.localidadSalida.trim()) { setErr('Falta la localidad de salida (de dónde sale la unidad, ej: MARCOS PAZ).'); return; }
      setBusy(true); setErr(null);
      window.CR.backend.altaVehiculo(f)
        .then(function (res) { setF(vacio); props.onAlta(res); })
        .catch(function (ex) { setErr(ex.message || 'No pude agregar el vehículo.'); })
        .then(function () { setBusy(false); });
    }
    var antig = antigDe(f.modelo);
    return h(ui.Card, { title: '➕ Agregar vehículo (alta del día)' },
      h('p', { className: 'muted', style: { fontSize: 12.5, margin: '0 0 12px' } },
        'Para sumar una unidad que no está en la base (eventual, refuerzo, alta nueva). Queda disponible al instante para asignar; si es definitiva, sumala también a la base de flota.'),
      h('div', { className: 'fa__grid' },
        h('label', null, h('span', null, 'Patente *'), input('patente', 'ej: AB123CD')),
        h('label', null, h('span', null, 'Chofer'), input('nombre', 'APELLIDO NOMBRE')),
        h('label', null, h('span', null, 'Unidad *'),
          h(ui.Select, { value: f.unidad, placeholder: 'Elegir…', options: UNIDADES, onChange: campo('unidad'), 'aria-label': 'Unidad del vehículo nuevo' })),
        campoPala(f, campo, 'Pala del vehículo nuevo'),
        h('label', null, h('span', null, 'Año de la unidad'),
          input('modelo', 'ej: 2019', { type: 'number', min: 1950, max: 2027 }),
          antig ? h('span', { className: 'fa__antig' }, '→ ' + antig) : null),
        h('label', null, h('span', null, 'Capacidad (pallets)'), input('pallets', 'ej: 12', { type: 'number', min: 1, max: 60 })),


        h('label', null, h('span', null, 'Localidad de salida *'),
          input('localidadSalida', 'ej: MARCOS PAZ', { required: true, 'aria-label': 'Localidad de salida del vehículo nuevo' })),
        h('label', null, h('span', null, 'Zona'),
          h(ui.Select, { value: f.zona, placeholder: '(sin zona)', options: ZONAS, onChange: campo('zona'), 'aria-label': 'Zona del vehículo nuevo' })),
        h('label', null, h('span', null, 'Teléfono'), input('telefono', 'ej: 5491133334444')),
        window.CR.canSeePii ? h('label', null, h('span', null, 'DNI del chofer'), input('dni', 'ej: 30123456')) : null,
        h('label', null, h('span', null, 'ID conductor'), input('idConductor', 'ej: 123456')),
        h('label', null, h('span', null, 'Agencia'), input('agencia', 'ej: PARTICULAR')),
        h('label', null, h('span', null, 'Estado'),
          h(ui.Select, { value: f.estado, options: ['ACTIVO', 'EVENTUAL', 'BAJA', 'ULTIMA MILLA'], onChange: campo('estado'), 'aria-label': 'Estado del vehículo nuevo' }))),
      f.estado === 'ULTIMA MILLA' ? h('p', { className: 'muted' }, 'Esta unidad será exclusiva de Last Mile; no se ofrecerá para asignar rutas de Primera Milla.') : null,
      h('div', { className: 'fa__acts' },
        check('tarifaDiferencial', 'Tarifa diferencial'),
        h('span', { className: 'muted', style: { fontSize: 12 } }, 'La antigüedad (flota nueva, etc.) sale sola del año de la unidad.'),
        h('div', { className: 'spacer' }),
        h(ui.Button, { variant: 'primary', disabled: busy, onClick: guardar }, busy ? 'Agregando…' : 'Agregar a la flota')),
      err ? h('div', { style: { color: 'var(--danger)', marginTop: 10, fontSize: 13 } }, '⚠ ' + err) : null);
  }

  // mini-form para CAMBIAR EL CHOFER de una unidad existente (caso agencia: misma patente, otro conductor)
  function CambioChofer(props) {
    var v = props.vehiculo;
    var st = useState({ nombre: v.nombre || '', dni: v.dni || '', telefono: v.telefono || '', idConductor: v.idConductor || '' });
    var f = st[0], setF = st[1];
    var busyState = useState(false); var busy = busyState[0], setBusy = busyState[1];
    var errState = useState(null); var err = errState[0], setErr = errState[1];
    function campo(k) { return function (e) { var n = Object.assign({}, f); n[k] = e.target.value; setF(n); }; }
    function guardar() {
      if (!f.nombre.trim()) { setErr('El chofer no puede quedar sin nombre.'); return; }
      setBusy(true); setErr(null);
      window.CR.backend.editarChofer(v.patente, f)
        .then(function (res) { props.onGuardado(res); })
        .catch(function (ex) { setErr(ex.message || 'No pude cambiar el chofer.'); })
        .then(function () { setBusy(false); });
    }
    return h('div', { className: 'cc__form' },
      h('div', { className: 'fa__grid' },
        h('label', null, h('span', null, 'Chofer *'), h('input', { className: 'input', value: f.nombre, onChange: campo('nombre') })),
        window.CR.canSeePii ? h('label', null, h('span', null, 'DNI'), h('input', { className: 'input', value: f.dni, onChange: campo('dni') })) : null,
        h('label', null, h('span', null, 'Teléfono'), h('input', { className: 'input', value: f.telefono, onChange: campo('telefono') })),
        h('label', null, h('span', null, 'ID conductor'), h('input', { className: 'input', value: f.idConductor, onChange: campo('idConductor') }))),
      h('div', { className: 'fa__acts' },
        h(ui.Button, { variant: 'primary', size: 'sm', disabled: busy, onClick: guardar }, busy ? 'Guardando…' : 'Cambiar chofer'),
        h(ui.Button, { variant: 'ghost', size: 'sm', disabled: busy, onClick: props.onCancelar }, 'Cancelar'),
        h('span', { className: 'muted', style: { fontSize: 12 } }, 'La unidad ' + v.patente + ' queda igual; cambia el conductor (las rutas asignadas se actualizan solas).')),
      err ? h('div', { style: { color: 'var(--danger)', marginTop: 8, fontSize: 13 } }, '⚠ ' + err) : null);
  }




  function EditarVehiculo(props) {
    var v = props.vehiculo;
    // El estado REAL de la base puede estar fuera del enum ('EVENTUAL' a secas = pendiente de aprobar,
    // 'EN PROCESO', 'LICENCIA'…). SOLO se mapea a las 3 opciones canónicas lo que es inequívoco; el
    // resto se muestra tal cual (opción extra) — y como el form manda SOLO LO QUE CAMBIÓ, guardar sin
    // tocar el estado jamás lo pisa (QA v0.11.0: un guardado no-op reactivaba unidades no disponibles).
    function canonEstado(e) {
      if (String(e || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').trim().replace(/\s+/g, ' ').toUpperCase() === 'ULTIMA MILLA') return 'ULTIMA MILLA';
      if (/^INACTIVO/i.test(e || '')) return 'INACTIVO';
      if (e === 'EVENTUAL OK' || e === 'EVENTUAL OK ROSARIO') return 'EVENTUAL';
      if (/^ACTIVO/i.test(e || '')) return 'ACTIVO';
      if (/^BAJA/i.test(e || '')) return 'BAJA';
      return null;   // estado crudo de la base: se respeta, no se coerce
    }
    // El crudo va con etiqueta "(pendiente…)" para que NO colisione con la opción canónica: un
    // 'EVENTUAL' a secas duplicaba la opción y dejaba la aprobación → EVENTUAL OK inalcanzable
    // (QA v0.13.0, hallazgo ALTA — elegir la canónica ahora difiere del inicial y viaja al server).
    var crudoLabel = null;
    if (!canonEstado(v.estado) && v.estado) {
      crudoLabel = ['ACTIVO', 'EVENTUAL', 'INACTIVO'].indexOf(v.estado) >= 0
        ? '(' + v.estado + ' — pendiente de aprobar)' : v.estado;
    }
    var estadoInicial = canonEstado(v.estado) || crudoLabel || '';
    var inicial = { estado: estadoInicial, unidad: v.unidad || '', conPala: typeof v.conPala === 'boolean' ? v.conPala : null, modelo: v.modelo != null ? String(v.modelo) : '', pallets: v.pallets != null ? String(v.pallets) : '', localidadSalida: v.localidadSalida || '', zona: v.zona || '', agencia: v.agencia || '', tarifaDiferencial: !!v.tarifaDiferencial };
    var st = useState(inicial);
    var f = st[0], setF = st[1];
    var busyState = useState(false); var busy = busyState[0], setBusy = busyState[1];
    var errState = useState(null); var err = errState[0], setErr = errState[1];
    function campo(k) { return function (val) { var n = Object.assign({}, f); n[k] = val; if (k === 'unidad' && !esChasisMediano(val)) n.conPala = null; setF(n); }; }
    function antigDe(anio) {
      var n = parseInt(anio, 10); if (!n || n < 1950) return null;
      var edad = new Date().getFullYear() - n;
      return edad <= 15 ? 'FLOTA NUEVA' : (edad <= 24 ? '25 A 15 AÑOS' : '+25 AÑOS');
    }
    // opciones que INCLUYEN el valor actual aunque esté fuera del catálogo (unidad/zona legacy de la
    // base: sin esto el select quedaba en blanco y obligaba a inventar un valor para poder guardar)
    var opsEstado = (crudoLabel ? [crudoLabel] : []).concat(['ACTIVO', 'EVENTUAL', 'INACTIVO', 'BAJA', 'ULTIMA MILLA']);
    var opsUnidad = (f.unidad && UNIDADES.indexOf(v.unidad) < 0 && v.unidad ? [v.unidad] : []).concat(UNIDADES);
    var opsZona = (v.zona && ZONAS.indexOf(v.zona) < 0 ? [v.zona] : []).concat(ZONAS);
    function guardar() {
      // SOLO el diff: lo que no se tocó no viaja (no se re-valida ni se pisa)
      var cambios = {};
      Object.keys(f).forEach(function (k) { if (f[k] !== inicial[k]) cambios[k] = f[k]; });
      // volver a elegir la etiqueta "(… pendiente)" = no cambiar el estado (el server no la conoce)
      if (cambios.estado === crudoLabel) delete cambios.estado;


      if ('localidadSalida' in cambios && !String(cambios.localidadSalida).trim()) { setErr('La localidad de salida no puede quedar vacía: decí de dónde sale la unidad.'); return; }
      if (!Object.keys(cambios).length) { setErr('No cambiaste nada.'); return; }
      if (cambios.estado === 'BAJA' && !window.confirm('Vas a dar de BAJA la unidad ' + v.patente + ' (se va del servicio). Deja de tomarse en la planificación. ¿Confirmás?')) return;
      setBusy(true); setErr(null);
      window.CR.backend.editarVehiculo(v.patente, cambios)
        .then(function (res) { props.onGuardado(res); })
        .catch(function (ex) { setErr(ex.message || 'No pude editar la unidad.'); })
        .then(function () { setBusy(false); });
    }
    var antig = antigDe(f.modelo);
    var pasaAInactivo = f.estado === 'INACTIVO' && estadoInicial !== 'INACTIVO';
    var pasaABaja = f.estado === 'BAJA' && estadoInicial !== 'BAJA';
    return h('div', { className: 'cc__form' },
      h('div', { className: 'fa__grid' },
        h('label', null, h('span', null, 'Estado'),
          h(ui.Select, { value: f.estado, options: opsEstado, onChange: campo('estado'), 'aria-label': 'Estado de la unidad ' + v.patente })),
        h('label', null, h('span', null, 'Unidad'),
          h(ui.Select, { value: f.unidad, placeholder: '(sin dato)', options: opsUnidad, onChange: campo('unidad'), 'aria-label': 'Tipo de unidad de ' + v.patente })),
        campoPala(f, campo, 'Pala de ' + v.patente),
        h('label', null, h('span', null, 'Año de la unidad'),
          h('input', { className: 'input', type: 'number', min: 1950, max: 2027, value: f.modelo, placeholder: 'ej: 2019', onChange: function (e) { campo('modelo')(e.target.value); } }),
          antig ? h('span', { className: 'fa__antig' }, '→ ' + antig) : null),
        h('label', null, h('span', null, 'Capacidad (pallets)'),
          h('input', { className: 'input', type: 'number', min: 1, max: 60, value: f.pallets, placeholder: 'ej: 12', onChange: function (e) { campo('pallets')(e.target.value); } })),
        h('label', null, h('span', null, 'Localidad de salida'),
          h('input', { className: 'input', value: f.localidadSalida, placeholder: 'ej: MARCOS PAZ', 'aria-label': 'Localidad de salida de ' + v.patente, onChange: function (e) { campo('localidadSalida')(e.target.value); } })),
        h('label', null, h('span', null, 'Zona'),
          h(ui.Select, { value: f.zona, placeholder: '(sin zona)', options: opsZona, onChange: campo('zona'), 'aria-label': 'Zona de ' + v.patente })),
        h('label', null, h('span', null, 'Agencia'),
          h('input', { className: 'input', value: f.agencia, placeholder: 'ej: PARTICULAR', onChange: function (e) { campo('agencia')(e.target.value); } }))),
      pasaAInactivo ? h('div', { className: 'muted', style: { fontSize: 12.5, margin: '8px 0 0', color: 'var(--warning, #d9a514)' } },
        '⚠ La unidad deja de estar disponible para asignar. Si hoy tiene rutas asignadas, van a quedar marcadas en Discrepancias para que elijas reemplazo. Cuando vuelva a estar apta, pasala a ACTIVO desde acá mismo.') : null,
      pasaABaja ? h('div', { className: 'muted', style: { fontSize: 12.5, margin: '8px 0 0', color: 'var(--danger)' } },
        '⛔ BAJA = la unidad se va del servicio (definitiva o de largo plazo). Deja de tomarse en la planificación, igual que INACTIVO. Si hoy tiene rutas asignadas, van a Discrepancias para que elijas reemplazo. Para una ausencia temporal (rotura, vacaciones), usá INACTIVO.') : null,
      f.estado === 'ULTIMA MILLA' ? h('p', { className: 'muted' }, 'Unidad exclusiva de Last Mile. No se ofrecerá para Primera Milla. Si tiene rutas asignadas allí, deberás elegir un reemplazo antes de confirmar.') : null,
      h('div', { className: 'fa__acts' },
        h('label', { className: 'fa__check' },
          h('input', { type: 'checkbox', checked: f.tarifaDiferencial, onChange: function (e) { campo('tarifaDiferencial')(e.target.checked); } }),
          h('span', null, 'Tarifa diferencial')),
        h('div', { className: 'spacer' }),
        h(ui.Button, { variant: 'primary', size: 'sm', disabled: busy, onClick: guardar }, busy ? 'Guardando…' : 'Guardar cambios'),
        h(ui.Button, { variant: 'ghost', size: 'sm', disabled: busy, onClick: props.onCancelar }, 'Cancelar')),
      err ? h('div', { style: { color: 'var(--danger)', marginTop: 8, fontSize: 13 } }, '⚠ ' + err) : null);
  }

  // tras cualquier re-evaluación disparada desde ESTA pantalla, el dock de CRÁNEO tiene que ver la
  // ruta FRESCA (QA v0.12.0: explicaba con la copia vieja — mismo patrón que aplicar() en asignación)
  function aplicarReeval(res) {
    if (!res || !res.rutas || !window.CR.store) return;
    window.CR.store.bulkSet('asignacionReal', [{ rutas: res.rutas, resumen: res.resumen, discrepancias: res.discrepancias,
      fechaOperacion: res.fechaOperacion, jornadaId: res.jornadaId, version: res.version, fm: res.fm || null,
      jornadasProgramadas: res.jornadasProgramadas || [] }]);
    var sel = window.CR.store.list('copilotoRuta')[0];
    if (sel) {
      var fresca = res.rutas.filter(function (x) { return x.id === sel.id; })[0];
      window.CR.store.bulkSet('copilotoRuta', fresca ? [fresca] : []);
    }
  }

  function FlotaOperativa(props) {
    var readOnly = !!(props && props.readOnly) || window.CR.canWrite === false;
    var backendOn = !!(window.CR.backend && window.CR.backend.enabled);
    var flotaState = useState(null); var flota = flotaState[0], setFlota = flotaState[1];
    var busyState = useState(true); var busy = busyState[0], setBusy = busyState[1];
    var okState = useState(null); var ok = okState[0], setOk = okState[1];
    var altaState = useState(false); var altaAbierta = altaState[0], setAltaAbierta = altaState[1];
    var ccState = useState(null); var ccPatente = ccState[0], setCcPatente = ccState[1];   // fila en modo "cambiar chofer"
    var evState = useState(null); var evPatente = evState[0], setEvPatente = evState[1];


    var buscarState = useState(''); var buscar = buscarState[0], setBuscar = buscarState[1];
    var fEstadoState = useState(''); var fEstado = fEstadoState[0], setFEstado = fEstadoState[1];
    var fUnidadState = useState(''); var fUnidad = fUnidadState[0], setFUnidad = fUnidadState[1];

    function refrescar() {
      return window.CR.backend.flotaReal().then(function (fl) { setFlota(fl || []); }).catch(function () { setFlota([]); });
    }
    useEffect(function () {
      if (!backendOn || !window.CR.backend.flotaReal) { setBusy(false); return; }
      refrescar().then(function () { setBusy(false); });
    }, [backendOn]);

    if (!backendOn) {
      return h('div', null, h(ui.Page, { title: 'Flota (MELI)' }),
        h(ui.Card, null, h(ui.EmptyState, { title: 'Necesito el backend prendido' }, 'La flota se lee del servidor.')));
    }

    var arr = flota || [];
    // el badge distingue eventual APROBADO (warn) de estados crudos/pendientes (info): antes 47 filas
    // lucían el mismo amarillo mientras el chip "Eventuales" decía 19 (QA v0.13.0)
    var estadoColor = function (e) {
      if (/^ACTIVO/i.test(e || '')) return 'ok';
      if (e === 'EVENTUAL OK' || e === 'EVENTUAL OK ROSARIO') return 'warn';
      if (/^INACTIVO/i.test(e || '')) return 'neutral';
      if (/^BAJA/i.test(e || '')) return 'danger';
      return 'info';   // crudos de la base: EVENTUAL pendiente, EN PROCESO, etc.
    };

    var cols = [
      { key: 'patente', label: 'PATENTE', render: function (v) { return h('span', null, h('b', null, v.patente || '—'), v.altaManual ? h('span', { className: 'badge badge--info', style: { fontSize: 10, marginLeft: 6 } }, 'alta manual') : null); } },
      { key: 'nombre', label: 'CHOFER', render: function (v) {
        return h('span', null, v.nombre || '—',
          v.choferEditado ? h('span', { className: 'badge badge--info', style: { fontSize: 10, marginLeft: 6 } }, 'cambiado') : null,
          !readOnly ? h('button', { type: 'button', className: 'cc__btn', title: 'Cambiar el chofer de ' + v.patente + ' (misma unidad, otro conductor)',
            onClick: function () { setCcPatente(v.patente); setEvPatente(null); setOk(null); } }, '⇄') : null);
      } },
      { key: 'modelo', label: 'MODELO', render: function (v) { return v.modelo || '—'; } },
      { key: 'unidad', label: 'UNIDAD', render: function (v) { return v.unidad || '—'; } },
      { key: 'conPala', label: 'PALA', render: function (v) { return palaTexto(v); } },
      { key: 'pallets', label: 'PALLETS', align: 'right', render: function (v) { return v.pallets != null ? v.pallets : '—'; } },
      { key: 'zona', label: 'ZONA', render: function (v) { return v.zona || '—'; } },
      { key: 'localidadSalida', label: 'LOCALIDAD DE SALIDA', render: function (v) { return v.localidadSalida || '—'; } },
      { key: 'agencia', label: 'AGENCIA', render: function (v) { return v.agencia || '—'; } },
      { key: 'antiguedad', label: 'ANTIGÜEDAD', render: function (v) { return v.flotaNueva ? h('span', { className: 'badge badge--ok', style: { fontSize: 11 } }, 'flota nueva') : (v.antiguedad || '—'); } },
      { key: 'tarifaDif', label: 'TARIFA DIF.', render: function (v) { return v.tarifaDiferencial ? h('span', { className: 'badge badge--warn', style: { fontSize: 11 } }, 'sí') : '—'; } },
      { key: 'estado', label: 'ESTADO', render: function (v) {
        return h('span', null,
          h('span', { className: 'badge badge--' + estadoColor(v.estado), dot: true, style: { fontSize: 11 } }, v.estado || '—'),
          v.vehiculoEditado ? h('span', { className: 'badge badge--info', style: { fontSize: 10, marginLeft: 6 } }, 'editado') : null,
          !readOnly ? h('button', { type: 'button', className: 'cc__btn', title: 'Editar la unidad ' + v.patente + ' (estado activo/inactivo, año, pallets, zona…)',
            onClick: function () { setEvPatente(v.patente); setCcPatente(null); setOk(null); } }, '✎') : null);
      } }
    ];

    var activos = arr.filter(function (v) { return /^ACTIVO/i.test(v.estado || ''); }).length;
    var nuevas = arr.filter(function (v) { return v.flotaNueva; }).length;
    var manuales = arr.filter(function (v) { return v.altaManual; }).length;
    var porZona = arr.reduce(function (m, v) { var z = v.zona || 'S/Z'; m[z] = (m[z] || 0) + 1; return m; }, {});

    // Categoría exclusiva de los chips: la familia EVENTUAL completa se agrupa aunque los estados
    // crudos sigan pendientes de aprobar en el form y conserven su badge/disponibilidad actuales.
    var estadoCat = function (v) {
      var e = v.estado || '';
      if (/^ACTIVO/i.test(e)) return 'ACTIVO';
      if (e === 'EVENTUAL OK' || e === 'EVENTUAL OK ROSARIO' || e === 'EVENTUAL' || e === 'EVENTUAL ROSARIO') return 'EVENTUAL';
      if (/^INACTIVO/i.test(e)) return 'INACTIVO';
      if (/^BAJA/i.test(e)) return 'BAJA';
      if (e.normalize('NFD').replace(/[\u0300-\u036f]/g, '').trim().replace(/\s+/g, ' ').toUpperCase() === 'ULTIMA MILLA') return 'ULTIMA MILLA';
      return 'OTRO';
    };
    var cuentaCat = arr.reduce(function (m, v) { var c = estadoCat(v); m[c] = (m[c] || 0) + 1; return m; }, {});
    var unidadCat = function (v) { var u = String(v.unidad || '').trim().toUpperCase(); return UNIDADES.indexOf(u) >= 0 ? u : 'OTRO'; };
    var cuentaUnidad = arr.reduce(function (m, v) { var u = unidadCat(v); m[u] = (m[u] || 0) + 1; return m; }, {});
    // sin acentos ni eñes a los dos lados: 'ibanez' TIENE que encontrar a IBAÑEZ (QA v0.13.0)
    var plano = function (s) { return String(s).toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, ''); };
    var q = plano(buscar.trim());
    var filtrada = arr.filter(function (v) {
      if (fEstado && estadoCat(v) !== fEstado) return false;
      if (fUnidad && unidadCat(v) !== fUnidad) return false;
      if (!q) return true;
      return [v.patente, v.nombre, v.agencia, v.zona, v.localidadSalida, v.unidad, v.estado, v.modelo, window.CR.canSeePii ? v.dni : '', v.idConductor]
        .some(function (x) { return x != null && plano(x).indexOf(q) >= 0; });
    });
    var hayFiltro = !!(q || fEstado || fUnidad);
    var chips = [
      { key: '', label: 'Todas (' + arr.length + ')' },
      { key: 'ACTIVO', label: 'Activas (' + (cuentaCat.ACTIVO || 0) + ')' },
      { key: 'EVENTUAL', label: 'Eventuales (' + (cuentaCat.EVENTUAL || 0) + ')' },
      { key: 'INACTIVO', label: 'Inactivas (' + (cuentaCat.INACTIVO || 0) + ')' },
      { key: 'ULTIMA MILLA', label: 'Última milla (' + (cuentaCat['ULTIMA MILLA'] || 0) + ')' }
    ].concat(cuentaCat.BAJA ? [{ key: 'BAJA', label: 'Bajas (' + cuentaCat.BAJA + ')' }] : [])
      .concat(cuentaCat.OTRO ? [{ key: 'OTRO', label: 'Otros estados (' + cuentaCat.OTRO + ')' }] : []);
    var chipsUnidad = [{ key: '', label: 'Todas (' + arr.length + ')' }]
      .concat(UNIDADES.filter(function (u) { return cuentaUnidad[u]; }).map(function (u) { return { key: u, label: u + ' (' + cuentaUnidad[u] + ')' }; }))
      .concat(cuentaUnidad.OTRO ? [{ key: 'OTRO', label: 'Otras (' + cuentaUnidad.OTRO + ')' }] : []);

    return h('div', { 'data-novedad': 'pm-semi' },
      h(ui.Page, { title: 'Flota (MELI)', subtitle: 'La flota cargada de la base + las altas manuales del día. Mismos parámetros que MELI: modelo, unidad, pallets, zona, agencia, antigüedad, tarifa diferencial y estado.' }),
      h('p', { className: 'muted', 'data-novedad': 'flota-pala' },
        'Equipamiento de pala: cada chasis indica Con pala, Sin pala o Sin confirmar. Se completa desde Editar unidad, con permiso de edición. Sólo Con pala habilita cupos de ese tipo en Last Mile.'),

      h(ui.Toolbar, null,
        !readOnly ? h(ui.Button, { variant: altaAbierta ? 'ghost' : 'primary', icon: altaAbierta ? '✕' : '➕',
          onClick: function () { setAltaAbierta(!altaAbierta); setOk(null); } }, altaAbierta ? 'Cerrar alta' : 'Agregar vehículo') : h('span',{className:'muted'},'Consulta de flota · solo lectura'),
        h('div', { className: 'spacer' }),
        ok ? h('span', { className: 'badge badge--ok', dot: true }, ok) : null),

      altaAbierta && !readOnly ? h(AltaVehiculo, { onAlta: function (res) {
        setOk('✔ ' + res.vehiculo.patente + ' agregado a la flota');
        setAltaAbierta(false);
        refrescar();
        // el server ya re-evaluó la asignación con el vehículo nuevo: reflejarla en la pantalla de rutas
        aplicarReeval(res);
      } }) : null,

      busy ? h(ui.Card, null, h('div', { className: 'muted' }, 'Cargando flota…')) :
        !arr.length ? h(ui.Card, null, h(ui.EmptyState, { title: 'Todavía no hay flota cargada' },
          h('span', null, 'Subí la base de flota en '), h('b', null, '“Asignar rutas del día (MELI)”'),
          h('span', null, ' o agregá vehículos a mano con el botón de arriba.'))) :
          h('div', null,
            h(ui.Card, null, h('div', { className: 'resumen-row' },
              h(ui.StatCard, { label: 'Unidades', value: arr.length }),
              h(ui.StatCard, { label: 'Activos', value: activos }),
              h(ui.StatCard, { label: 'Flota nueva', value: nuevas }),
              h(ui.StatCard, { label: 'Altas manuales', value: manuales }),
              h(ui.StatCard, { label: 'Zonas', value: Object.keys(porZona).length }))),
            (function () {
              var vSel = ccPatente ? arr.filter(function (x) { return x.patente === ccPatente; })[0] : null;
              return vSel && !readOnly ? h(ui.Card, { title: '⇄ Cambiar chofer de ' + vSel.patente + ' (misma unidad)' },
                h(CambioChofer, { key: vSel.patente, vehiculo: vSel,
                  onGuardado: function (res) {
                    setOk('✔ Chofer de ' + vSel.patente + ' actualizado: ' + res.vehiculo.nombre);
                    setCcPatente(null);
                    refrescar();
                    aplicarReeval(res);
                  },
                  onCancelar: function () { setCcPatente(null); } })) : null;
            })(),
            (function () {
              var vSel = evPatente ? arr.filter(function (x) { return x.patente === evPatente; })[0] : null;
              return vSel && !readOnly ? h(ui.Card, { title: '✎ Editar unidad ' + vSel.patente + (vSel.nombre ? ' — ' + vSel.nombre : '') },
                h(EditarVehiculo, { key: vSel.patente, vehiculo: vSel,
                  onGuardado: function (res) {
                    var w = (res.warnings || []).length ? ' · ' + res.warnings[0] : '';
                    setOk('✔ Unidad ' + vSel.patente + ' actualizada (' + res.vehiculo.estado + ')' + w);
                    setEvPatente(null);
                    refrescar();
                    aplicarReeval(res);
                  },
                  onCancelar: function () { setEvPatente(null); } })) : null;
            })(),
            h(ui.Card, { title: 'Unidades y conductores — parámetros MELI' },

              h('div', { style: { display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center', marginBottom: 12 } },
                h('input', { className: 'input', style: { maxWidth: 320 }, value: buscar,
                  placeholder: '🔎 Buscar patente, chofer, agencia, zona…', 'aria-label': 'Buscar en la flota',
                  onChange: function (e) { setBuscar(e.target.value); } }),
                h('div', { className: 'prov-chips', role: 'group', 'aria-label': 'Filtrar por estado' },
                  chips.map(function (c) {
                    var activo = fEstado === c.key;
                    return h('button', { key: c.key || 'todas', type: 'button',
                      className: 'rep-chip' + (activo ? ' rep-chip--on' : ''), 'aria-pressed': activo,
                      onClick: function () { setFEstado(activo && c.key !== '' ? '' : c.key); } }, c.label);
                  })),
                h('div', { className: 'prov-chips', role: 'group', 'aria-label': 'Filtrar por tipo de unidad' },
                  chipsUnidad.map(function (c) {
                    var activo = fUnidad === c.key;
                    return h('button', { key: c.key || 'todas', type: 'button',
                      className: 'rep-chip' + (activo ? ' rep-chip--on' : ''), 'aria-pressed': activo,
                      onClick: function () { setFUnidad(activo && c.key !== '' ? '' : c.key); } }, c.label);
                  })),
                (q || fEstado || fUnidad) ? h('span', { className: 'muted', style: { fontSize: 12 } },
                  filtrada.length + ' de ' + arr.length + ' unidades') : null,
                (q || fEstado || fUnidad) ? h('button', { type: 'button', className: 'cc__btn', title: 'Limpiar búsqueda y filtros',
                  onClick: function () { setBuscar(''); setFEstado(''); setFUnidad(''); } }, '✕ limpiar') : null,
              /* El botón dice CUÁNTAS unidades baja, y con filtro puesto dice "N de M". No es
                 decoración: en Onboarding, «seleccionar todos» con filtro puesto marcó 119 grupos
                 y no los 3 visibles. Acá el daño sería más callado —un Excel incompleto que se
                 cruza contra logistics y "no cierra"— así que la cuenta va en el botón y el
                 archivo se llama `-filtrada` para que no se confunda con la flota entera. */
              h('button', { type: 'button', className: 'cc__btn', disabled: !filtrada.length,
                'aria-describedby': window.CR.canSeePii ? null : 'flota-excel-sin-id',
                title: (hayFiltro
                  ? 'Baja las ' + filtrada.length + ' unidades que estás viendo, no las ' + arr.length + ' de la flota completa'
                  : 'Baja la flota completa (' + arr.length + ' unidades)')
                  + (window.CR.canSeePii ? '' : ' — sin la columna ID conductor: tu rol no la recibe del servidor.'),
                onClick: function () {
                  window.CR.csv.descargar(
                    'craneo-flota-meli-' + new Date().toISOString().slice(0, 10)
                      + (hayFiltro ? '-filtrada' : '')
                      + (window.CR.canSeePii ? '' : '-sin-id-conductor') + '.csv',
                    columnasCsvFlota(), filtrada);
                } },
                '⬇ Excel (' + filtrada.length + (hayFiltro ? ' de ' + arr.length : '') + ')'),
              /* Un CSV se abre solo, fuera de la pantalla. Si la columna de cruce no está, tiene
                 que decirlo acá Y en el nombre del archivo: a los dos días nadie se acuerda de con
                 qué rol lo bajó. */
              window.CR.canSeePii ? null
                : h('span', { id: 'flota-excel-sin-id', className: 'muted', role: 'status',
                  style: { fontSize: 12 } },
                  'El Excel sale SIN la columna «ID conductor»: es un dato personal y tu rol no lo '
                  + 'recibe. Para cruzar contra logistics con el ID, pedíselo a Gerencia.')),
              h(ui.DataTable, { columns: cols, rows: filtrada, rowKey: 'patente',
                empty: (q || fEstado || fUnidad) ? 'Ninguna unidad coincide con la búsqueda/filtro.' : 'Sin flota' }))));
  }

  /* Las condiciones viven BAJO Flota y heredan su sección/permisos del servidor. No se agrega una
     ruta ni una tabla de roles paralela: el GET de condiciones vuelve a fallar cerrado con los
     permisos efectivos. La cuenta exclusiva de Last Mile nunca monta este shell. */
  function FlotaReal(props) {
    var vs = useState('flota'); var vista = vs[0], setVista = vs[1];
    var FmCondiciones = window.CR.screens && window.CR.screens.FmCondiciones;
    return h('div', { className: 'flota-shell', 'data-flota-vista': vista },
      h('div', { className: 'flota-subnav', 'data-novedad': 'pm-condiciones-patente', role: 'tablist', 'aria-label': 'Secciones de Flota' },
        h('button', { type: 'button', role: 'tab', 'aria-selected': vista === 'flota',
          className: 'flota-subnav__tab' + (vista === 'flota' ? ' is-active' : ''), onClick: function () { setVista('flota'); } }, 'Unidades y conductores'),
        h('button', { type: 'button', role: 'tab', 'aria-selected': vista === 'condiciones',
          className: 'flota-subnav__tab' + (vista === 'condiciones' ? ' is-active' : ''), onClick: function () { setVista('condiciones'); } }, 'Condiciones de Primera Milla')),
      vista === 'condiciones' && FmCondiciones
        ? h(FmCondiciones, { session: props && props.session, onVolverFlota: function () { setVista('flota'); } })
        : h(FlotaOperativa, props));
  }

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