/**
 * Fichier  : assets/js/pages/lots.js
 * Auteur   : KREMER Régis
 * Version  : 2.6.86
 * Date     : 2026-07-20
 * Description : Lots et traçabilité — liste, blocage et historique.
 *
 * Changelog :
 *   v2.6.86 (2026-07-20) — CRUD MOBILE CARDS10 : motif de blocage accessible et historique mobile en chronologie.
 */
(function(){
  function qs(sel, root){ return (root||document).querySelector(sel); }
  function qsa(sel, root){ return Array.from((root||document).querySelectorAll(sel)); }
  function esc(s){ return (s||'').toString().replace(/[&<>"']/g, m=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[m])); }
  function fmtDate(d){ if(!d) return ''; return d.toString().slice(0,10).split('-').reverse().join('/'); }

  async function api(url, opts){
    const o = opts||{};
    o.headers = Object.assign({ 'X-Requested-With':'XMLHttpRequest' }, o.headers||{});
    // CSRF
    const csrf = window.__CSRF_TOKEN__ || '';
    if(o.method && o.method !== 'GET') o.headers['X-CSRF-Token'] = csrf;

    const endpoint = (window.Api && typeof window.Api.url === 'function') ? window.Api.url(url) : url;
    const r = await fetch(endpoint, o);
    const j = await r.json().catch(()=>({}));
    if(!r.ok) throw new Error(j.error || ('HTTP '+r.status));
    return j;
  }

  function openModal(id){
    const m = qs(id);
    if(!m) return;
    m.setAttribute('aria-hidden','false');
    m.classList.add('is-open');
  }
  function closeModal(el){
    const m = el.closest('.modal');
    if(!m) return;
    m.setAttribute('aria-hidden','true');
    m.classList.remove('is-open');
  }

  async function loadWarehouses(){
    const sel = qs('#lotsWarehouse');
    if(!sel) return;
    const w = await api('api/warehouses.php');
    const list = Array.isArray(w) ? w : (w.items||[]);
    sel.innerHTML = '<option value="">Tous</option>' + list.map(x=>`<option value="${x.id}">${esc(x.name)}</option>`).join('');
  }

  async function loadLocations(warehouseId){
    const sel = qs('#lotsLocation');
    if(!sel) return;
    // locations.json is generic and not per warehouse in Lot 1 => keep simple
    const loc = await api('api/locations.php');
    sel.innerHTML = '<option value="">Tous</option>' + (loc.items||[]).map(x=>`<option value="${esc(x.id)}">${esc(x.label||x.id)}</option>`).join('');
  }

  function rowActions(item){
    const blocked = !!item.blocked;
    const btnBlock = blocked
      ? `<button class="btn btn-secondary btn-xs" data-act="unblock">Débloquer</button>`
      : `<button class="btn btn-danger btn-xs" data-act="block">Bloquer</button>`;
    return `
      <div style="display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap">
        <button class="btn btn-secondary btn-xs" data-act="history">Historique</button>
        ${btnBlock}
      </div>
    `;
  }

  function renderLots(items){
    const tb = qs('#tblLots tbody');
    if(!tb) return;
    const q = (qs('#lotsSearch')?.value || '').trim().toLowerCase();
    const filtered = (items||[]).filter(it=>{
      if(!q) return true;
      const s = `${it.productName||''} ${it.lotNumber||''} ${it.expiryDate||''} ${it.locationId||''}`.toLowerCase();
      return s.includes(q);
    });

    tb.innerHTML = filtered.map(it=>{
      const blocked = !!it.blocked;
      return `
        <tr data-pid="${it.productId}" data-wid="${it.warehouseId}" data-loc="${esc(it.locationId)}" data-lot="${esc(it.lotNumber)}" data-exp="${esc(it.expiryDate||'')}">
          <td>${esc(it.productName||'')}</td>
          <td><code>${esc(it.lotNumber||'')}</code></td>
          <td>${esc(fmtDate(it.expiryDate||''))}</td>
          <td>${(it.quantity||0)}</td>
          <td>${esc(it.locationId||'default')}</td>
          <td>${blocked ? `<span class="badge badge-danger" title="${esc(it.blockReason||'')}">Oui</span>` : `<span class="badge">Non</span>`}</td>
          <td>${rowActions(it)}</td>
        </tr>
      `;
    }).join('');
  }

  let cacheLots = [];

  async function reloadLots(){
    const wid = qs('#lotsWarehouse')?.value || '';
    const loc = qs('#lotsLocation')?.value || '';

    const url = new URL((window.Api && Api.url ? Api.url('api/lots.php') : 'api/lots.php'), window.location.origin);
    if(wid) url.searchParams.set('warehouseId', wid);
    if(loc) url.searchParams.set('locationId', loc);

    const j = await api(url.toString());
    cacheLots = j.items || [];
    renderLots(cacheLots);
  }

  function requestBlockReason(lot){
    return new Promise(resolve=>{
      let settled=false;
      const finish=(value)=>{
        if(settled) return;
        settled=true;
        Modal.close();
        resolve(value);
      };
      Modal.show('Bloquer le lot', `
        <label class="lbl" for="lotBlockReason">Motif du blocage *</label>
        <textarea class="inp" id="lotBlockReason" rows="4" maxlength="500" placeholder="Expliquez pourquoi le lot ${esc(lot)} ne doit plus être utilisé."></textarea>
        <p class="text-muted" style="margin-top:8px">Le motif restera visible dans la traçabilité.</p>`, [
        {label:'Annuler', cls:'btn-secondary', onclick:()=>finish(null)},
        {label:'Bloquer', cls:'btn-danger', onclick:()=>{
          const input=qs('#lotBlockReason');
          const value=(input?.value||'').trim();
          if(!value){ input?.focus(); toast('Motif obligatoire.','error'); return; }
          finish(value);
        }}
      ], 'warning');
      Modal.onClose?.(()=>{ if(!settled) resolve(null); });
    });
  }

  async function toggleBlock(tr, blocked){
    const pid = tr.getAttribute('data-pid');
    const wid = tr.getAttribute('data-wid');
    const loc = tr.getAttribute('data-loc');
    const lot = tr.getAttribute('data-lot');
    const exp = tr.getAttribute('data-exp');
    let reason = '';
    if(blocked){
      reason = await requestBlockReason(lot);
      if(reason===null) return;
    }
    await api('api/lots.php', {
      method:'POST',
      headers:{'Content-Type':'application/json'},
      body: JSON.stringify({ productId: +pid, warehouseId:+wid, locationId:loc, lotNumber:lot, expiryDate:exp, blocked: blocked, reason })
    });
    toast(blocked ? 'Lot bloqué.' : 'Lot débloqué.', 'success');
    await reloadLots();
  }

  async function openHistory(tr){
    const pid = tr.getAttribute('data-pid');
    const wid = tr.getAttribute('data-wid');
    const lot = tr.getAttribute('data-lot');
    const exp = tr.getAttribute('data-exp');

    const url = new URL((window.Api && Api.url ? Api.url('api/lots.php') : 'api/lots.php'), window.location.origin);
    url.searchParams.set('history','1');
    url.searchParams.set('productId', pid);
    url.searchParams.set('warehouseId', wid);
    url.searchParams.set('lotNumber', lot);
    if(exp) url.searchParams.set('expiryDate', exp);

    const j = await api(url.toString());
    const title = `Historique — Lot ${lot}${exp?(' / '+fmtDate(exp)):''}`;
    const items = j.items||[];
    const rows = items.map(x=>{
      const dt = (x.date||'').replace('T',' ').slice(0,19);
      return `
        <tr>
          <td>${esc(dt)}</td>
          <td>${esc(x.type||'')}</td>
          <td>${(x.quantity||0)}</td>
          <td>${esc(x.locationId||'')}</td>
          <td>${esc((x.site||'') + (x.operator?(' — '+x.operator):''))}</td>
        </tr>`;
    }).join('') || '<tr><td colspan="5" class="text-muted">Aucun historique.</td></tr>';
    const timeline = items.length ? `<div class="lot-history-timeline">${items.map(x=>{
      const dt=(x.date||'').replace('T',' ').slice(0,19);
      return `<article class="lot-history-item">
        <div class="lot-history-item__head"><strong>${esc(x.type||'Mouvement')}</strong><time>${esc(dt)}</time></div>
        <dl><div><dt>Quantité</dt><dd>${x.quantity||0}</dd></div><div><dt>Emplacement</dt><dd>${esc(x.locationId||'—')}</dd></div></dl>
        ${x.site||x.operator?`<p>${esc((x.site||'')+(x.operator?(' — '+x.operator):''))}</p>`:''}
      </article>`;
    }).join('')}</div>` : '<p class="text-muted">Aucun historique.</p>';

    if(typeof Modal !== 'undefined' && Modal.open){
      const touch=Math.max(window.visualViewport?.width||window.innerWidth||0,1)<1200;
      Modal.show({
        title,
        sub: 'Entrées, sorties, transferts et blocages.',
        icon: 'clock',
        html: touch ? timeline : `
          <div class="table-container" style="max-height:60vh;overflow:auto">
            <table class="data-table">
              <thead>
                <tr>
                  <th style="width:170px">Date</th>
                  <th style="width:110px">Type</th>
                  <th style="width:120px">Qté</th>
                  <th style="width:160px">Emplacement</th>
                  <th>Site / Opérateur</th>
                </tr>
              </thead>
              <tbody>${rows}</tbody>
            </table>
          </div>`
      });
    } else {
      alert('Modal non disponible.');
    }
  }

  function bind(){
    const root = qs('#pgLots');
    if(!root) return;

    qs('#btnLotsReload')?.addEventListener('click', reloadLots);
    qs('#lotsSearch')?.addEventListener('input', ()=>renderLots(cacheLots));
    qs('#lotsWarehouse')?.addEventListener('change', async()=>{ await loadLocations(qs('#lotsWarehouse').value); await reloadLots(); });
    qs('#lotsLocation')?.addEventListener('change', reloadLots);

    qs('#tblLots')?.addEventListener('click', async(e)=>{
      const btn = e.target.closest('button[data-act]');
      if(!btn) return;
      const tr = btn.closest('tr');
      const act = btn.getAttribute('data-act');
      try{
        if(act==='history') await openHistory(tr);
        if(act==='block') await toggleBlock(tr, true);
        if(act==='unblock') await toggleBlock(tr, false);
      }catch(err){
        toast(err.message||String(err), 'error');
      }
    });

    (async()=>{
      try{
        await loadWarehouses();
        await loadLocations('');
        await reloadLots();
      }catch(e){
        console.error(e);
      }
    })();
  }

  // Compat: allow App.dispatchPage('lots')
  window.LotsPage = { init: bind };
  document.addEventListener('DOMContentLoaded', bind);
})();
