// incidencias.module.js — módulo para gestionar incidencias en el wizard
(function(){
  const STORAGE_KEY = 'pc_incidencias_v1';

  // Helper para escapar HTML
  function escapeHtml(s){ return String(s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }

  // Obtiene filas desde el backend
  async function loadItems(){
    const resp = await fetch('../../backend/api/incidencias/get_incidencias.php', { cache: 'no-store' });
    if (!resp.ok) throw new Error('HTTP ' + resp.status);
    const text = await resp.text();
    try { return JSON.parse(text); } catch(e){
      // si el endpoint devuelve lines con BOM u otros, intentar limpiar
      const cleaned = text.replace(/^[^\[]+/, '');
      return JSON.parse(cleaned);
    }
  }

  // Crea una tabla HTML a partir de filas y registra firmas globales por fila
  function createTableFromRows(rows){
    if (!rows || rows.length === 0) return '<div class="text-muted">No hay incidencias.</div>';
    const cols = Object.keys(rows[0]);
    // init global maps
    window.PCRowKeyCounter = window.PCRowKeyCounter || 0;
    window.PCRowSignatures = window.PCRowSignatures || {};
    window.PCRowSignaturesNormalized = window.PCRowSignaturesNormalized || {};
    function signatureFor(r){ const ks = Object.keys(r).sort(); const o = {}; ks.forEach(k=> o[k]=String(r[k] ?? '')); return JSON.stringify(o); }
    function signatureForNormalized(r){ const o = {}; Object.keys(r).forEach(k=> o[k.toLowerCase()]=String(r[k] ?? '')); const ks = Object.keys(o).sort(); const p = {}; ks.forEach(k=> p[k]=o[k]); return JSON.stringify(p); }

    let html = '<div class="table-responsive"><table class="table table-sm table-striped">';
    html += '<thead><tr>' + cols.map(c=> `<th>${escapeHtml(c)}</th>`).join('') + '<th>Justificado</th></tr></thead>';
    html += '<tbody>' + rows.map(r=>{
      const keyId = 'rk' + (++window.PCRowKeyCounter);
      window.PCRowSignatures[keyId] = signatureFor(r);
      window.PCRowSignaturesNormalized[keyId] = signatureForNormalized(r);
      const cells = cols.map(c=> `<td>${escapeHtml(r[c])}</td>`).join('');
      const chk = `<td><input type="checkbox" class="pc-justificado" data-pc-keyid="${keyId}"></td>`;
      return `<tr data-pc-keyid="${keyId}">${cells}${chk}</tr>`;
    }).join('') + '</tbody>';
    html += '</table></div>';
    return html;
  }

  // Renderiza la UI del módulo dentro del contenedor
  async function render(container){
    container.innerHTML = `
      <h6 class="mb-2">Incidencias</h6>
      <p class="text-muted mb-2">Mostrando registros de <code>PreNominaIncidencias</code>.</p>
      <div class="row g-2 align-items-center mb-2">
        <div class="col-auto"><input id="pc_filter_attuid" class="form-control form-control-sm" placeholder="Filtrar (ATTUID, CURP, texto...)" /></div>
        <div class="col-auto"><button id="pc_filter_btn" class="btn btn-sm btn-outline-primary">Filtrar</button></div>
        <div class="col-auto d-flex align-items-center"><input id="pc_ver_todos" type="checkbox" class="form-check-input me-1" checked /><label for="pc_ver_todos" class="form-check-label small mb-0">Ver todos</label></div>
        <div class="col-auto"><button id="pc_refresh_btn" class="btn btn-sm btn-outline-secondary">Refrescar</button></div>
        <div class="col-auto"><button id="pc_marcar_todos" class="btn btn-sm btn-outline-primary">Marcar todos</button></div>
        <div class="col-auto"><button id="pc_desmarcar_todos" class="btn btn-sm btn-outline-secondary">Desmarcar todos</button></div>
      </div>
      <div class="small text-muted mb-2">Marque "Justificado" en las filas que no deben contarse para el cálculo de faltas.</div>
      <div id="pc_in_table">Cargando...</div>
    `;

    const tableEl = container.querySelector('#pc_in_table');
    const inputFilter = container.querySelector('#pc_filter_attuid');
    const btnFilter = container.querySelector('#pc_filter_btn');
    const btnRefresh = container.querySelector('#pc_refresh_btn');
    const chkVerTodos = container.querySelector('#pc_ver_todos');

    function getFieldValue(row, names){
      if (!row) return undefined;
      for (const n of names) if (Object.prototype.hasOwnProperty.call(row, n)) return row[n];
      const lower = {}; Object.keys(row).forEach(k=> lower[k.toLowerCase()]=row[k]);
      for (const n of names) if (Object.prototype.hasOwnProperty.call(lower, n.toLowerCase())) return lower[n.toLowerCase()];
      return undefined;
    }

    async function loadAndRender(){
      tableEl.innerHTML = 'Cargando...';
      try{
        let rows = await loadItems();
        const q = (inputFilter.value || '').trim().toLowerCase();
        if (q) rows = rows.filter(r=> Object.values(r).some(v=> String(v || '').toLowerCase().includes(q)));
        const verTodos = chkVerTodos.checked;
        if (!verTodos) {
          function norm(v){ return String(v || '').trim().toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,''); }
          rows = rows.filter(r => {
            const resultado = String(getFieldValue(r,['Resultado','resultado']) || '').trim().toLowerCase();
            const incid = String(getFieldValue(r,['incidias','incidencias','incidencia']) || '');
            if (norm(incid) === 'dia de descanso') return false;
            return resultado !== 'ok';
          });
        }
        tableEl.innerHTML = createTableFromRows(rows);
      }catch(err){
        tableEl.innerHTML = `<div class="alert alert-danger small">Error al cargar incidencias: ${escapeHtml(err.message)}</div>` +
                          `<pre class="small text-muted">Comprueba el endpoint en <code>prenomina/backend/api/incidencias/get_incidencias.php</code> y la conexión a la BD.</pre>`;
      }
    }

    btnFilter.addEventListener('click', ()=> loadAndRender());
    inputFilter.addEventListener('keydown', (e)=> { if (e.key === 'Enter') loadAndRender(); });
    btnRefresh.addEventListener('click', ()=> { inputFilter.value=''; loadAndRender(); });
    container.querySelector('#pc_marcar_todos').addEventListener('click', ()=>{ Array.from(container.querySelectorAll('.pc-justificado')).forEach(c=> c.checked = true); });
    container.querySelector('#pc_desmarcar_todos').addEventListener('click', ()=>{ Array.from(container.querySelectorAll('.pc-justificado')).forEach(c=> c.checked = false); });

    await loadAndRender();
  }

  function getData(){ return loadItems(); }
  function onFinish(){ return {}; }

  // conversión hora a minutos
  function parseToMinutes(v){
    if (!v) return null; v = String(v).trim();
    const m = v.match(/(\d{1,2}:\d{2})(:\d{2})?/);
    if (m){ const parts = m[1].split(':'); const hh = parseInt(parts[0],10); const mm = parseInt(parts[1],10); if (isNaN(hh)||isNaN(mm)) return null; return hh*60+mm; }
    const num = Number(v); if (!isNaN(num)){ const d = (String(v).length<=10) ? new Date(num*1000) : new Date(num); if (!isNaN(d.getTime())) return d.getHours()*60 + d.getMinutes(); }
    return null;
  }

  // onCalculate: aplica reglas y muestra resumen
  async function onCalculate(){
    try{
      let rows = await loadItems();
      // excluir filas marcadas como justificadas
      try{
        const checked = Array.from(document.querySelectorAll('.pc-justificado:checked')).map(el=> el.getAttribute('data-pc-keyid'));
        if (checked.length){
          const sigs = new Set(checked.map(k=> window.PCRowSignatures && window.PCRowSignatures[k]).filter(Boolean));
          if (sigs.size) rows = (rows||[]).filter(r=>{ const ks = Object.keys(r).sort(); const o = {}; ks.forEach(k=> o[k]=String(r[k] ?? '')); return !sigs.has(JSON.stringify(o)); });
        }
      }catch(e){ console.warn('filter justificadas', e); }

      // normalizar keys lowercase
      const normRows = (rows || []).map(r=>{ const o={}; Object.keys(r).forEach(k=> o[k.toLowerCase()]=r[k]); return o; });

      // construir mapa firma normalizada -> keyIds
      const sigToKeyIds = {};
      Object.keys(window.PCRowSignaturesNormalized || {}).forEach(kid=>{ const s = window.PCRowSignaturesNormalized[kid]; if (!s) return; sigToKeyIds[s] = sigToKeyIds[s]||[]; sigToKeyIds[s].push(kid); });

      // filtrar y agrupar
      const map = new Map();
      normRows.forEach(r=>{
        const name = String(r['nombre_completo'] || r['nombre'] || '').trim() || 'Sin nombre';
        const tacloud = r['tacloud'] || r['taclock'] || r['ta_cloud'] || r['tacloud_time'] || r['tacloud'] || '';
        const horario = r['horario'] || r['hora'] || r['scheduled'] || '';
        const incidField = r['incidias'] ?? r['incidencias'] ?? r['inciidias'] ?? r['incidencia'] ?? '';
        const resultadoRaw = String(r['resultado'] || '').trim().toLowerCase();

        const tMinutes = parseToMinutes(tacloud);
        const hMinutes = parseToMinutes(horario);
        // Si Tacloud está vacío y Resultado == 'horario no encontrado' => falta
        if (tMinutes === null){
          if (resultadoRaw === 'horario no encontrado'){
            const e = map.get(name) || { name, retardos:0, faltas:0, rows:[], keyIds:[] };
            e.faltas += 1; e.rows.push({ raw: r, diffMin: null, note: 'HORARIO NO ENCONTRADO' }); map.set(name, e); return;
          }
          // si hay incidencia y no hay tacloud, omitimos registro
          if (String(incidField || '').trim() !== '') return;
        }

        const diffMin = (tMinutes !== null && hMinutes !== null) ? (tMinutes - hMinutes) : null;
        const e = map.get(name) || { name, retardos:0, faltas:0, rows:[], keyIds:[] };
        // mapear keyIds usando firma normalizada
        const ks = Object.keys(r).sort(); const o = {}; ks.forEach(k=> o[k]=String(r[k] ?? '')); const normalizedSig = JSON.stringify(o);
        const mappedKeyIds = sigToKeyIds[normalizedSig] || [];
        e.rows.push({ raw: r, diffMin, normalizedSig, keyIds: mappedKeyIds.slice() });
        mappedKeyIds.forEach(kid=> { if (!e.keyIds.includes(kid)) e.keyIds.push(kid); });

        if (diffMin === null) { e.missingTime = (e.missingTime||0) + 1; }
        else if (diffMin > 0 && diffMin <= 9) { e.retardos += 1; }
        else if (diffMin >= 10) { e.faltas += 1; }
        map.set(name, e);
      });

      const results = [];
      for (const [name, e] of map.entries()){ const faltasFromRetardos = Math.floor(e.retardos/2); const totalFaltas = e.faltas + faltasFromRetardos; results.push({ nombre: name, retardos: e.retardos, faltas_directas: e.faltas, faltas_convertidas_por_retardos: faltasFromRetardos, faltas_totales: totalFaltas, missing_time: e.missingTime||0, rows: e.rows, keyIds: e.keyIds }); }
      results.sort((a,b)=> a.nombre.localeCompare(b.nombre, 'es'));

      const toShow = results.filter(r=> Number(r.faltas_totales || 0) > 0);
      if (!toShow.length) { alert('No se encontraron registros con faltas totales > 0.'); return results; }

      const rowsHtml = toShow.map((r,i)=> `
        <tr class="pc-summary-row" data-pc-idx="${i}" data-pc-person="${escapeHtml(r.nombre)}" style="cursor:pointer">
          <td>${escapeHtml(r.nombre)}</td>
          <td class="text-center">${r.retardos}</td>
          <td class="text-center">${r.faltas_directas}</td>
          <td class="text-center">${r.faltas_convertidas_por_retardos}</td>
          <td class="text-center fw-bold">${r.faltas_totales}</td>
          <td class="text-center">${r.missing_time}</td>
        </tr>
      `).join('');
      const table = `
        <div class="table-responsive"><table class="table table-sm table-bordered"><thead class="table-light"><tr>
          <th>Nombre</th><th class="text-center">Retardos</th><th class="text-center">Faltas directas</th><th class="text-center">Faltas por retardos</th><th class="text-center">Faltas totales</th><th class="text-center">Sin tiempo</th>
        </tr></thead><tbody>${rowsHtml}</tbody></table></div>`;

      showSummaryHtmlModal('Resumen de faltas', table);
      // attach click handlers
      setTimeout(()=>{
        try{ document.querySelectorAll('.pc-summary-row').forEach(el=> el.addEventListener('click', ()=>{ const idx = Number(el.getAttribute('data-pc-idx')); const entry = toShow[idx]; if (entry) showPersonDetailsModal(entry); })); }catch(e){ console.warn(e); }
      }, 50);

      if (window.PCWizard && typeof window.PCWizard.render === 'function') try{ window.PCWizard.render(); }catch(e){}
      return results;
    }catch(e){ console.error('onCalculate error', e); alert('Error al calcular: ' + (e.message || e)); throw e; }
  }

  // Modal HTML summary
  function showSummaryHtmlModal(title, htmlContent){
    let root = document.getElementById('pc_summary_modal');
    if (!root){ root = document.createElement('div'); root.id = 'pc_summary_modal'; root.innerHTML = `
      <div class="modal" tabindex="-1">
        <div class="modal-dialog modal-lg modal-dialog-centered">
          <div class="modal-content">
            <div class="modal-header"><h5 class="modal-title">${escapeHtml(title)}</h5></div>
            <div class="modal-body" id="pc_summary_html_body"></div>
            <div class="modal-footer"><button class="btn btn-sm btn-primary" data-close>OK</button></div>
          </div>
        </div>
      </div>`; document.body.appendChild(root); root.querySelector('[data-close]').addEventListener('click', hideSummaryModal); }
    root.querySelector('#pc_summary_html_body').innerHTML = htmlContent; const modalEl = root.querySelector('.modal'); modalEl.classList.add('show'); modalEl.style.display = 'block'; const bd = document.createElement('div'); bd.className='modal-backdrop fade show'; bd.id='pc_summary_backdrop'; document.body.appendChild(bd);
  }
  function hideSummaryModal(){ const root = document.getElementById('pc_summary_modal'); if (!root) return; const modalEl = root.querySelector('.modal'); modalEl.classList.remove('show'); modalEl.style.display='none'; const bd=document.getElementById('pc_summary_backdrop'); if(bd)bd.remove(); }

  // Modal detalle por persona
  function showPersonDetailsModal(entry){
    if (!entry) return; let root = document.getElementById('pc_person_modal');
    if (!root){ root = document.createElement('div'); root.id = 'pc_person_modal'; root.innerHTML = `
      <div class="modal" tabindex="-1">
        <div class="modal-dialog modal-lg modal-dialog-centered">
          <div class="modal-content">
            <div class="modal-header"><h5 class="modal-title">Detalles: <span id="pc_person_name"></span></h5></div>
            <div class="modal-body"><div id="pc_person_rows"></div></div>
            <div class="modal-footer"><button class="btn btn-sm btn-secondary" data-close>Cancelar</button><button class="btn btn-sm btn-primary" id="pc_person_apply">Aplicar</button></div>
          </div>
        </div>
      </div>`; document.body.appendChild(root);
      root.querySelector('[data-close]').addEventListener('click', hidePersonModal);
      root.querySelector('#pc_person_apply').addEventListener('click', async ()=>{
        const checks = Array.from(root.querySelectorAll('.pc-person-row-check')).map(ch=> ({ json: ch.getAttribute('data-pc-keyids'), checked: ch.checked, el: ch }));
        // preparar firmas normalizadas para las filas marcadas como checked
        const signatures = [];
        checks.forEach(c=>{
          if (!c.checked) return;
          try{ const keyIds = JSON.parse(c.json||'[]');
            // para cada keyId obtener la firma normalizada desde el mapa global
            keyIds.forEach(kid => { const s = window.PCRowSignaturesNormalized && window.PCRowSignaturesNormalized[kid]; if (s) signatures.push(s); });
          }catch(e){ console.warn('invalid json', e); }
        });

        if (signatures.length === 0){
          // sólo propagar al DOM si no se envía nada al backend
          checks.forEach(c=>{ try{ const keyIds = JSON.parse(c.json||'[]'); keyIds.forEach(k=>{ const mainChk = document.querySelector(`.pc-justificado[data-pc-keyid="${k}"]`); if (mainChk) mainChk.checked = !!c.checked; }); }catch(e){} });
          hidePersonModal();
          return;
        }

        try{
          const resp = await fetch('../../backend/api/incidencias/justificar_incidencias.php', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ signatures: Array.from(new Set(signatures)) }) });
          const json = await resp.json();
          if (!resp.ok) throw new Error(json.message || json.error || 'Error en justificación');
          // marcar checkboxes y actualizar columna Resultado en la tabla principal (DOM only)
          // json should contain list of updated count and pk_column; we will mark by matching signature map
          const updatedSigs = Array.from(new Set(signatures));
          // por cada signature buscar keyIds y marcar
          updatedSigs.forEach(s=>{
            Object.keys(window.PCRowSignaturesNormalized || {}).forEach(kid=>{
              if (window.PCRowSignaturesNormalized[kid] === s){
                const mainChk = document.querySelector(`.pc-justificado[data-pc-keyid="${kid}"]`);
                if (mainChk) mainChk.checked = true;
                // también actualizar celda Resultado en la misma fila si existe
                const tr = document.querySelector(`tr[data-pc-keyid="${kid}"]`);
                if (tr){
                  // buscar columna que contenga 'Resultado' en el header
                  const ths = Array.from(tr.parentNode.parentNode.querySelectorAll('thead th'));
                  let idx = -1;
                  ths.forEach((th, i)=>{ if (th.textContent.trim().toLowerCase() === 'resultado') idx = i; });
                  if (idx >= 0){ const tds = tr.querySelectorAll('td'); if (tds[idx]) tds[idx].textContent = 'Justificado RRHH'; }
                }
              }
            });
          });

        }catch(e){ console.error('Error justificando en backend', e); alert('Error al justificar: ' + (e.message||e)); }

        hidePersonModal();
      }); }
    root.querySelector('#pc_person_name').textContent = entry.nombre;
    const rowsContainer = root.querySelector('#pc_person_rows');
    // Mostrar sólo filas relevantes para el cálculo: retardo (diffMin>0), falta (diffMin>=10), sin tiempo (diffMin===null)
    // y casos explícitos como 'HORARIO NO ENCONTRADO'. Omitir filas con diffMin<=0 o Resultado == 'OK'.
    const relevant = (entry.rows || []).filter(rr => {
      try{
        if (rr.note && String(rr.note).trim().toUpperCase() === 'HORARIO NO ENCONTRADO') return true;
        const diff = rr.diffMin;
        if (diff === null) return true; // sin tiempo
        if (typeof diff === 'number') return diff > 0; // retardo o falta
        return false;
      }catch(e){ return false; }
    });
    if (!relevant || relevant.length === 0){
      rowsContainer.innerHTML = '<div class="text-muted">No hay filas relevantes para el cálculo en esta persona.</div>';
    } else {
      const listHtml = relevant.map(rr=>{
        const t = escapeHtml(rr.raw.tacloud || rr.raw.Tacloud || rr.raw.Taclock || rr.raw.taclock || '');
        const h = escapeHtml(rr.raw.horario || rr.raw.Horario || rr.raw.hora || '');
        const res = escapeHtml(rr.raw.resultado || rr.raw.Resultado || '');
        const inc = escapeHtml(rr.raw.incidencias || rr.raw.Incidia || rr.raw.incidia || rr.raw.incidencia || '');
        const keyIdsJson = escapeHtml(JSON.stringify(rr.keyIds || []));
        const preChecked = (rr.keyIds || []).some(k=>{ const main = document.querySelector(`.pc-justificado[data-pc-keyid="${k}"]`); return main && main.checked; });
        return `<div class="border rounded p-2 mb-2"><div><strong>Horario:</strong> ${h}</div><div><strong>Tacloud:</strong> ${t}</div><div><strong>Resultado:</strong> ${res}</div><div><strong>Incidencia:</strong> ${inc}</div><div class="mt-2"><label class="d-block"><input type="checkbox" class="pc-person-row-check" data-pc-keyids='${keyIdsJson}' ${preChecked? 'checked':''}> Justificar</label></div></div>`;
      }).join('');
      rowsContainer.innerHTML = listHtml;
    }
    const modalEl = root.querySelector('.modal'); modalEl.classList.add('show'); modalEl.style.display='block'; const bd = document.createElement('div'); bd.className='modal-backdrop fade show'; bd.id='pc_person_backdrop'; document.body.appendChild(bd);
  }
  function hidePersonModal(){ const root = document.getElementById('pc_person_modal'); if (!root) return; const modalEl = root.querySelector('.modal'); modalEl.classList.remove('show'); modalEl.style.display='none'; const bd = document.getElementById('pc_person_backdrop'); if (bd) bd.remove(); }

  // Registrar módulo
  function register(){ if (window.PCWizard && typeof window.PCWizard.registerModule === 'function'){ window.PCWizard.registerModule('incidencias', { render, getData, onFinish, onCalculate }); if (typeof window.PCWizard.render === 'function') try{ window.PCWizard.render(); }catch(e){} } else setTimeout(register, 200); }
  register();

  // Exponer helper para debugging
  window.PCIncidencias = { loadItems };

})();
