// ---------- 11 Reliquat xdockPlus → www.gp-eff.fr (nouvelle app My Truck / GP) ----------
// Version révisée pour pointer vers la nouvelle API FastAPI (server.py)
// au lieu de l'ancien gp-eff.alwaysdata.net/reliquat.php
//
// 3 choses ont changé par rapport à l'ancien :
//  - Les URL pointent vers https://www.gp-eff.fr/api/gp/xdock-plus/*
//  - Une constante XDP_KEY est ajoutée
//  - xdpFetchViaBridge() injecte automatiquement le header X-XDockPlus-Key
// ----------------------------------------------------------------------------
(function () {
  "use strict";

  // ✅ Activation / désactivation via API (XDP_FEATURES ou data-xdp-features)
  function xdpReadFeatures() {
    if (window.XDP_FEATURES && typeof window.XDP_FEATURES === "object") {
      return window.XDP_FEATURES;
    }
    const raw = document.documentElement?.dataset?.xdpFeatures || "";
    if (raw) { try { return JSON.parse(raw); } catch (e) {} }
    return {};
  }
  function xdpIsOn(v) { return v === true || v === 1 || v === "1" || v === "true"; }
  const FEATURES = xdpReadFeatures();
  if (!xdpIsOn(FEATURES.reliquats)) return;

  // 🔧 1. Nouvelle base + clé d'auth de l'extension
  const GP_BASE          = "https://www.gp-eff.fr";   // ou "https://gp-eff.fr"
  const XDP_KEY          = "xdockplus"; // ⚠️ doit matcher XDOCKPLUS_API_KEY du backend NAS
  const ENDPOINT_POST    = GP_BASE + "/api/gp/xdock-plus/reliquat";
  const ENDPOINT_MOTIFS  = GP_BASE + "/api/gp/xdock-plus/motifs";
  const ENDPOINT_USERS   = GP_BASE + "/api/gp/xdock-plus/users";
  const ENDPOINT_RESOLVE = GP_BASE + "/api/gp/xdock-plus/resolve-user";

  const Q  = (s,r=document)=>r.querySelector(s);
  const QA = (s,r=document)=>Array.from(r.querySelectorAll(s));
  const wait = (ms)=>new Promise(r=>setTimeout(r,ms));
  const el = (tag, attrs={}, children=[]) => {
    const x=document.createElement(tag);
    Object.entries(attrs).forEach(([k,v])=>{
      if(k==="text") x.textContent=v;
      else if(k==="html") x.innerHTML=v;
      else if(k==="class") x.className=v;
      else if(v===true) x.setAttribute(k,k);
      else if(v!==false && v!=null) x.setAttribute(k,v);
    });
    children.forEach(c=>x.appendChild(c));
    return x;
  };
  const norm = s => (s||"").toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/\s+/g," ").trim();
  const last4 = s => { const d=String(s||"").replace(/\D/g,""); return d.length>=4 ? d.slice(-4) : d; };

  const WANT = {
    fournisseur: t => /(fournisseur|lieferant|supplier)/.test(t),
    gtin:        t => /(gtin|ean)/.test(t),
    ref:         t => /(reference|référence|klstb)/.test(t),
    poids:       t => /(poids|gewicht)/.test(t),
    ls:          t => /(n|nr)[ ]?ls/.test(t)
  };

  // ===== Activation / désactivation via xdockPlus_settings =====
  const STORAGE_KEY = "xdockPlus_settings";
  const MODULE_KEY  = "reliquatGP";

  function loadSettings() {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      if (!raw) return {};
      const parsed = JSON.parse(raw);
      return (parsed && typeof parsed === "object") ? parsed : {};
    } catch (e) { return {}; }
  }

  let ACTIVE = true;
  (function initActivation() {
    const st = loadSettings();
    if (Object.prototype.hasOwnProperty.call(st, MODULE_KEY)) ACTIVE = !!st[MODULE_KEY];
    else ACTIVE = true;
    console.log("[XDock+ Reliquats] État initial :", ACTIVE ? "ON" : "OFF");
  })();

  function isActive() { return ACTIVE === true; }

  window.addEventListener("xdockPlusSettingsChanged", function (ev) {
    const st   = (ev && ev.detail && typeof ev.detail === "object") ? ev.detail : loadSettings();
    const prev = ACTIVE;
    ACTIVE     = st[MODULE_KEY] !== false;
    console.log("[XDock+ Reliquats] Changement réglages :", ACTIVE ? "ON" : "OFF");
    if (ACTIVE && !prev) inject();
  });

  // ==========================================================
  // CSP-safe fetch via bridge XDP_FETCH_REQ (installé par xdp_loader.js)
  // 🔧 2. Le helper rajoute automatiquement la clé X-XDockPlus-Key
  // ==========================================================
  const __xdpFetchWaiters = new Map();
  let __xdpFetchRid = 0;

  function xdpFetchViaBridge(url, options = {}, timeoutMs = 15000) {
    return new Promise((resolve, reject) => {
      const rid = "r" + (++__xdpFetchRid) + "_" + Date.now();
      const timer = setTimeout(() => {
        __xdpFetchWaiters.delete(rid);
        reject(new Error("XDP_FETCH timeout"));
      }, timeoutMs);
      __xdpFetchWaiters.set(rid, (resp) => {
        clearTimeout(timer);
        __xdpFetchWaiters.delete(rid);
        resolve(resp);
      });
      // 🔧 Injecte la clé d'auth dans toutes les requêtes vers GP_BASE
      const opts = Object.assign({}, options);
      opts.headers = Object.assign(
        { "X-XDockPlus-Key": XDP_KEY, "Accept": "application/json" },
        options.headers || {}
      );
      window.postMessage({ type: "XDP_FETCH_REQ", rid, url, options: opts }, "*");
    });
  }

  window.addEventListener("message", (ev) => {
    try {
      if (!ev || ev.source !== window) return;
      const d = ev.data;
      if (!d || d.type !== "XDP_FETCH_RES" || !d.rid) return;
      const cb = __xdpFetchWaiters.get(d.rid);
      if (cb) cb(d);
    } catch (e) {}
  }, false);

  async function xdpFetchJSON(url, options = {}) {
    const r = await xdpFetchViaBridge(url, options);
    if (!r || r.ok !== true) {
      // En cas d'erreur HTTP, on tente quand même de parser pour récupérer le "detail"
      // (utile pour le 409 anti-doublon SSCC)
      try { return r && r.text ? JSON.parse(r.text) : null; } catch(e) { return null; }
    }
    const txt = String(r.text || "");
    if (!txt) return null;
    try { return JSON.parse(txt); } catch (e) { return null; }
  }

  /* ---------- CSS (modale) ---------- */
  (function injectCSS(){
    if (document.getElementById("gp-ux-css")) return;
    const style=document.createElement("style"); style.id="gp-ux-css";
    style.textContent=`
      .gp-modal-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:2147483000;display:flex;align-items:center;justify-content:center}
      .gp-modal{background:#fff;border-radius:12px;max-width:920px;width:92%;box-shadow:0 20px 60px rgba(0,0,0,.25);overflow:hidden}
      .gp-modal-h{padding:14px 18px;border-bottom:1px solid #e5e7eb;display:flex;justify-content:space-between;align-items:center;gap:10px}
      .gp-modal-t{font-weight:700;font-size:16px}
      .gp-modal-right{display:flex;align-items:center;gap:8px}
      .gp-modal-c{padding:14px 18px;max-height:60vh;overflow:auto}
      .gp-modal-f{padding:12px 18px;border-top:1px solid #e5e7eb;display:flex;justify-content:flex-end;align-items:center;gap:8px}
      .gp-row{display:flex;gap:12px;align-items:flex-start;margin-bottom:12px;flex-wrap:wrap}
      .gp-row label{min-width:62px;font-weight:600}
      .gp-help{font-size:12px;color:#6b7280}
      .gp-sscc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px}
      .gp-pill{display:flex;align-items:center;gap:12px;border:1px solid #d1d5db;border-radius:12px;padding:12px 14px;background:#fff}
      .gp-pill label{font-family:ui-monospace, Menlo, Consolas, monospace;font-size:14px;letter-spacing:.2px}
      .gp-select{min-width:260px;padding:6px 10px;border:1px solid #d1d5db;border-radius:8px;background:#fff}
      .gp-input{padding:6px 10px;border:1px solid #d1d5db;border-radius:8px;background:#fff}
      .gp-btn{border:1px solid #c7ccd5;background:#fff;border-radius:8px;padding:8px 14px;cursor:pointer}
      .gp-btn:hover{background:#f3f4f6}
      .gp-btn.primary{background:#2563eb;border-color:#2563eb;color:#fff}
    `;
    document.head.appendChild(style);
  })();

  /* ---------- Table / colonnes ---------- */
  function findMainTable(){
    for(const t of QA("table")){
      const heads=QA("thead th, thead td", t).map(th=>norm(th.textContent));
      if(heads.some(h=>WANT.fournisseur(h)) && heads.some(h=>WANT.gtin(h)) && heads.some(h=>WANT.ref(h)) && heads.some(h=>WANT.poids(h))){
        return t;
      }
    }
    return null;
  }
  function colIndex(t, wantFn){
    const ths=QA("thead th, thead td", t);
    for(let i=0;i<ths.length;i++){ if(wantFn(norm(ths[i].textContent))) return i; }
    return -1;
  }
  function findRefHeaderCell(table){
    const headRow = Q("thead tr:last-child", table) || Q("thead tr", table);
    if (!headRow) return null;
    return headRow.querySelector("th.col-referenz") ||
           Array.from(headRow.children).find(th => /référence/i.test(th.textContent||"")) || null;
  }
  function findPalColumnIndex(table){
    const headRow = table.querySelector("thead tr:last-child") || table.querySelector("thead tr");
    if(!headRow) return -1;
    const ths = Array.from(headRow.children);
    let idx = ths.findIndex(th => String(th.textContent||"").trim() === "PAL");
    if (idx >= 0) return idx;
    idx = ths.findIndex(th => {
      const sp = th.querySelector("span");
      return sp && String(sp.textContent||"").trim() === "PAL";
    });
    if (idx >= 0) return idx;
    idx = ths.findIndex(th => {
      const sp = th.querySelector("span[data-original-title], span[title]");
      const tt = (sp?.getAttribute("data-original-title") || sp?.getAttribute("title") || "").toLowerCase();
      return tt.includes("palettes") || tt.includes("nombre de palettes") || /\bpal\b/.test(tt);
    });
    if (idx >= 0) return idx;
    return colIndex(table, t => /\bpal(ettes)?\b/.test(t));
  }
  function getPalCountForRow(tr, idx){
    const parseFirstInt = (s) => {
      const m = String(s||"").match(/(\d+)/);
      if (!m) return NaN;
      const n = parseInt(m[1], 10);
      return Number.isFinite(n) ? n : NaN;
    };
    const palletSpan = tr.querySelector(
      "span[data-original-title*='CHEP'],span[data-original-title*='LPR'],span[data-original-title*='IPP'],span[data-original-title*='PreTurn'],span[data-original-title*='Einweg']"
    );
    if (palletSpan) {
      let n = parseFirstInt(palletSpan.textContent);
      if (n > 0) return n;
      n = parseFirstInt(palletSpan.getAttribute("data-original-title"));
      if (n > 0) return n;
    }
    try{
      if (idx.pal != null && idx.pal >= 0) {
        const td = tr.children[idx.pal];
        if (td) {
          let n = parseFirstInt(td.getAttribute('data-value') || td.getAttribute('title') || td.textContent);
          if (n > 0) return n;
          const v1 = td.querySelector('input,select');
          if (v1) {
            n = parseFirstInt(v1.value || v1.textContent);
            if (n > 0) return n;
          }
        }
      }
    }catch(_){}
    const anySpan = tr.querySelector("span[data-original-title]");
    if (anySpan) {
      const txt = (anySpan.textContent || anySpan.getAttribute("data-original-title") || "");
      const n = parseFirstInt(txt);
      if (n > 0) return n;
    }
    return 1;
  }
  function retargetToNativeFiliale(table){
    QA("tbody tr", table).forEach(tr=>{
      const nativeCb = tr.querySelector('input[type="checkbox"][name$=".IsNachlieferung"][value="true"]');
      if (!nativeCb) return;
      if (!nativeCb.classList.contains("gp-rel")) {
        nativeCb.classList.add("gp-rel");
        nativeCb.title = "Marquer pour envoi vers Gestion Palettes";
      }
    });
  }

  /* ---------- SSCC helpers ---------- */
  function readSSCCsFromNode(node){
    const res = new Set();
    const imgs = node.querySelectorAll('img[id^="barcodeimg_"], img[src*="GetBarcodeImageGs1Code128"]');
    for (const img of imgs){
      if (img.alt && /^\d{18}$/.test(img.alt)) res.add(img.alt);
      let m = (img.getAttribute('src') || "").match(/\(00\)\s*(\d{18})/);
      if (m) res.add(m[1]);
      m = (img.getAttribute('data-modal-src') || "").match(/\(00\)\s*(\d{18})/);
      if (m) res.add(m[1]);
    }
    const text=(node.textContent||"").replace(/\s+/g," ");
    for (const m of text.matchAll(/\(00\)\s*(\d{18})/g)) res.add(m[1]);
    for (const m of text.matchAll(/\b\d{18}\b/g)) res.add(m[0]);
    return Array.from(res);
  }
  async function extractSSCCsFromRow(tr){
    let list = readSSCCsFromNode(tr);
    if (list.length) return list;
    let next = tr.nextElementSibling;
    if (next){
      list = readSSCCsFromNode(next);
      if (list.length) return list;
    }
    const plusBtn = tr.querySelector('.palettenAufklappen, [onclick*="OpenPaletten"]');
    if (plusBtn){
      plusBtn.dispatchEvent(new MouseEvent('click',{bubbles:true,cancelable:true}));
      for (let i=0;i<15;i++){
        await wait(100);
        next = tr.nextElementSibling;
        if (next){
          list = readSSCCsFromNode(next);
          if (list.length) return list;
        }
      }
    }
    return [];
  }

  /* ---------- Lecture email XDOCK ---------- */
  function getXDockEmail(){
    const rx = /\b(stb_[a-z0-9]+@xdock\.de)\b/i;
    const probes = [
      document.querySelector('.fal.fa-sign-out'),
      document.querySelector('.fa-sign-out'),
      document.querySelector('.fa-sign-out-alt')
    ].filter(Boolean);
    for (const n of probes){
      const cands = [
        n.getAttribute('data-original-title'),
        n.getAttribute('title'),
        n.getAttribute('aria-label'),
        n.textContent
      ].filter(Boolean);
      for (const raw of cands){
        const s = String(raw).replace(/logout/ig,' ');
        const m = s.match(rx);
        if (m) return m[1].toLowerCase();
      }
    }
    const txt = (document.body.innerText||"").replace(/logout/ig,' ');
    const m2 = txt.match(rx);
    return m2 ? m2[1].toLowerCase() : "";
  }

  /* ---------- 🔧 3. Chargement Motifs / Users / Resolve via NOUVELLE API ---------- */
  async function loadMotifs(){
    try{
      const j = await xdpFetchJSON(ENDPOINT_MOTIFS, { method:"GET" });
      if (j && j.ok && Array.isArray(j.motifs)) return j.motifs;
    }catch(e){}
    return ["Autre"];
  }
  async function loadUsers(){
    try{
      const j = await xdpFetchJSON(ENDPOINT_USERS, { method:"GET" });
      if (j && j.ok && Array.isArray(j.users)){
        return j.users.map(label => ({ label: String(label).trim() }));
      }
    }catch(e){}
    return [];
  }
  async function resolveUsernameByEmail(emailXdock){
    if (!emailXdock) return "";
    try{
      const j = await xdpFetchJSON(
        ENDPOINT_RESOLVE + "?email=" + encodeURIComponent(emailXdock),
        { method:"GET" }
      );
      if (j && j.ok && j.username) return String(j.username);
    }catch(e){}
    return "";
  }

  let USERS_CACHE = null;

  function setSelectValueByLabel(selectEl, wantedLabel){
    if (!selectEl || !wantedLabel) return false;
    for (const opt of selectEl.options){
      if (String(opt.textContent||"").trim().toLowerCase() === String(wantedLabel).trim().toLowerCase()){
        opt.selected = true;
        return true;
      }
    }
    return false;
  }

  /* ---------- Enregistrer XDock ---------- */
  function saveXDockPage(){
    const form = document.getElementById("postform") ||
                 document.querySelector('form#postform') ||
                 document.querySelector('form[action*="Warenausgang"], form[action*="WaTour"]');
    if (form) {
      if (typeof form.requestSubmit === "function") form.requestSubmit();
      else {
        const submit = form.querySelector('button[type="submit"], input[type="submit"]');
        if (submit) submit.click(); else form.submit();
      }
      return true;
    }
    const btn = Array.from(document.querySelectorAll("button, a"))
      .find(b => /(enregistrer|speichern|save|sichern)/i.test(b.textContent||""));
    if (btn){ btn.click(); return true; }
    return false;
  }

  /* ---------- Modale ---------- */
  function showSSCCModal(ssccList, motifs, tr, currentMotif, table, idx){
    if (!isActive()) return;
    const bd = el("div",{class:"gp-modal-backdrop"});
    const box= el("div",{class:"gp-modal"});
    const h  = el("div",{class:"gp-modal-h"});
    const t  = el("div",{class:"gp-modal-t",text:"Sélection des palettes (SSCC) & Motifs"});
    const right = el("div",{class:"gp-modal-right"});
    const nameLab = el("span",{text:"Nom :"});
    const nameSel = el("select",{class:"gp-input",style:"min-width:260px"});
    nameSel.append(el("option",{value:"",text:"— Sélectionner —"}));
    if (Array.isArray(USERS_CACHE)) USERS_CACHE.forEach(u=> nameSel.append(el("option",{value:u.label, text:u.label})));
    if (tr.dataset.gpUser) nameSel.value = tr.dataset.gpUser;
    (async ()=>{
      if (tr.dataset.gpUser) return;
      const email = getXDockEmail();
      if (!email) return;
      const userLabel = await resolveUsernameByEmail(email);
      if (userLabel) setSelectValueByLabel(nameSel, userLabel);
    })();
    right.append(nameLab, nameSel);
    h.append(t, right);

    const c  = el("div",{class:"gp-modal-c"});
    const rMot = el("div",{class:"gp-row"});
    rMot.append(el("label",{text:"Motifs"}));
    let selectedMotifs = [];
    if (tr.dataset.gpMotifs) {
      try { selectedMotifs = JSON.parse(tr.dataset.gpMotifs) || []; } catch(e){}
    } else if (currentMotif) {
      selectedMotifs = currentMotif.split(/\s*-\s*/).filter(Boolean);
    }
    const selMot = el("select",{class:"gp-select", multiple:true, size: Math.min(8, Math.max(4, motifs.length))});
    const selSet = new Set(selectedMotifs.map(v => String(v).trim().toLowerCase()));
    motifs.forEach(m=>{
      const opt = el("option",{value:m, text:m});
      if (selSet.has(String(m).trim().toLowerCase())) opt.selected = true;
      selMot.append(opt);
    });
    rMot.append(selMot);
    rMot.append(el("span",{class:"gp-help",text:"Astuce : Maintiens Ctrl pour sélectionner plusieurs motifs."}));
    c.append(rMot);

    const grid = el("div",{class:"gp-sscc-grid"});
    if (!ssccList.length){
      c.append(el("div",{style:"margin:8px 0; color:#444;", text:"Aucun SSCC détecté dans cette ligne."}));
      const palCount = Math.max(1, getPalCountForRow(tr, idx));
      for (let i=1; i<=palCount; i++){
        const wrap = el("div",{class:"gp-pill"});
        const id = `gp_nosscc_${Math.random().toString(36).slice(2)}_${i}`;
        const chk = el("input",{type:"checkbox",id, checked:true});
        chk.dataset.sscc = "";
        const lab = el("label",{for:id,text:`Pas de SSCC #${i}`});
        wrap.append(chk, lab);
        grid.append(wrap);
      }
      c.append(grid);
    } else {
      ssccList.forEach((code,i)=>{
        const id=`gp_sscc_${Math.random().toString(36).slice(2)}_${i}`;
        const pill=el("div",{class:"gp-pill"});
        const chk =el("input",{type:"checkbox",id});
        chk.dataset.sscc=code; chk.checked=true;
        const lab=el("label",{for:id, text:code});
        pill.append(chk,lab); grid.append(pill);
      });
      c.append(grid);
    }

    const f  = el("div",{class:"gp-modal-f"});
    const ok = el("button",{class:"gp-btn primary",text:"Valider"});
    f.append(ok);
    box.append(h,c,f); bd.append(box); document.body.append(bd);

    ok.onclick= async ()=>{
      if (!isActive()) { bd.remove(); return; }
      const chosenMotifs = Array.from(selMot.selectedOptions).map(o=>o.value).filter(Boolean);
      if (!chosenMotifs.length){ alert("Choisis au moins un motif."); return; }
      const chosenUser = nameSel.value || "";
      if (!chosenUser){ alert("Sélectionne un nom dans la liste."); return; }
      const chosenSSCC = Array.from(grid.querySelectorAll('input[type="checkbox"]:checked')).map(i=>i.dataset.sscc);
      const noSSCC = !ssccList.length;
      if (!chosenSSCC.length){
        alert(noSSCC ? 'Coche au moins une case "Pas de SSCC".' : "Sélectionne au moins un SSCC.");
        return;
      }
      tr.dataset.gpUser        = chosenUser;
      tr.dataset.gpMotifs      = JSON.stringify(chosenMotifs);
      tr.dataset.gpMotif       = chosenMotifs.join(' - ');
      tr.dataset.gpChosenSscc  = JSON.stringify(chosenSSCC);
      tr.dataset.gpNoSSCC      = noSSCC ? "1" : "";
      tr.dataset.gpPrepared    = "1";
      await sendToGP(table, idx);
      saveXDockPage();
      bd.remove();
    };
  }

  /* ---------- Collecte + envoi ---------- */
  function findKLSTBToken(tr, refCell){
    const tryNode = (n)=>{
      const txt=(n.textContent||"").toUpperCase();
      const m = txt.match(/KLSTB([A-Z0-9_-]+)/i);
      if(m) return "KLSTB"+m[1].toUpperCase();
      return "";
    };
    if (refCell){ const v = tryNode(refCell); if (v) return v; }
    for (const td of tr.children){ const v=tryNode(td); if(v) return v; }
    const next=tr.nextElementSibling;
    if(next){
      for (const td of next.children){ const v=tryNode(td); if(v) return v; }
      for (const n of next.querySelectorAll("*")){ const v=tryNode(n); if(v) return v; }
    }
    return "";
  }
  function normalizeKLSTB(raw){
    if(!raw) return "";
    const up = raw.toUpperCase().trim();
    const m = up.match(/^KLSTB(.+)/);
    return m ? m[1] : up;
  }
  function extractFournisseurFromRow(tr, idxFournisseur){
    let node = tr.querySelector('#lieferantTd, [id*="lieferant" i]');
    if (node) {
      const txt = (node.textContent || node.getAttribute('title') || "").trim();
      if (txt) return txt;
    }
    if (idxFournisseur >= 0){
      const cell = tr.children[idxFournisseur];
      if (cell) return (cell.textContent || "").trim();
    }
    return "";
  }
  function pickFullGTINFromText(t) {
    if (!t) return "";
    let m = t.match(/\b(\d{14})\b/); if (m) return m[1];
    m = t.match(/\b(\d{13})\b/);     if (m) return m[1];
    m = t.match(/\b(\d{12})\b/);     if (m) return m[1];
    return "";
  }
  function extractFullGTINFromCell(cell){
    if (!cell) return "";
    let v = (cell.textContent || "").trim();
    let g = pickFullGTINFromText(v); if (g) return g;
    const title = cell.getAttribute("title") || "";
    g = pickFullGTINFromText(title); if (g) return g;
    const ds = cell.dataset || {};
    for (const k of Object.keys(ds)){ g = pickFullGTINFromText(String(ds[k]||"")); if (g) return g; }
    const valNode = cell.querySelector("input,span,div");
    if (valNode){
      const s1 = (valNode.value ?? valNode.textContent ?? "").trim();
      g = pickFullGTINFromText(s1); if (g) return g;
      const t1 = valNode.getAttribute("title") || "";
      g = pickFullGTINFromText(t1); if (g) return g;
      for (const a of (valNode.attributes||[])){ if (/^data-/.test(a.name)){ g = pickFullGTINFromText(a.value); if (g) return g; } }
    }
    return "";
  }
  function extractFullGTINFromRow(tr, idxGtin){
    let cell = tr.querySelector('[id*="gtin" i], [id*="ean" i]');
    if (cell){ const g = extractFullGTINFromCell(cell); if (g) return g; }
    if (idxGtin >= 0){ cell = tr.children[idxGtin]; const g2 = extractFullGTINFromCell(cell); if (g2) return g2; }
    const clone = tr.cloneNode(true);
    clone.querySelectorAll('img').forEach(img=>img.remove());
    const text = (clone.textContent || "").replace(/\s+/g," ");
    return pickFullGTINFromText(text);
  }
  function getSMNumber() {
    const h = document.querySelector("h5.xdock-head-title, h3, h1");
    if (h && /SM\s*\d+/i.test(h.textContent)) {
      const m = h.textContent.match(/SM\s*(\d+)/i);
      return m ? m[1] : "";
    }
    const url = new URL(location.href);
    if (url.searchParams.has("waTourId")) return url.searchParams.get("waTourId");
    return "";
  }
  function getDateSortie() {
    const h = document.querySelector("h5.xdock-head-title, h3, h1");
    if (h && /\d{2}\.\d{2}\.\d{4}/.test(h.textContent)) {
      return h.textContent.match(/(\d{2}\.\d{2}\.\d{4})/)[1];
    }
    return "";
  }
  function getZone() {
    const sel1 = document.querySelector('select#WeTourheader_Zone');
    if (sel1) {
      const opt = sel1.selectedOptions && sel1.selectedOptions[0];
      if (opt && opt.textContent) return opt.textContent.trim();
      if (sel1.value) return sel1.value.trim();
    }
    const sel2 = document.querySelector('select[name*="Zone"], select[id*="Zone"]');
    if (sel2) {
      const opt = sel2.selectedOptions && sel2.selectedOptions[0];
      if (opt && opt.textContent) return opt.textContent.trim();
      if (sel2.value) return sel2.value.trim();
    }
    const bsBtn = document.querySelector('button[data-id*="Zone"] .filter-option-inner-inner') ||
                  document.querySelector('button[data-id*="WeTourheader_Zone"] .filter-option-inner-inner');
    if (bsBtn && bsBtn.textContent) return bsBtn.textContent.trim();
    const lab = Array.from(document.querySelectorAll("label")).find(l=>/^\s*zone\s*$/i.test(l.textContent||""));
    if (lab) {
      const cont = lab.closest(".form-group, .row, div") || lab.parentElement;
      const txt = cont && cont.querySelector(".filter-option-inner-inner, .form-control, .form-select, span");
      if (txt && txt.textContent) return txt.textContent.trim();
    }
    return "";
  }

  async function collectCheckedRows(table, idx){
    const rows=[];
    const trs = QA("tbody tr", table);
    const sm   = getSMNumber();
    const date = getDateSortie();
    const zone = getZone();
    const commentaireGlobal = `SM: ${sm || "?"} | Départ le: ${date || "?"}`;
    const refTh = findRefHeaderCell(table);
    const headRow = Q("thead tr:last-child", table) || Q("thead tr", table);
    const headCells = Array.from(headRow ? headRow.children : []);
    const refIndex = refTh ? headCells.indexOf(refTh) : -1;

    for (let rowI=0; rowI<trs.length; rowI++){
      const tr = trs[rowI];
      const cb=tr.querySelector("input.gp-rel");
      if(!cb || !cb.checked) continue;
      if (tr.dataset.gpPrepared !== "1") continue;

      const tds=tr.children;
      const fournisseur = extractFournisseurFromRow(tr, idx.fournisseur);
      const refCell     = refIndex>=0 ? tds[refIndex] : null;
      const klstbToken  = findKLSTBToken(tr, refCell);
      const klstb       = normalizeKLSTB(klstbToken);
      const gtinFull    = extractFullGTINFromRow(tr, idx.gtin);
      const gtin4       = gtinFull ? last4(gtinFull) : "";

      let motifsArr = [];
      if (tr.dataset.gpMotifs){
        try { motifsArr = JSON.parse(tr.dataset.gpMotifs)||[]; } catch(e){}
      }
      const motifStr = motifsArr.length ? motifsArr.join(' - ') : (tr.dataset.gpMotif || "");
      if (!motifStr){
        alert(`Ligne ${rowI+1}: motif manquant.`);
        continue;
      }
      const chosenUser = tr.dataset.gpUser || "";
      let chosen = [];
      let noSSCC = tr.dataset.gpNoSSCC === "1";
      if (tr.dataset.gpChosenSscc){
        try { chosen = JSON.parse(tr.dataset.gpChosenSscc)||[]; } catch(e){}
      }
      if (!chosen.length && !noSSCC){
        let list = await extractSSCCsFromRow(tr);
        list = list.filter(x=>/^\d{18}$/.test(x));
        if (list.length===1) chosen = [list[0]];
        else {
          alert(`Ligne ${rowI+1}: SSCC manquant.`);
          continue;
        }
      }
      if (noSSCC && !chosen.length) chosen = [""];

      for (const sscc of chosen){
        rows.push({
          row: rowI+1,
          fournisseur, gtin4, klstb, sscc,
          motifsArr,
          motif: motifStr,
          commentaire: commentaireGlobal,
          zone,
          no_sscc: noSSCC,
          created_by_username: chosenUser
        });
      }
    }
    return rows;
  }

  const isValidSSCC=v=>/^\d{18}$/.test((v||"").trim());
  function validateRow(r){
    const e=[];
    if(!r.motif) e.push("Motif manquant");
    if(!r.no_sscc){
      if(r.sscc && !isValidSSCC(r.sscc)) e.push("SSCC invalide");
      if(!r.sscc) e.push("SSCC manquant");
    }
    if(!r.created_by_username) e.push("Nom non sélectionné");
    return e;
  }

  async function sendToGP(table, idx){
    if (!isActive()) return;
    const rows=await collectCheckedRows(table, idx);
    if(!rows.length){ alert("Coche au moins une ligne."); return; }
    const problems=[];
    rows.forEach(l=>{ const errs=validateRow(l); if(errs.length) problems.push(`Ligne ${l.row}: ${errs.join(", ")}`); });
    if(problems.length){ alert("Validation impossible :\n"+problems.join("\n")); return; }

    let ok=0, ko=0, msgs=[];
    for(const L of rows){
      const payload = {
        fournisseur: L.fournisseur,
        gtin:        L.gtin4,
        sscc:        L.sscc,
        klstb:       L.klstb,
        motif:       L.motif,
        motifs:      L.motifsArr,
        zone:        L.zone || "",
        commentaire: L.commentaire,
        no_sscc:     !!L.no_sscc,
        created_by_username: L.created_by_username || ""
      };
      try{
        const j = await xdpFetchJSON(ENDPOINT_POST, {
          method: "POST",
          headers: { "Content-Type":"application/json" }, // la clé X-XDockPlus-Key est rajoutée par le bridge
          body: JSON.stringify(payload)
        });
        if(j && j.ok) ok++;
        else { ko++; msgs.push((j && j.detail) ? j.detail : (j && j.error ? j.error : "Erreur inconnue")); }
      }catch(e){ ko++; msgs.push(String(e)); }
    }
    alert(`Envoyé: ${ok} / Échecs: ${ko}${msgs.length ? "\n"+msgs.join("\n") : ""}`);
  }

  /* ---------- Injection ---------- */
  async function inject(){
    if (!isActive()) return;
    const table=findMainTable(); if(!table) return;
    retargetToNativeFiliale(table);
    const idx = {
      fournisseur: colIndex(table, WANT.fournisseur),
      gtin:        colIndex(table, WANT.gtin),
      ref:         colIndex(table, WANT.ref),
      ls:          colIndex(table, WANT.ls),
      pal:         findPalColumnIndex(table)
    };
    QA("input.gp-rel", table).forEach(cb=>{
      if(cb.dataset.bound) return;
      cb.dataset.bound="1";
      cb.addEventListener("change", async ()=>{
        if (!isActive()) return;
        const tr = cb.closest("tr");
        if(!cb.checked){
          delete tr.dataset.gpChosenSscc;
          delete tr.dataset.gpMotif;
          delete tr.dataset.gpMotifs;
          delete tr.dataset.gpNoSSCC;
          delete tr.dataset.gpPrepared;
          return;
        }
        // 🔧 Recharge motifs + users à CHAQUE ouverture pour voir
        // les ajouts/modifications faits depuis l'app sans recharger XDock.
        USERS_CACHE = await loadUsers();
        const motifs = await loadMotifs();
        const list = (await extractSSCCsFromRow(tr)).filter(x=>/^\d{18}$/.test(x));
        showSSCCModal(list, motifs, tr, tr.dataset.gpMotif || "", table, idx);
      });
    });
  }

  async function bootstrap(){
    for(let i=0;i<80;i++){
      await inject();
      if(Q("input.gp-rel")) break;
      await wait(300);
    }
    const root=Q("#content")||document.body;
    new MutationObserver(()=>inject()).observe(root,{childList:true,subtree:true});
  }

  if(document.readyState!=="loading") bootstrap();
  else document.addEventListener("DOMContentLoaded", bootstrap, {once:true});
})();
