<?php 
// accesorizacion.php — SGO · Accesorización por chasis
// Selección de filas + botón "Checklist (selección)" + modal con grupos + guardado MASIVO
// Preselección: accesorios ya asignados → checked (si están en todos) o indeterminate (si están en algunos)
declare(strict_types=1);
session_start();
if (!isset($_SESSION['ingreso']) || $_SESSION['ingreso'] !== 'YES') {
  header("Location: ../../views/index.php"); exit();
}
require_once __DIR__ . '/conex.php';
?>
<!doctype html>
<html lang="es">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>SGO · Programación de Accesorización</title>

  <!-- CSS mínimos -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://cdn.datatables.net/1.13.8/css/dataTables.bootstrap5.min.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">

  <style>
    body{ font-size:1rem; }
    .table thead th { white-space: nowrap; }
    .col-mini { width:54px; }
    .multi-chasis-wrap { display:flex; align-items:center; gap:.5rem; flex-wrap:wrap; }
    .multi-chasis-wrap .input-group { min-width:380px; max-width:780px; }
    .multi-chasis-help { margin-top:.25rem; }
    textarea#multiChasis{ resize:none; line-height:1.2; }

    /* Modal checklist */
    .grp-header{ display:flex; align-items:center; gap:.5rem; background: var(--bs-light); padding:.5rem .75rem; border-radius:.5rem; margin:.5rem 0; }
    .grp-body { padding:.25rem .25rem .5rem .25rem; }
    .grp-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:.25rem .75rem; }
  </style>
</head>
<body>
<div class="container-fluid">
  <div class="row">
    <?php include 'partials/menu.php'; ?>
    <main class="col-md-9 ms-sm-auto col-lg-10 px-2">
      <?php include 'partials/topbar.php'; ?>

      <div class="d-flex flex-wrap justify-content-between align-items-center mt-2 mb-2 gap-2">
        <h6 class="mb-0">Programación de Accesorización (por chasis)</h6>
        <div class="d-flex align-items-center gap-2">
          <span class="badge text-bg-secondary" id="selCount">Seleccionados: 0</span>
          <button type="button" class="btn btn-sm btn-primary" id="btn-bulk" disabled>
            <i class="fa-regular fa-square-check me-1"></i> Selección
          </button>
          <button type="button" class="btn btn-sm btn-outline-secondary" id="btn-clear" disabled>
            Limpiar selección
          </button>
        </div>
      </div>

      <!-- Buscador múltiple de CHASIS -->
      <div class="multi-chasis-wrap mb-2">
        <div class="input-group input-group-sm">
          <span class="input-group-text">Chasis</span>
          <textarea id="multiChasis" class="form-control" rows="1" placeholder="Pega varios chasis: ABC123, XYZ456 o uno por línea"></textarea>
          <button class="btn btn-outline-primary" id="btnChasisBuscar" title="Buscar (Enter)">Buscar</button>
          <button class="btn btn-outline-secondary" id="btnChasisLimpiar" title="Limpiar">Limpiar</button>
        </div>
        <!--div class="form-check form-switch ms-1">
          <input class="form-check-input" type="checkbox" role="switch" id="swExacto">
          <label class="form-check-label small" for="swExacto" title="Si está activo, filtra por coincidencia exacta">Exacto</label>
        </div-->
      </div>
      <div class="multi-chasis-help small text-body-secondary">
        Pega varios chasis separados por comas, espacios o líneas. “Exacto” busca coincidencia completa; apagado busca parcial.
      </div>

      <div class="card shadow-sm mt-2">
        <div class="card-body p-2">
          <div class="table-responsive">
            <table id="asigna" class="table table-hover table-sm w-100">
              <thead class="table-light">
                <tr>
                  <th class="text-center col-mini">
                    <div class="form-check d-flex justify-content-center align-items-center">
                      <input class="form-check-input" type="checkbox" id="checkAll" title="Seleccionar visibles" />
                      <label for="checkAll" class="ms-1 mb-0" title="Seleccionar todos los visibles">
                        <i class="fa fa-qrcode"></i>
                      </label>
                    </div>
                  </th>
                  <th>Marca</th>
                  <th>Modelo</th>
                  <th>Chasis</th>
                  <th>Color</th>
                  <th>Fecha de programación</th>
                  <th>Accesorios</th>
                </tr>
              </thead>
              <tbody><!-- dinámico --></tbody>
            </table>
          </div>
        </div>
      </div>
    </main>
  </div>
</div>

<!-- Modal Checklist Accesorios (MASIVO) -->
<div class="modal fade" id="modalChecklist" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header py-2">
        <h6 class="modal-title">Checklist de Accesorios — <span id="mc-chasis" class="text-primary"></span></h6>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
      </div>
      <div class="modal-body">
        <!-- Botones "Todos / Ninguno" removidos -->
        <div id="mc-grupos"></div>
      </div>
      <div class="modal-footer py-2">
        <div class="me-auto small text-body-secondary" id="mc-contador"></div>
        <button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancelar</button>
        <button type="button" class="btn btn-primary btn-sm" id="mc-guardar">Guardar</button>
      </div>
    </div>
  </div>
</div>

<!-- JS mínimos -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.datatables.net/1.13.8/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.8/js/dataTables.bootstrap5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>

<script>
  // === Helpers / API base ===
  const API_BASE = new URL('api/', window.location.href).href;
  const api = p => new URL(p, API_BASE).href;

  // === Toasters ===
  const toast = Swal.mixin({
    toast:true, position:'top-end', showConfirmButton:false, timer:1700, timerProgressBar:true,
    didOpen:t=>{ t.addEventListener('mouseenter', Swal.stopTimer); t.addEventListener('mouseleave', Swal.resumeTimer); }
  });
  const toastOk  = (m='Accesorios guardados') => toast.fire({ icon:'success', title:m });
  const toastErr = (m='Ocurrió un error')     => toast.fire({ icon:'error',   title:m });

  // === Selección de filas
  const SELECTED = new Set();
  function updateSelUI(){
    const n = SELECTED.size;
    document.getElementById('selCount').textContent = `Seleccionados: ${n}`;
    document.getElementById('btn-clear').disabled = n === 0;
    document.getElementById('btn-bulk').disabled  = n === 0;
  }
  function toggleSelection(chasis, checked){
    if (!chasis) return;
    if (checked) SELECTED.add(chasis); else SELECTED.delete(chasis);
    updateSelUI();
  }
  function recalcMaster(){
    const master = document.getElementById('checkAll');
    const $checks = $('#asigna tbody .row-check');
    const total = $checks.length;
    const marcados = $checks.filter(':checked').length;
    if (total === 0){ master.checked = false; master.indeterminate = false; return; }
    master.checked = marcados === total;
    master.indeterminate = marcados > 0 && marcados < total;
  }

  // ========== CHECKLIST MASIVO ==========
  // Catálogo (agrupado) desde accesorizacion_opciones.php (id, nombre, [grupo_id, grupo_nombre])
  let CATALOG = null, GRUPOS = [];
  async function cargarCatalogo(){
    if (CATALOG) return { CATALOG, GRUPOS };
    const r = await fetch(api('accesorizacion_opciones.php'));
    const j = await r.json();
    if (!j?.success) throw new Error(j?.message || 'No se pudo cargar catálogo');

    const raw = Array.isArray(j.data) ? j.data : [];
    const tieneGrupo = raw.some(o => 'grupo_id' in o || 'grupo_nombre' in o);
    CATALOG = raw.map(o=>({
      id: String(o.id),
      nombre: String(o.nombre ?? o.detalle ?? o.text ?? ''),
      grupo_id: String((tieneGrupo ? o.grupo_id : '0') ?? '0'),
      grupo_nombre: String((tieneGrupo ? o.grupo_nombre : 'Accesorios') ?? 'Accesorios')
    }));

    const map = {};
    for (const it of CATALOG){
      if (!map[it.grupo_id]) map[it.grupo_id] = { id: it.grupo_id, nombre: it.grupo_nombre, items: [] };
      map[it.grupo_id].items.push({ id: it.id, nombre: it.nombre });
    }
    GRUPOS = Object.values(map).sort((a,b)=> a.nombre.localeCompare(b.nombre));
    for (const g of GRUPOS) g.items.sort((a,b)=> a.nombre.localeCompare(b.nombre));
    return { CATALOG, GRUPOS };
  }

  // Estado del modal
  const M = { seleccion: new Set(), targetChasis: [], totalTargets: 0, counts: {} };

  function actualizarContadorModal(){
    document.getElementById('mc-contador').textContent = `${M.seleccion.size} accesorio(s) seleccionado(s)`;
  }

  function renderModalChecklist(){
    const cont = document.getElementById('mc-grupos');
    cont.innerHTML = '';

    const totalSel = M.totalTargets || 0;
    for (const g of GRUPOS){
      const wrap = document.createElement('div');
      wrap.className = 'mb-2';
      wrap.innerHTML = `
        <div class="grp-header">
          <strong class="me-auto">${g.nombre}</strong>
          <div class="btn-group btn-group-sm" role="group">
            <button class="btn btn-outline-primary btn-sm" data-act="grp-todos" data-g="${g.id}">Marcar grupo</button>
            <button class="btn btn-outline-secondary btn-sm" data-act="grp-ninguno" data-g="${g.id}">Ninguno</button>
          </div>
        </div>
        <div class="grp-body"><div class="grp-grid" id="grp-${g.id}"></div></div>`;
      cont.appendChild(wrap);

      const grid = wrap.querySelector(`#grp-${g.id}`);
      for (const it of g.items){
        const idAcc = String(it.id);
        const cnt   = (M.counts && M.counts[idAcc]) ? Number(M.counts[idAcc]) : 0;
        const checked       = (totalSel > 0 && cnt === totalSel) ? 'checked' : '';
        const partialNeeded = (cnt > 0 && cnt < totalSel);

        const row = document.createElement('div');
        row.innerHTML = `
          <div class="form-check">
            <input class="form-check-input mc-check" type="checkbox" value="${idAcc}" id="acc-${idAcc}" ${checked}>
            <label class="form-check-label" for="acc-${idAcc}">${it.nombre}</label>
          </div>`;
        grid.appendChild(row);

        const ck = row.querySelector('.mc-check');
        if (partialNeeded) ck.indeterminate = true;
        if (checked) M.seleccion.add(idAcc);
      }
    }
    actualizarContadorModal();
  }

  // Delegado único para el modal (evita duplicados de listeners)
  (function bindModalDelegatesOnce(){
    const cont = document.getElementById('mc-grupos');
    if (!cont.dataset.bound) {
      // Click en "Marcar grupo" / "Desmarcar grupo"
      cont.addEventListener('click', e=>{
        const btn = e.target.closest('[data-act]');
        if (!btn) return;
        const gid = btn.getAttribute('data-g');
        const grid = cont.querySelector(`#grp-${gid}`);
        if (!grid) return;
        const checks = grid.querySelectorAll('.mc-check');
        const marcar = btn.getAttribute('data-act') === 'grp-todos';
        checks.forEach(c=>{
          c.indeterminate = false;
          c.checked = marcar;
          if (marcar) M.seleccion.add(c.value); else M.seleccion.delete(c.value);
        });
        actualizarContadorModal();
      });

      // Cambio individual de checks
      cont.addEventListener('change', e=>{
        const ck = e.target.closest('.mc-check');
        if (!ck) return;
        ck.indeterminate = false; // el usuario decidió
        if (ck.checked) M.seleccion.add(ck.value); else M.seleccion.delete(ck.value);
        actualizarContadorModal();
      });

      cont.dataset.bound = '1';
    }
  })();

  async function abrirChecklistMasivo(targetChasis){
    try{
      await cargarCatalogo();
      M.targetChasis = Array.from(targetChasis);
      M.seleccion = new Set();

      // 1) Consultar accesorios ya asignados a los chasis seleccionados
      const pre = await fetch(api('accesorizacion_leer_multi.php'), {
        method:'POST',
        headers:{'Content-Type':'application/json'},
        body: JSON.stringify({ chasis: M.targetChasis })
      });
      const pj = await pre.json();
      if (!pj?.success) throw new Error(pj?.error || 'No se pudo cargar pre-selección');

      M.totalTargets = Number(pj.data?.total || 0);
      M.counts       = pj.data?.counts || {}; // { id_acc: veces_que_aparece }

      // 2) Pintar modal con preselección/indeterminados
      document.getElementById('mc-chasis').textContent = `Varios (${M.totalTargets})`;
      renderModalChecklist();

      const modalEl = document.getElementById('modalChecklist');
      const modal   = new bootstrap.Modal(modalEl);
      const btn     = document.getElementById('mc-guardar');

      // Guardado MASIVO: aplica exactamente los que están marcados en el modal
      btn.onclick = async ()=>{
        const txt = btn.innerHTML;
        btn.disabled = true; btn.innerHTML = 'Guardando…';
        try{
          const toSet = Array.from(M.seleccion); // marcados (checked)
          for (const ch of M.targetChasis){
            const r = await fetch(api('accesorizacion_guardar.php'), {
              method:'POST', headers:{'Content-Type':'application/json'},
              body: JSON.stringify({ chasis: ch, accesorios: toSet })
            });
            const j = await r.json();
            if (!j?.success) throw new Error(j?.message || `Error guardando ${ch}`);
          }
          toastOk('Checklist aplicado a la selección');
          if (dt) dt.ajax.reload(null, false);
          modal.hide();
        }catch(e){
          console.error(e); toastErr(e.message||'Error en guardado masivo');
        }finally{
          btn.disabled = false; btn.innerHTML = txt;
        }
      };

      // Limpiar onclick al cerrar
      modalEl.addEventListener('hidden.bs.modal', function onHidden(){
        btn.onclick = null;
        modalEl.removeEventListener('hidden.bs.modal', onHidden);
      });

      modal.show();
    }catch(e){
      console.error(e); toastErr('No se pudo abrir el checklist');
    }
  }

  // ========== DataTable ==========
  let dt;
  $(function(){
    dt = $('#asigna').DataTable({
      ajax: { url: api('accesorizacion_list_min.php'), dataSrc: 'data' },
      columns: [
        { data: null, orderable:false, searchable:false, className:'text-center',
          render: (data, type, row) => {
            const ch = String(row?.chasis || '');
            const safe = $('<div>').text(ch).html();
            const checked = SELECTED.has(ch) ? 'checked' : '';
            return `<input class="form-check-input row-check" type="checkbox" data-chasis="${safe}" ${checked}>`;
          }
        },
        { data: 'marca' },
        { data: 'modelo' },
        { data: 'chasis' },
        { data: 'color' },
        { data: 'fecha_programada' },
        { data: 'accesorios',
          render: (val) => {
            const txt = String(val ?? '').trim();
            return txt ? $('<div>').text(txt).html() : '<span class="text-body-secondary">—</span>';
          }
        }
      ],
      order: [[5,'desc']],
      pageLength: 25,
      language: { url: 'https://cdn.datatables.net/plug-ins/1.13.8/i18n/es-ES.json' }
    });

    // Selección por fila
    document.getElementById('asigna').addEventListener('change', (e)=>{
      const ck = e.target.closest('.row-check');
      if (!ck) return;
      const chasis = ck.getAttribute('data-chasis') || '';
      toggleSelection(chasis, ck.checked);
      recalcMaster();
    });

    // Maestro visibles
    document.getElementById('checkAll').addEventListener('change', function(){
      const marcar = this.checked;
      $('#asigna tbody .row-check').each(function(){
        this.checked = marcar;
        const ch = this.getAttribute('data-chasis') || '';
        toggleSelection(ch, marcar);
      });
      recalcMaster();
    });

    // Redibujo: restaurar checks y maestro
    dt.on('draw', function(){
      $('#asigna tbody .row-check').each(function(){
        const ch = this.getAttribute('data-chasis') || '';
        this.checked = SELECTED.has(ch);
      });
      recalcMaster();
    });

    // Botón Checklist → abre modal con seleccionados
    document.getElementById('btn-bulk').addEventListener('click', ()=>{
      if (SELECTED.size === 0) return;
      abrirChecklistMasivo(SELECTED);
    });

    // Limpiar selección
    document.getElementById('btn-clear').addEventListener('click', ()=>{
      SELECTED.clear();
      $('#asigna tbody .row-check').prop('checked', false);
      const master = document.getElementById('checkAll');
      master.checked = false; master.indeterminate = false;
      updateSelUI();
    });

    updateSelUI();
  });

  // ========== BÚSQUEDA MÚLTIPLE DE CHASIS ==========
  function escapeRegex(str){ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
  function normalizaListaEntrada(raw){
    return (raw || '').split(/[\s,]+/g).map(s=>s.trim()).filter(Boolean);
  }
  let CHASIS_EXACTO = false;

  function buildChasisRegex(tokens){
    if (!tokens.length) return '';
    const escaped = tokens.map(escapeRegex);
    if (CHASIS_EXACTO){
      return '^(?:' + escaped.join('|') + ')$';
    }
    return '(' + escaped.join('|') + ')';
  }

  $(function(){
    const $input  = $('#multiChasis');
    const $btnGo  = $('#btnChasisBuscar');
    const $btnClr = $('#btnChasisLimpiar');

    function aplicarFiltroChasis(){
      const tokens = normalizaListaEntrada($input.val());
      const pattern = buildChasisRegex(tokens);
      // Columna "Chasis" = índice 3; regex=true, smart=false
      dt.column(3).search(pattern, true, false).draw();
    }

    $btnGo.on('click', aplicarFiltroChasis);

    $input.on('keydown', function(e){
      if (e.key === 'Enter' && (e.ctrlKey || e.metaKey || !e.shiftKey)) {
        e.preventDefault();
        aplicarFiltroChasis();
      }
    });

    $input.on('input', function(){
      this.style.height = 'auto';
      this.style.height = Math.min(this.scrollHeight, 200) + 'px';
    });

    $btnClr.on('click', function(){
      $input.val('').trigger('input');
      dt.column(3).search('', true, false).draw();
    });

    $('#swExacto').on('change', function(){
      CHASIS_EXACTO = this.checked;
      aplicarFiltroChasis();
    });
  });
</script>
</body>
</html>
