// jsap.js

// Déclaration des variables globales
let idDevisEnCours = 0;
let idDevisArchives = 0;
let panel = 'enCours';
let fkUser = 0;
let oldColorLnEnCours = '';
let oldColorLnArchives = '';
let oldIdLnEnCours;
let oldIdLnArchives;
let nbCommentChat = 0;
let selectedXmlDevis = new Set();
let searchSapTimeout = null;

const tableSortStates = new Map();

function initTableSort() {
  const allTables = document.querySelectorAll('[id^="tblDos"], [id^="tblDosArch"]');

  allTables.forEach(table => {
    const tableId = table.id;
    const headers = table.querySelectorAll('th[data-sortable="true"]');
    const tbody = table.querySelector('tbody');

    if (!tbody) return;

    if (!tableSortStates.has(tableId)) {
      tableSortStates.set(tableId, {
        originalOrder: null,
        currentSort: { column: null, direction: null }
      });
    }

    headers.forEach(header => {
      header.addEventListener('click', function() {
        const columnIndex = parseInt(this.getAttribute('data-column-index'));
        const sortType = this.getAttribute('data-sort-type');
        sortTable(tableId, columnIndex, sortType, this);
      });
    });
  });
}

function sortTable(tableId, columnIndex, sortType, headerElement) {
  const table = document.getElementById(tableId);
  const tbody = table.querySelector('tbody');
  const rows = Array.from(tbody.querySelectorAll('tr'));
  const state = tableSortStates.get(tableId);

  if (!state.originalOrder) {
    state.originalOrder = rows.slice();
  }

  const allHeaders = table.querySelectorAll('th[data-sortable="true"]');
  allHeaders.forEach(h => h.style.fontWeight = 'normal');

  let sortedRows;

  if (state.currentSort.column === columnIndex && state.currentSort.direction === 'desc') {
    sortedRows = state.originalOrder.slice();
    state.currentSort = { column: null, direction: null };
  } else {
    const direction = (state.currentSort.column === columnIndex && state.currentSort.direction === 'asc') ? 'desc' : 'asc';

    sortedRows = rows.slice().sort((a, b) => {
      const aCell = a.cells[columnIndex];
      const bCell = b.cells[columnIndex];

      if (!aCell || !bCell) return 0;

      let aValue = aCell.textContent.trim();
      let bValue = bCell.textContent.trim();

      if (sortType === 'number') {
        aValue = aValue.replace(/[^\d,.-]/g, '').replace(',', '.');
        bValue = bValue.replace(/[^\d,.-]/g, '').replace(',', '.');
        aValue = parseFloat(aValue) || 0;
        bValue = parseFloat(bValue) || 0;
        return direction === 'asc' ? aValue - bValue : bValue - aValue;
      } else if (sortType === 'date') {
        aValue = parseDateFromText(aValue);
        bValue = parseDateFromText(bValue);
        if (!aValue && !bValue) return 0;
        if (!aValue) return direction === 'asc' ? 1 : -1;
        if (!bValue) return direction === 'asc' ? -1 : 1;
        return direction === 'asc' ? aValue - bValue : bValue - aValue;
      } else {
        const comparison = aValue.localeCompare(bValue, 'fr');
        return direction === 'asc' ? comparison : -comparison;
      }
    });

    state.currentSort = { column: columnIndex, direction };
    headerElement.style.fontWeight = 'bold';
  }

  tbody.innerHTML = '';
  sortedRows.forEach(row => tbody.appendChild(row));
}

function parseDateFromText(dateText) {
  const match = dateText.match(/(\d{2})\/(\d{2})[\/\s](\d{4})/);
  if (!match) return null;
  const [, day, month, year] = match;
  return new Date(year, month - 1, day);
}

window.addEventListener('DOMContentLoaded', (event) => {
  console.log('#');

  // Initialisation des éléments utilisés
  let elCelDevisEnCours = document.getElementsByClassName('celEnCours');
  let elCelDevisArchives = document.getElementsByClassName('celArchives');
  let elBtnViewDevisEnCours = document.getElementsByClassName('btnViewDevisEnCours');
  let elBtnExportDevisEnCours = document.getElementsByClassName('btnExportDevisEnCours');
  let elBtnExportDevisXMLEnCours = document.getElementsByClassName('btnExportDevisXMLEnCours');
  let elBtnExportSelectedXML = document.querySelector('.btnExportSelectedXML');
  let elExportCheckboxes = document.getElementsByClassName('exportXMLCheckbox');

  let elBtnImportPDFEnCours = document.getElementsByClassName('btnImportPDFEnCours');
  let elBtnUploadPDF = document.getElementById('btnUploadPDF');
  let elBtnClosePDF = document.getElementById('btnClosePDF');
  let elBtnDeleteDevis = document.getElementsByClassName('btnDeleteDevis');
  let elBtnViewDevisArchives = document.getElementsByClassName('btnViewDevisArchives');
  let elChatBtnSendEnCours = document.getElementById('chatBtnSendEnCours');
  let elBtnSaveComment = document.getElementById('btnSaveComment');

  let elBtnDevisEnvoye = document.getElementsByClassName('btnDevisEnvoye');

  // Par défaut, on n'affiche pas les chats
  document.getElementById('chat-container-enCours').style.display = 'none';
  document.getElementById('chat-container-archives').style.display = 'none';

  //! On récupère les données contextuelles propres à l'utilisateur
  fetch('/jxpost/get_context', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json;charset=utf-8',
      Accept: 'application/json;charset=utf-8',
    },
  }).then((response) => {
    const ret = response.json();
    ret.then(function (data) {
      const user = data.user;
      fkUser = user.rowid;
      const session = data.session;
    });
  });

  //! Si on clique sur l'onglet "En cours", met à jour le panel
  $('a[data-toggle="tab"]').on('show.bs.tab', function (e) {
    if ($(this).attr('href') == '#tabEnCours') {
      panel = 'enCours';
    } else if ($(this).attr('href') == '#tabArchives') {
      panel = 'archives';
    }
    console.log('panel: ' + panel);
  });

  // Fonctions
  let clickLigDevisEnCours = function () {
    panel = 'enCours';
    //! On ne fait rien si l'utilisateur clique sur le même devis
    console.log('click ligne devis en cours');
    if (this.getAttribute('data-rid') != idDevisEnCours) {
      idDevisEnCours = this.getAttribute('data-rid');

      //! On met enfin en évidence la ligne cliquée
      Array.from(elCelDevisEnCours).forEach(function (ligDevis) {
        if (ligDevis.getAttribute('data-rid') == oldIdLnEnCours) {
          ligDevis.style.backgroundColor = oldColorLnEnCours;
        } else if (ligDevis.getAttribute('data-rid') == idDevisEnCours) {
          oldColorLnEnCours = ligDevis.style.backgroundColor;
          ligDevis.style.backgroundColor = '#9bbce7';
        }
      });
      oldIdLnEnCours = idDevisEnCours;
      console.log('idDevisEnCours: ' + idDevisEnCours);

      refreshChat();
    }
  };

  let clickViewDevis = function () {
    if (panel == 'enCours') {
      idDevisEnCours = this.getAttribute('data-rid');
    } else {
      idDevisArchives = this.getAttribute('data-rid');
    }
    const idDevis = panel == 'enCours' ? idDevisEnCours : idDevisArchives;
    let chkSpeciaux = false;

    showLoading();
    // on charge les infos de l'en-tête du devis
    fetch('/jxdevis/load_devis', {
      method: 'POST',
      body: JSON.stringify({ cid: idDevis }),
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
        Accept: 'application/json;charset=utf-8',
      },
    })
      .then((response) => {
        if (!response.ok) {
          showNotification('Erreur', "Le chargement des infos de l'en-tête de ce devis n'a pas abouti", 'error');
        } else {
          const ret = response.json();
          ret
            .then(function (data) {
              fkUser = data[0].fk_user;
              idMarche = data[0].fk_marche;
              chkClientsSecteur = data[0].chk_clients_secteur;
              chkSpeciaux = data[0].chk_speciaux == '1' ? true : false;
              if (chkSpeciaux) {
                document.getElementById('panSpeciaux').classList.remove('hidden');
              } else {
                document.getElementById('panSpeciaux').classList.add('hidden');
              }
              showDevisEnTete(data);
              showDevisTotaux(data);
            })
            .then(function () {
              //! Une fois le marché trouvé, on charge les infos du marché préchargé dans l'en-tête du devis
              fetch('/jxdevis/load_devis_marche_infos', {
                method: 'POST',
                body: JSON.stringify({ cid: idMarche }),
                headers: {
                  'Content-Type': 'application/json;charset=utf-8',
                  Accept: 'application/json;charset=utf-8',
                },
              }).then((response) => {
                if (!response.ok) {
                  showNotification('Erreur', "Le chargement des infos du marché n'a pas abouti", 'error');
                } else {
                  const ret = response.json();
                  ret.then(function (data) {
                    showDevisMarcheInfos(data);
                  });
                }
              });
              if (chkSpeciaux) {
                //! On charge les infos des produits spéciaux
                fetch('/jxdevis/load_devis_speciaux', {
                  method: 'POST',
                  body: JSON.stringify({ cid: idDevis }),
                  headers: {
                    'Content-Type': 'application/json;charset=utf-8',
                    Accept: 'application/json;charset=utf-8',
                  },
                }).then((response) => {
                  if (!response.ok) {
                    showNotification('Erreur', "Le chargement des produits spéciaux de ce devis n'a pas abouti", 'error');
                  } else {
                    const retSpeciaux = response.json();
                    retSpeciaux.then(function (dataSpeciaux) {
                      // on vide les 5 lignes de produits spéciaux pour éviter de reprendre des données d'un autre devis
                      for (i = 1; i <= 5; i++) {
                        document.getElementById('inp_specialCode_' + i).value = '';
                        document.getElementById('inp_specialLibe_' + i).value = '';
                        document.getElementById('inp_specialQte_' + i).value = '';
                        document.getElementById('inp_specialCout_' + i).value = '';
                        document.getElementById('inp_chk_specialEchantillon_' + i).checked = false;
                        document.getElementById('inp_specialDate_' + i).value = '';
                        document.getElementById('inp_specialConcurrent_' + i).value = '';
                        document.getElementById('inp_specialDescription_' + i).value = '';
                      }
                      if (dataSpeciaux.length > 0) {
                        // on a trouvé une ligne dans la table devis_speciaux
                        const data = dataSpeciaux[0];
                        console.log('on a trouvé une ligne dans la table devis_speciaux');
                        console.log(data);
                        // on charge les données dans le formulaire
                        if (data.chk_livr_multi == '1') {
                          document.getElementById('inp_chk_livr_multi').checked = true;
                        } else {
                          document.getElementById('inp_chk_livr_multi').checked = false;
                        }
                        document.getElementById('inp_nb_livr').value = data.nb_livr;
                        document.getElementById('inp_date_livr_1').value = data.date_livr_1;

                        for (i = 1; i <= 5; i++) {
                          document.getElementById('inp_specialCode_' + i).value = data[`code_produit_${i}`];
                          document.getElementById('inp_specialLibe_' + i).value = data[`lib_produit_${i}`];
                          document.getElementById('inp_specialQte_' + i).value = data[`qte_${i}`];
                          document.getElementById('inp_specialCout_' + i).value = data[`surcout_${i}`];
                          if (data[`chk_echantillon_${i}`] == '1') {
                            document.getElementById('inp_chk_specialEchantillon_' + i).checked = true;
                          } else {
                            document.getElementById('inp_chk_specialEchantillon_' + i).checked = false;
                          }
                          if (data[`date_echantillon_${i}`] != '0000-00-00') {
                            document.getElementById('inp_specialDate_' + i).value = data[`date_echantillon_${i}`];
                          }
                          document.getElementById('inp_specialConcurrent_' + i).value = data[`lib_concurrent_${i}`];
                          document.getElementById('inp_specialDescription_' + i).value = data[`description_${i}`];
                        }
                      } else {
                        // on n'a pas trouvé de ligne dans la table devis_speciaux
                        console.log("on n'a pas trouvé de ligne dans la table devis_speciaux");
                        // on vide les champs du formulaire
                        document.getElementById('inp_idDevis_speciaux').value = idDevis;
                        document.getElementById('frmSpeciaux').reset();
                      }
                    });
                  }
                });
              }
            });
        }
      })
      .catch((error) => {
        showNotification('Erreur', "Le chargement des infos de l'en-tête de ce devis n'a pas abouti", 'error');
      });

    // on charge les produits enregistrés pour ce devis dans 2 tableaux distincts tblProduitsSelect (2ème onglet) et tblDevisPro (3ème onglet)
    fetch('/jxdevis/load_devis_produits', {
      method: 'POST',
      body: JSON.stringify({ cid: idDevis }),
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
        Accept: 'application/json;charset=utf-8',
      },
    }).then((response) => {
      if (!response.ok) {
        showNotification('Erreur', "Le chargement des produits de ce devis n'a pas abouti", 'error');
      } else {
        const ret = response.json();

        //! Boucle sur le résultat de la requête ajax
        ret.then(function (data) {
          showDevisProduits(data);
        });
      }
    });

    hideLoading();

    if (panel == 'enCours') {
      //! On ne fait rien si l'utilisateur clique sur le même devis
      if (this.getAttribute('data-rid') != idDevisEnCours) {
        idDevisEnCours = this.getAttribute('data-rid');

        //! On met enfin en évidence la ligne cliquée
        Array.from(elCelDevisEnCours).forEach(function (ligDevis) {
          if (ligDevis.getAttribute('data-rid') == oldIdLnEnCours) {
            ligDevis.style.backgroundColor = oldColorLnEnCours;
          } else if (ligDevis.getAttribute('data-rid') == idDevisEnCours) {
            oldColorLnEnCours = ligDevis.style.backgroundColor;
            ligDevis.style.backgroundColor = '#9bbce7';
          }
        });
        oldIdLnEnCours = idDevisEnCours;
        console.log('idDevisEnCours: ' + idDevisEnCours);
      }
    } else {
      //! On ne fait rien si l'utilisateur clique sur le même devis
      if (this.getAttribute('data-rid') != idDevisArchives) {
        idDevisArchives = this.getAttribute('data-rid');

        //! On met enfin en évidence la ligne cliquée
        Array.from(elCelDevisArchives).forEach(function (ligDevis) {
          if (ligDevis.getAttribute('data-rid') == oldIdLnArchives) {
            ligDevis.style.backgroundColor = oldColorLnArchives;
          } else if (ligDevis.getAttribute('data-rid') == idDevisArchives) {
            oldColorLnArchives = ligDevis.style.backgroundColor;
            ligDevis.style.backgroundColor = '#9bbce7';
          }
        });
        oldIdLnArchives = idDevisArchives;
        console.log('idDevisArchives: ' + idDevisArchives);
      }
    }
    refreshChat();

    document.getElementById('modViewDevisTitre').innerHTML = 'Consultation du devis n°' + idDevis;
    showModal(document.getElementById('modalViewDevis'));
  };

  document.getElementById('btnCloseModViewDevis').addEventListener('click', function () {
    hideModal(document.getElementById('modalViewDevis'));
  });

  function showDevisEnTete(ret) {
    // Affiche les données de l'en-tête du devis
    const data = ret[0];

    document.getElementById('inp_num_opportunite').value = data.num_opportunite;
    document.getElementById('inp_date_demande').value = data.date_demande;
    document.getElementById('inp_date_remise').value = data.date_remise;
    console.log(data.code);
    if (data.code === null) {
      document.getElementById('inp_lib_client').value = data.lib_new_client;
      document.getElementById('inp_type_client').value = data.type_new_client;
      document.getElementById('inp_adresse1').value = data.adresse1_new_client;
      document.getElementById('inp_adresse2').value = data.adresse2_new_client;
      document.getElementById('inp_adresse3').value = data.adresse3_new_client;
      document.getElementById('inp_cp').value = data.cp_new_client;
      document.getElementById('inp_ville').value = data.ville_new_client;
      document.getElementById('inp_contact_nom').value = data.contact_new_nom;
      document.getElementById('inp_contact_prenom').value = data.contact_new_prenom;
      document.getElementById('inp_contact_fonction').value = data.contact_new_fonction;
      document.getElementById('inp_email').value = data.new_email;
      document.getElementById('inp_telephone').value = data.new_telephone;
      document.getElementById('inp_mobile').value = data.new_mobile;
    } else {
      document.getElementById('inp_lib_client').value = data.libelle;
      document.getElementById('inp_type_client').value = data.type_client;
      document.getElementById('inp_adresse1').value = data.adresse1;
      document.getElementById('inp_adresse2').value = data.adresse2;
      document.getElementById('inp_adresse3').value = data.adresse3;
      document.getElementById('inp_cp').value = data.cp;
      document.getElementById('inp_ville').value = data.ville;
      document.getElementById('inp_contact_nom').value = data.contact_nom;
      document.getElementById('inp_contact_prenom').value = data.contact_prenom;
      document.getElementById('inp_contact_fonction').value = data.contact_fonction;
      document.getElementById('inp_email').value = data.email;
      document.getElementById('inp_telephone').value = data.telephone;
      document.getElementById('inp_mobile').value = data.mobile;
    }
    document.getElementById('inp_lib_marche').value = data.lib_marche;
    if (data.chk_devis_photos == '1') {
      document.getElementById('inp_chk_devis_photos').checked = true;
    } else {
      document.getElementById('inp_chk_devis_photos').checked = false;
    }
    document.getElementById('inp_commentaire').value = data.commentaire;
  }

  function showDevisTotaux(ret) {
    // Affiche les totaux du devis
    const data = ret[0];

    document.getElementById('inpTotalHT').value = data.montant_total_ht;
    document.getElementById('inpTotalRemHT').value = data.montant_total_ht_remise;
    document.getElementById('inpTotalMarge').value = data.marge_totale;
  }

  function showDevisMarcheInfos(ret) {
    // On affiche les infos du marché
    if (ret.length == 1) {
      let line = ret[0];
      $('#tdTxRemiseTrim').text(line.taux_remise_trimestrielle + ' %');
      $('#tdTxRemiseSeme').text(line.taux_remise_semestrielle + ' %');
      $('#tdTxRemiseAnnu').text(line.taux_remise_annuelle + ' %');
      $('#tdDebutFin').text(convertMySQLDateToFrenchDate(line.date_fin));
      $('#tdGarantie').text(line.garantie);
      $('#tdDelaiLivr').text(line.delai_de_livraison);
      $('#tdRemisesCo').text(line.remises_commerciales);
    } else {
      $('#tdTxRemiseTrim').text('-');
      $('#tdTxRemiseSeme').text('-');
      $('#tdTxRemiseAnnu').text('-');
      $('#tdDebutFin').text('-');
      $('#tdGarantie').text('-');
      $('#tdDelaiLivr').text('-');
      $('#tdRemisesCo').text('-');
    }
  }

  function showDevisProduits(ret) {
    //! On affiche les produits du devis dans le tableau tblDevisPro
    // On vide son body
    let tblBodyPro = document.getElementById('tblDevisPro').getElementsByTagName('tbody')[0];
    tblBodyPro.innerHTML = '';

    if (ret.length > 0) {
      // au moins un produit trouvé pour ce devis
      let nbProduits = ret.length;

      for (let key in ret) {
        if (ret.hasOwnProperty(key)) {
          // Récupération des valeurs de la ligne
          let val = ret[key];

          // Insertion d'une nouvelle ligne et création de ses colonnes : on prend ici le rowid de devis_produits
          let newRowPro = tblBodyPro.insertRow(0);

          let celCodePro = newRowPro.insertCell(0);
          celCodePro.innerHTML = val['code'];

          let celLibellePro = newRowPro.insertCell(1);
          celLibellePro.innerHTML = val['libelle'];

          let celPrixVentePro = newRowPro.insertCell(2);
          celPrixVentePro.className = 'text-right';
          celPrixVentePro.innerHTML = val['prix_vente'] + ' €';

          let celQtePro = newRowPro.insertCell(3);
          celQtePro.innerHTML =
            '<input type="number" class="form-control numeric" id="inpQte_' +
            val['fk_produit'] +
            '" name="inpQte_' +
            val['fk_produit'] +
            '" data-rid="' +
            val['fk_produit'] +
            '" data-achat="' +
            val['prix_achat_net'] +
            '" data-vente="' +
            val['prix_vente'] +
            '" value="' +
            val['qte'] +
            '" min="0" max="1000" step="1" style="width: 100px; text-align: right;" disabled>';

          let celRemisePro = newRowPro.insertCell(4);
          celRemisePro.innerHTML =
            '<div class="input-group"><input type="number" class="form-control numeric" id="inpRemise_' +
            val['fk_produit'] +
            '" name="inpRemise_' +
            val['fk_produit'] +
            '" data-rid="' +
            val['fk_produit'] +
            '" data-achat="' +
            val['prix_achat_net'] +
            '" data-vente="' +
            val['prix_vente'] +
            '" value="' +
            val['remise'] +
            '" min="0" max="100" step="1" style="width: 80px; text-align: right; border-color: #8DB255!important; border-width: 4px;" disabled/><div class="input-group-addon">%</div></div>';

          let celHTPro = newRowPro.insertCell(5);
          celHTPro.innerHTML = '<div class="input-group"><input type="text" class="form-control numeric" id="inpHT_' + val['fk_produit'] + '" name="inpHT_' + val['fk_produit'] + '" value="' + val['totalht'] + '" style="width: 100px; text-align: right;" readonly tabindex="-1" /><div class="input-group-addon">&euro;</div></div>';

          let celVariante = newRowPro.insertCell(6);
          celVariante.className = 'text-center';
          celVariante.innerHTML =
            '<input type="checkbox" id="chkVariante_' + val['fk_produit'] + '" name="chkVariante_' + val['fk_produit'] + '" data-rid="' + val['fk_produit'] + '" data-achat="' + val['prix_achat_net'] + '" data-vente="' + val['prix_vente'] + '" value="' + val['chk_variante'] + '" ' + (val['chk_variante'] == 1 ? 'checked' : '') + ' disabled />';

          let celMargePro = newRowPro.insertCell(7);
          celMargePro.innerHTML =
            '<div class="input-group"><input type="text" class="form-control numeric" id="inpMG_' + val['fk_produit'] + '" name="inpMG_' + val['fk_produit'] + '" value="' + val['marge'] + '" style="width: 80px; text-align: right; border-color: #DC3023!important; border-width: 4px;" readonly tabindex="-1" /><div class="input-group-addon">%</div></div>';
        }
      }
    }
  }

  let clickLigDevisArchives = function () {
    panel = 'archives';
    //! On ne fait rien si l'utilisateur clique sur le même devis
    if (this.getAttribute('data-rid') != idDevisArchives) {
      idDevisArchives = this.getAttribute('data-rid');

      //! On met enfin en évidence la ligne cliquée
      Array.from(elCelDevisArchives).forEach(function (ligDevis) {
        if (ligDevis.getAttribute('data-rid') == oldIdLnArchives) {
          ligDevis.style.backgroundColor = oldColorLnArchives;
        } else if (ligDevis.getAttribute('data-rid') == idDevisArchives) {
          oldColorLnArchives = ligDevis.style.backgroundColor;
          ligDevis.style.backgroundColor = '#9bbce7';
        }
      });
      oldIdLnArchives = idDevisArchives;
      console.log('idDevisArchives: ' + idDevisArchives);

      refreshChat();
    }
  };

  let clickExportDevisEnCours = function () {
    idDevisEncours = this.getAttribute('data-rid');
    const url = '/expxls/export_sap_devis/' + idDevisEncours.toString();
    console.log('Export Excel : ' + url);
    window.open(url, '_blank');

    panel = 'enCours';
    refreshChat();
    return false;
  };

  let clickExportDevisXMLEnCours = function () {
    idDevisEncours = this.getAttribute('data-rid');
    const url = '/jxexport/xml_devis/' + idDevisEncours.toString();
    console.log('Export xml : ' + url);
    window.open(url, '_blank');
    return false;
  };

  function refreshChat() {
    console.log('refreshChat()');
    if ((idDevisEnCours > 0 && panel == 'enCours') || (idDevisArchives > 0 && panel == 'archives')) {
      console.log('refreshChat()');
      let idDevis = 0;
      if (panel == 'enCours') {
        idDevis = idDevisEnCours;
      } else {
        idDevis = idDevisArchives;
      }
      //! On récupère les données de devis_histo
      fetch('/jxchat/refresh', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json;charset=utf-8',
          Accept: 'application/json;charset=utf-8',
        },
        body: JSON.stringify({
          cid: idDevis,
        }),
      }).then((response) => {
        const ret = response.json();
        ret.then(function (data) {
          // on vérifie si le nombre de commentaires a changé
          if (nbCommentChat != data.length) {
            // Si c'est le cas on rafraîchit tous les commentaires

            // On supprime tous les commentaires
            const chatContainer = document.getElementById('chat-bubbles-' + panel);
            const chatBubbles = chatContainer.getElementsByClassName('chat-bubble');
            while (chatBubbles.length > 0) {
              chatBubbles[0].parentNode.removeChild(chatBubbles[0]);
            }

            // On ajoute tous les commentaires
            for (let i = 0; i < data.length; i++) {
              const chatBubble = document.createElement('div');
              chatBubble.classList.add('chat-bubble');
              if (data[i].fk_user == fkUser) {
                chatBubble.classList.add('right-chat-bubble');
              } else {
                chatBubble.classList.add('left-chat-bubble');
              }
              const initiales = data[i].prenom.substring(0, 1) + data[i].libelle.substring(0, 1);

              const userInfo = document.createElement('div');
              userInfo.classList.add('user-info');
              const userInitials = document.createElement('div');
              userInitials.classList.add('user-initials');
              userInitials.innerHTML = initiales;
              userInfo.appendChild(userInitials);
              const usernameDate = document.createElement('div');
              usernameDate.classList.add('username-date');
              const username = document.createElement('span');
              username.classList.add('username');
              username.innerHTML = data[i].prenom + ' ' + data[i].libelle;
              usernameDate.appendChild(username);
              const date = document.createElement('span');
              date.classList.add('date');
              date.innerHTML = data[i].date_histo;
              usernameDate.appendChild(date);
              userInfo.appendChild(usernameDate);
              chatBubble.appendChild(userInfo);
              const message = document.createElement('div');
              message.classList.add('message');
              message.innerHTML = data[i].commentaire;
              chatBubble.appendChild(message);
              chatContainer.appendChild(chatBubble);
            }

            nbCommentChat = data.length;

            // et on vide le champ de saisie s'il n'a pas le focus
            if (!document.getElementById('chatInputMessage').hasFocus) {
              document.getElementById('chatInputMessage').value = '';
            }
          }
          const chatCont = document.getElementById('chat-container-' + panel);
          chatCont.style.display = 'block';
        });
      });
      console.log('Chat refreshed at ' + new Date());
    }
  }

  let chatSendMessage = function () {
    // On récupère le message à envoyer
    const message = document.getElementById('chatInputMessage').value;
    // On récupère l'id du devis
    let idDevis = 0;
    if (panel == 'enCours') {
      idDevis = idDevisEnCours;
    } else {
      idDevis = idDevisArchives;
    }

    // On envoie le message
    fetch('/jxchat/save_message', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
        Accept: 'application/json;charset=utf-8',
      },
      body: JSON.stringify({
        cid: idDevis,
        message: message,
        fkuser: fkUser,
      }),
    }).then((response) => {
      const ret = response.json();
      ret.then(function (data) {
        refreshChat();
      });
    });
  };

  setInterval(refreshChat, 60000); // Refresh every 60 seconds (1000 ms = 1 second)

  let clickSaveComment = function () {
    commentaire = document.getElementById('inpComment').value;
    if (commentaire == '') {
      showNotification('Veuillez saisir un commentaire', 'warning');
      return false;
    }
    // On envoie le message
    fetch('/jxchat/save_message', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
        Accept: 'application/json;charset=utf-8',
      },
      body: JSON.stringify({
        cid: idDevisEnCours,
        message: commentaire,
        fkuser: fkUser,
      }),
    }).then((response) => {
      const ret = response.json();
      ret.then(function (data) {
        hideModal(document.getElementById('modalViewDevis'));
        refreshChat();
      });
    });
  };

  let clickImportPDFEnCours = function () {
    idDevisEnCours = this.getAttribute('data-rid');
    panel = 'enCours';

    //! On va chercher les éventuels fichiers déjà uploadés
    fetch('/jximport/get_files', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
        Accept: 'application/json;charset=utf-8',
      },
      body: JSON.stringify({
        cid: idDevisEnCours,
        sup: 'devis_pdf_sap',
      }),
    }).then(function (response) {
      const tblBodyPJ = document.getElementById('tblPJ').getElementsByTagName('tbody')[0];
      tblBodyPJ.innerHTML = '';

      if (response.ok) {
        const ret = response.json();
        ret.then(function (data) {
          if (data.length > 0) {
            data.forEach(function (val, idx) {
              let newRowPJ = tblBodyPJ.insertRow(-1);
              newRowPJ.className = 'text-center';
              let celPJ = newRowPJ.insertCell(0);
              celPJ.innerHTML = '<a href="/' + val['dir0'] + val['fichier'] + '" target="_blank">' + val['fichier'] + '</a>';
              let celSup = newRowPJ.insertCell(1);
              celSup.innerHTML = '<button type="button" class="btn btn-danger btn-sm" id="btnSupPJ_' + val['rowid'] + '" data-rid="' + val['rowid'] + '"><i class="fa fa-trash"></i></button>';
              document.getElementById('btnSupPJ_' + val['rowid']).addEventListener('click', clickDeletePJ);
            });
          }
        });
      }
      refreshChat();
    });

    showModal(document.getElementById('modalUploadPDF'));

    panel = 'enCours';
    return false;
  };

  let clickUploadPDF = function () {
    let file = document.getElementById('txtUploadPDF').files[0];
    if (file == undefined) {
      showNotification('Veuillez sélectionner un fichier PDF', 'warning');
      return false;
    }
    let formData = new FormData();
    formData.append('file', file);
    formData.append('cid', idDevisEnCours);
    fetch('/jximport/upload_sap_pdf', {
      method: 'POST',
      body: formData,
    }).then((response) => {
      const ret = response.json();
      ret.then(function (data) {
        if (data.ret == 'ok') {
          showNotification(data.msg, 'success');
        } else {
          showNotification(data.msg, 'error');
        }
        hideModal(document.getElementById('modalUploadPDF'));
        location.reload();
      });
    });
  };

  let clickClosePDF = function () {
    hideModal(document.getElementById('modalUploadPDF'));
  };

  function clickDeletePJ() {
    const idMedia = this.getAttribute('data-rid');

    if (confirm('Voulez-vous vraiment supprimer ce fichier ?')) {
      let id = this.getAttribute('data-rid');
      fetch('/jximport/delete_file', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json;charset=utf-8',
          Accept: 'application/json;charset=utf-8',
        },
        body: JSON.stringify({
          cid: idMedia,
        }),
      }).then(function (response) {
        if (response.ok) {
          const ret = response.json();
          ret.then(function () {
            showNotification('Fichier supprimé avec succès !');
            // On rafraichit la liste des PJ
            const tblBodyPJ = document.getElementById('tblPJ').getElementsByTagName('tbody')[0];
            // On supprime la ligne correspondant à la PJ supprimée
            Array.from(tblBodyPJ.rows).forEach(function (row) {
              if (row.cells[1].firstChild.getAttribute('data-rid') == idMedia) {
                row.remove();
              }
            });
          });
        }
      });
    }
    return false;
  }

  let clickDevisEnvoye = function () {
    idDevisEnCours = this.getAttribute('data-rid');
    panel = 'enCours';
    refreshChat();

    if (confirm('Ce devis a bien été envoyé au client ? Il sera archivé et ne pourra plus être mis à jour.')) {
      let data = {};
      data['cid'] = idDevisEnCours;
      data['statut'] = 20;
      data['commentaire'] = 'Devis envoyé au client et archivé';

      fetch('/jxdevis/statut_devis', {
        method: 'POST',
        body: JSON.stringify(data),
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
        },
      });
      showNotification('Devis archivé', 'Le devis est maintenant archivé', 'success');
      setTimeout(function () {
        location.reload();
      }, 2000); // 2000 millisecondes = 2 secondes
    }
    return false;
  };

  let clickDeleteDevis = function () {
    idDevisEnCours = this.getAttribute('data-rid');
    panel = 'enCours';
    refreshChat();

    if (confirm('Voulez-vous vraiment supprimer ce devis ?')) {
      let data = {};
      data['cid'] = idDevisEnCours;

      fetch('/jxdevis/delete_devis', {
        method: 'POST',
        body: JSON.stringify(data),
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
        },
      });
      showNotification('Devis supprimé', 'Le devis a été supprimé', 'success');
      setTimeout(function () {
        location.reload();
      }, 2000); // 2000 millisecondes = 2 secondes
    }
    return false;
  };

  // Fonctions de recherche SAP
  let elSearchSAP = document.getElementById('searchSAP');
  let elBtnResetSearchSAP = document.getElementById('btnResetSearchSAP');

  function restoreSearchSAP() {
    const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives';
    const savedTerm = sessionStorage.getItem(storageKey);
    if (savedTerm && savedTerm.length >= 3) {
      elSearchSAP.value = savedTerm;
      elBtnResetSearchSAP.style.display = 'inline-block';
      performSearchSAP(savedTerm);
    } else {
      elSearchSAP.value = '';
      elBtnResetSearchSAP.style.display = 'none';
    }
  }

  function performSearchSAP(term) {
    if (term.length < 3) {
      return;
    }

    const context = panel === 'archives' ? 'archives' : 'encours';

    fetch('/jxdevis/search_devis_sap', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        term: term,
        context: context,
      }),
    })
      .then((response) => response.json())
      .then((data) => {
        if (data.success) {
          const devisIds = data.devis.map((d) => d.rowid);
          filterDevisTablesSAP(devisIds, context);
          updateBadgesSAP(data.nb_devis);
        } else {
          console.error('Erreur recherche:', data.message);
        }
      })
      .catch((error) => {
        console.error('Erreur AJAX:', error);
      });
  }

  function filterDevisTablesSAP(devisIds, context) {
    if (context === 'encours') {
      const statuts = document.querySelectorAll('[id^="tblBodyDos"]');
      statuts.forEach((tbody) => {
        const rows = tbody.querySelectorAll('tr.ligEnCours');
        rows.forEach((row) => {
          const cells = row.querySelectorAll('.celEnCours');
          if (cells.length > 0) {
            const rowId = parseInt(cells[0].getAttribute('data-rid'));
            if (devisIds.includes(rowId)) {
              row.style.display = '';
            } else {
              row.style.display = 'none';
            }
          }
        });
      });
    } else {
      const archives = document.querySelectorAll('[id^="tblBodyDosArch"]');
      archives.forEach((tbody) => {
        const rows = tbody.querySelectorAll('tr');
        rows.forEach((row) => {
          if (row.id && (row.id.startsWith('trArch_') || row.id.startsWith('trArchTous_'))) {
            const rowId = parseInt(row.id.replace('trArch_', '').replace('trArchTous_', ''));
            if (devisIds.includes(rowId)) {
              row.style.display = '';
            } else {
              row.style.display = 'none';
            }
          }
        });
      });
    }
  }

  function updateBadgesSAP(nbDevis) {
    Object.keys(nbDevis).forEach((statutId) => {
      const liElements = document.querySelectorAll('[id^="liStat"]');
      liElements.forEach((li) => {
        li.setAttribute('data-after-text', nbDevis[statutId] || '0');
        li.setAttribute('data-after-type', 'orange badge top left');
      });
    });
  }

  function resetSearchSAP() {
    elSearchSAP.value = '';
    elBtnResetSearchSAP.style.display = 'none';
    const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives';
    sessionStorage.removeItem(storageKey);

    const context = panel === 'archives' ? 'archives' : 'encours';
    if (context === 'encours') {
      const statuts = document.querySelectorAll('[id^="tblBodyDos"]');
      statuts.forEach((tbody) => {
        const rows = tbody.querySelectorAll('tr');
        rows.forEach((row) => {
          row.style.display = '';
        });
      });
    } else {
      const archives = document.querySelectorAll('[id^="tblBodyDosArch"]');
      archives.forEach((tbody) => {
        const rows = tbody.querySelectorAll('tr');
        rows.forEach((row) => {
          row.style.display = '';
        });
      });
      const tbodyTous = document.getElementById('tblBodyDosArchTous');
      if (tbodyTous) {
        const rowsTous = tbodyTous.querySelectorAll('tr');
        rowsTous.forEach((row) => {
          row.style.display = '';
        });
      }
    }
  }

  elSearchSAP.addEventListener('input', function () {
    const term = this.value.trim();

    if (searchSapTimeout) {
      clearTimeout(searchSapTimeout);
    }

    if (term.length >= 3) {
      elBtnResetSearchSAP.style.display = 'inline-block';
      const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives';
      sessionStorage.setItem(storageKey, term);
      searchSapTimeout = setTimeout(() => {
        performSearchSAP(term);
      }, 300);
    } else if (term.length === 0) {
      resetSearchSAP();
    } else {
      elBtnResetSearchSAP.style.display = 'none';
    }
  });

  elBtnResetSearchSAP.addEventListener('click', function () {
    resetSearchSAP();
  });

  // Hook sur changement d'onglet pour restaurer la recherche appropriée
  $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
    if ($(this).attr('href') == '#tabEnCours') {
      panel = 'enCours';
      restoreSearchSAP();
    } else if ($(this).attr('href') == '#tabArchives') {
      panel = 'archives';
      restoreSearchSAP();
    }
  });

  restoreSearchSAP();

  initTableSort();

  // Gestion des états actifs des onglets départements (multiples <ul>)
  // Utiliser l'événement Bootstrap 'shown.bs.tab' au lieu de 'click'
  const allDeptTabs = document.querySelectorAll('.dept-tab a');
  allDeptTabs.forEach((tab) => {
    $(tab).on('shown.bs.tab', function(e) {
      // Retirer 'active' de tous les onglets départements sauf celui-ci
      document.querySelectorAll('.dept-tab').forEach((li) => {
        if (li !== this.parentElement) {
          li.classList.remove('active');
        }
      });
      // Retirer 'active' de l'onglet "Tous"
      const tousLi = document.querySelector('a[href="#dosArchTous"]').parentElement;
      tousLi.classList.remove('active');
    });
  });

  // Gestion du clic sur "Tous"
  const tousTab = document.querySelector('a[href="#dosArchTous"]');
  if (tousTab) {
    $(tousTab).on('shown.bs.tab', function(e) {
      // Retirer 'active' de tous les onglets départements
      document.querySelectorAll('.dept-tab').forEach((li) => {
        li.classList.remove('active');
      });
    });
  }

  // Add new functions
  function updateExportButton() {
    if (selectedXmlDevis.size > 0) {
      elBtnExportSelectedXML.classList.remove('hidden');
    } else {
      elBtnExportSelectedXML.classList.add('hidden');
    }
  }

  function handleCheckboxChange(e) {
    const devisId = e.target.getAttribute('data-rid');
    if (e.target.checked) {
      selectedXmlDevis.add(devisId);
    } else {
      selectedXmlDevis.delete(devisId);
    }
    updateExportButton();
  }

  function exportSelectedDevis() {
    selectedXmlDevis.forEach((devisId) => {
      const url = '/jxexport/xml_devis/' + devisId;
      window.open(url, '_blank');
    });

    // Reset checkboxes
    Array.from(elExportCheckboxes).forEach((checkbox) => {
      checkbox.checked = false;
    });

    // Clear Set and hide export button
    selectedXmlDevis.clear();
    updateExportButton();
  }

  // Initialisation des événements
  Array.from(elCelDevisEnCours).forEach(function (lnDevis) {
    lnDevis.addEventListener('click', clickLigDevisEnCours);
  });
  Array.from(elCelDevisArchives).forEach(function (lnDevis) {
    lnDevis.addEventListener('click', clickLigDevisArchives);
  });

  Array.from(elBtnExportDevisEnCours).forEach(function (expDevis) {
    expDevis.addEventListener('click', clickExportDevisEnCours);
  });
  Array.from(elBtnExportDevisXMLEnCours).forEach(function (expDevis) {
    expDevis.addEventListener('click', clickExportDevisXMLEnCours);
  });
  Array.from(elBtnImportPDFEnCours).forEach(function (impDevis) {
    impDevis.addEventListener('click', clickImportPDFEnCours);
  });
  Array.from(elBtnViewDevisEnCours).forEach(function (viewDevis) {
    viewDevis.addEventListener('click', clickViewDevis);
  });
  Array.from(elBtnViewDevisArchives).forEach(function (viewDevis) {
    viewDevis.addEventListener('click', clickViewDevis);
  });
  Array.from(elBtnDeleteDevis).forEach(function (delDevis) {
    delDevis.addEventListener('click', clickDeleteDevis);
  });

  elChatBtnSendEnCours.addEventListener('click', chatSendMessage);
  elBtnSaveComment.addEventListener('click', clickSaveComment);
  elBtnUploadPDF.addEventListener('click', clickUploadPDF);
  elBtnClosePDF.addEventListener('click', clickClosePDF);
  Array.from(elBtnDevisEnvoye).forEach(function (devisEnvoye) {
    devisEnvoye.addEventListener('click', clickDevisEnvoye);
  });

  Array.from(elExportCheckboxes).forEach((checkbox) => {
    checkbox.addEventListener('change', handleCheckboxChange);
  });

  elBtnExportSelectedXML.addEventListener('click', exportSelectedDevis);
});
