async function updateCSSPaths(cssFilePath, prependPath) {
  try {
    // Fetch the CSS file
    const response = await fetch(cssFilePath);
    let cssContent = await response.text();

    // Update the paths in the CSS content
    cssContent = cssContent.replace(/url\((['"]?)(.*?)\1\)/g, (match, p1, p2) => {
      // Only update paths that do not start with http, https, or data
      if (!p2.match(/^(https?:|data:)/)) {
        return `url(${p1}${prependPath}${p2}${p1})`;
      }
      return match;
    });

    // Create a new <style> element
    const styleElement = document.createElement("style");
    styleElement.textContent = cssContent;

    // Append the <style> element to the <head>
    document.head.appendChild(styleElement);
  } catch (error) {
    console.error("Error loading or updating CSS:", error);
  }
}

// Call the function with the path to the CSS file and the path to prepend
updateCSSPaths(ROOT_URL + "/src/css/images.css", ROOT_URL);

var randNum = function () {
  return Math.floor(Math.random() * (1 + 40 - 20)) + 20;
};

if ($(".progress .progress-bar")[0]) {
  $(".progress .progress-bar").progressbar();
}

function generateEmailMessage(client, type) {}

$(".formButton,.transferButton,.archiveButton, .emailButton").click(function () {
  $("#popupBox .modal-body").html("");
  $("#popupBox .modal-footer").html("");
  var target = $(this).data("href");
  var string = $(this).data("values");
  var dest = encodeURI(target + "?mode=popup&data=" + string);
  $("#popupBox .modal-body").load(dest);
  const element = document.querySelector("#popupBox");
  const options = {
    backdrop: true,
    focus: true,
  };
  const instance = new mdb.Modal(element, options);
  instance.show();
});

function triggerAction(i) {
  // Find the element with the given ID
  var element = document.getElementById(i);

  // Check if the element exists
  if (element) {
    // Create a new MouseEvent for the click
    var clickEvent = new MouseEvent("click", {
      bubbles: true,
      cancelable: true,
      view: window,
    });

    // Dispatch the event to simulate the click
    element.dispatchEvent(clickEvent);
  } else {
    console.error('Element with ID "' + i + '" not found.');
  }
}

function showResponse(type, text) {
  const responseContainer = document.getElementById("response");
  responseContainer.innerHTML = `
    <div class="alert ${type}-color-dark text-light text-center response-alert">
      <p class="response-text text-center">${text}</p>
    </div>
  `;

  // Ensure element is visible before applying animation classes
  responseContainer.style.display = "block";

  // Add class to trigger the slide-down animation
  responseContainer.classList.add("slide-down");

  // Remove the slide-down class after animation is done and add slide-up class
  setTimeout(() => {
    responseContainer.classList.remove("slide-down");
    responseContainer.classList.add("slide-up");
  }, 5000); // Keep the message on the screen for 4 seconds

  // Hide the element after the slide-up animation is done
  setTimeout(() => {
    responseContainer.style.display = "none";
    responseContainer.classList.remove("slide-up");
  }, 5500); // Adjust based on the total duration of both animations
}

function triggerCal(i) {
  $("#" + i).trigger("click");
}

function setBox() {
  $("#overlay").css("display", "block");
}

function drawSearch(n, i) {
  var table = $("#datatable").dataTable().api();

  $.fn.dataTable.ext.search.pop();

  $.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {
    var msdsSearch = n;
    var msdsValue = data[i];
    if (msdsSearch == msdsValue) {
      return true;
    }
    return false;
  });

  table.draw();
}

function addSearch(n,t) {
  var table = $("#"+t).dataTable().api();
  table.search(n).draw();
}

function clearSearch(t) {
  var table = $("#"+t).dataTable().api();
  $.fn.dataTable.ext.search.pop();
  table.search("").draw();
  $("#siteList").val(null).trigger("change");
}

function resetAC() {}

function clearbox(i) {
  var original_color = $("#" + i).css("border-color");
  $("#" + i).addClass("dangerBorder");
  setTimeout(function () {
    $("#" + i).removeClass("dangerBorder");
    $("#" + i).text("");
    $("#" + i).val("");
  }, 200);
}

function validatedEmail(sEmail) {
  var filter = /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
  if (filter.test(sEmail)) {
    return true;
  } else {
    return false;
  }
}

function on() {
  document.getElementById("overlay").style.display = "block";
}
function off() {
  document.getElementById("overlay").style.display = "none";
}

function toggleVisibility(i) {
  $("#" + i).toggle();
}

function debug(m) {
  const element = document.querySelector("#debugBox");
  const options = {
    backdrop: true,
    focus: true,
  };
  const instance = new mdb.Modal(element, options);
  instance.hide();
  $("#debugBox .modal-body").html("");
  $("#debugBox").modal("show");
  $("#debugBox .modal-header").html('<a href="javascript:void(0)" class="sa">DEBUG</a>');
  $("#debugBox .modal-body").html(`<div class="text-center"><p><textarea id="output" class="form-control" rows="30">${m}</textarea></p><br /></div><div class="float-end"><a class="btn btn-danger" href="javascript:void(0)" onclick="\$(\'#debugBox\').modal(\'hide\');">Close<a/></div>`);
  $("#debugBox .modal-footer").html("");
  instance.show();
}

function delWSC(i) {
  if (confirm("Are you sure about removing this WS entry?\nThis action cannot be undone") == true) {
    $.post(ROOT_URL + "/includes/master/ws_functions.php", { mode: "delWS", id: i, tenant: TENANT_URL }, function (result) {
      if ($.trim(result) == "success") {
        showResponse("success", "THE WS HAS BEEN REMOVED SUCCESSFULLY");
        relWs();
      } else {
        showResponse("danger", "THERE WAS AN ERROR REMOVING THE WS");
      }
    });
  }
}

function editWSC(i) {
  const target = ROOT_URL + "/includes/master/ws_edit.php?ws=" + i + "&tenant=" + TENANT_URL;
  var dest = encodeURI(target);
  loadModalContent(dest, "wsBox", "modal-xxl", 1060, "true", "Written Scheme", "close");
}

function delLWSC(i) {
  if (confirm("Are you sure about removing this LWS entry?\nThis action cannot be undone") == true) {
    $.post(ROOT_URL + "/includes/master/lws_functions.php", { mode: "delLWS", id: i, tenant: TENANT_URL }, function (result) {
      if ($.trim(result) == "success") {
        showResponse("success", "THE LWS HAS BEEN REMOVED SUCCESSFULLY");
        relLWs();
      } else {
        showResponse("danger", "THERE WAS AN ERROR REMOVING THE WLWSS");
      }
    });
  }
}

function editLWSC(i) {
  const target = ROOT_URL + "/includes/master/lws_edit.php?lws=" + i + "&tenant=" + TENANT_URL;
  var dest = encodeURI(target);
  loadModalContent(dest, "lwsBox", "modal-xxl", 1060, "true", "LOLER Written Scheme", "close");
}

function checkValue(str, max) {
  if (str.charAt(0) !== "0" || str == "00") {
    var num = parseInt(str);
    if (isNaN(num) || num <= 0 || num > max) num = 1;
    str = num > parseInt(max.toString().charAt(0)) && num.toString().length == 1 ? "0" + num : num.toString();
  }
  return str;
}

$(".numberfield").each(function () {
  $(this).on("keyup", function (evt) {
    if ($(this).val() !== "") {
      if (evt.which != 110) {
        //not a fullstop
        var n = parseFloat($(this).val().replace(/\,/g, ""), 10);
        $(this).val(n.toLocaleString());
      }
    }
  });
});

function pad(str, max) {
  str = str.toString();
  return str.length < max ? pad("0" + str, max) : str;
}

function loadcalc() {
  var dest = encodeURI(tenant_url + "/functions/calc.php");
  loadModalContent(dest, "popupBox", "modal-lg", 1060, "true", "Calculator", "close");
}

//table,column,id,script,function
function archive(t, c, i, s, f) {
  $.post(ROOT_URL + "/includes/master/" + s, { FUNCTION: f, [c]: i }, function (ret) {
    if ($.trim(ret) == "s") {
      showResponse("success", t + " Archived successfully");
    }
  });
}

function printer(data) {}

//OPTIONS modal-fullscreen, modal-xl, modal-lg, {empty}, modal-sm
function loadModalContent(dest, target, size = "modal-xl", zIndex = 1050, backdrop = "true", title = "", footerMode, confirmCallback, saveCallback, updateCallback) {
  hideTooltips();

  // Increment zIndex for stacking modals
  const currentModals = document.querySelectorAll(".modal.fade.show");
  zIndex += currentModals.length * 10;

  // Check if dest is a URL or HTML string
  const isHtmlString = dest.trim().startsWith("<");

  const loadContent = isHtmlString ? Promise.resolve(dest) : fetch(dest).then((response) => response.text());

  loadContent
    .then((html) => {
      // Remove existing modal with the same target ID if it exists
      const existingModal = document.getElementById(target);
      if (existingModal) {
        existingModal.remove();
      }

      // Create and append the new modal HTML
      const modalHtml = `
        <div id="${target}" class="modal fade" role="dialog" aria-hidden="true" style="z-index:${zIndex}" data-mdb-backdrop="${backdrop}" data-mdb-keyboard="true">
          <div class="modal-dialog ${size}">
            <div class="modal-content">
              <div class="modal-header"></div>
              <div class="modal-body">${html}</div>
              <div class="modal-footer text-center"></div>
            </div>
          </div>
        </div>
      `;
      document.querySelector("#modalContainer").insertAdjacentHTML("beforeend", modalHtml);

      // After loading content, initialize modal
      const modalElement = document.getElementById(target);
      const popupBoxInstance = new mdb.Modal(modalElement);
      popupBoxInstance.show();

      createModalFooter(modalElement, footerMode, popupBoxInstance, confirmCallback, saveCallback, updateCallback);

      // Manually execute scripts in the modal
      const scriptElements = modalElement.querySelectorAll(".modal-body script");
      scriptElements.forEach((script) => {
        const newScript = document.createElement("script");
        if (script.src) {
          newScript.src = script.src;
          newScript.onload = function () {
            document.body.appendChild(newScript);
            document.body.removeChild(newScript);
          };
        } else {
          newScript.textContent = script.innerText;
          document.body.appendChild(newScript);
          document.body.removeChild(newScript);
        }
      });

      // Add cancel button functionality
      const btnCancel = document.querySelector(`#${target} #modalBtnCancel`);
      if (btnCancel) {
        btnCancel.addEventListener("click", function () {
          popupBoxInstance.hide();
          // Remove the modal from DOM after it's hidden
          modalElement.addEventListener("hidden.bs.modal", () => {
            modalElement.remove();
          });
        });
      }

      // Add the title and toggle size button to the modal header
      if (title !== "") {
        const modalHeader = document.querySelector("#" + target + " .modal-header");
        if (modalHeader) {
          modalHeader.innerHTML = `
            <div class="d-flex justify-content-between w-100">
              <div class="col-6"><a href="javascript:void(0)" class="sa">${title}</a></div>
              <div class="col-6 text-end">
                <button id="${target}-toggleSizeBtn" class="btn btn-link p-0">
                  <i class="fad ${size === "modal-fullscreen" ? "fa-compress" : "fa-expand"} fa-2x"></i>
                </button>
              </div>
            </div>
          `;

          // Add click event listener to toggle size button
          const toggleSizeBtn = document.getElementById(`${target}-toggleSizeBtn`);
          toggleSizeBtn.addEventListener("click", function () {
            toggleModalSize(modalElement, size, toggleSizeBtn);
          });
        }
      }
    })
    .catch((error) => console.error("Error loading modal content:", error));
}

function createModalFooter(modalElement, footerMode, modalInstance, confirmCallback, saveCallback, updateCallback) {
  const modalFooter = modalElement.querySelector(".modal-footer");

  if (!modalFooter) {
    return; // Do nothing if no footer element is found
  }

  switch (footerMode) {
    case "cancel":
      modalFooter.innerHTML = `
       <div class="col-12 text-center">
        <button type="button" class="btn btn-danger" data-mdb-dismiss="modal" data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="Close">Cancel</button>
         </div>
      `;
      break;

    case "close":
      modalFooter.innerHTML = `
       <div class="col-12 text-center">
        <button type="button" class="btn btn-danger" data-mdb-dismiss="modal" data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="Close">Close</button>
         </div>
      `;
      break;

    case "sortReports":
      modalFooter.innerHTML = `
       <div class="col-12 text-center">
         <button type="button" class="btn btn-danger float-end" data-mdb-dismiss="modal">Cancel</button>
         <button type="button" class="btn btn-success" id="modalBtnSort">Sort Reports</button>
        <button type="button" class="btn btn-info float-start" id="modalBtnContinue">Continue without sorting</button>
        </div>
      `;
      const continueButton = modalElement.querySelector("#modalBtnContinue");
      const sortButton = modalElement.querySelector("#modalBtnSort");
      // Check if the callback is a string or a function
      if (typeof confirmCallback === "string") {
        continueButton.setAttribute("onclick", `${confirmCallback}`);
      } else if (typeof confirmCallback === "function") {
        continueButton.addEventListener("click", confirmCallback); // Attach callback
      }

      // Check if the callback is a string or a function
      if (typeof saveCallback === "string") {
        sortButton.setAttribute("onclick", `${saveCallback}`);
      } else if (typeof saveCallback === "function") {
        sortButton.addEventListener("click", saveCallback); // Attach callback
      }
      break;

    case "cancelConfirm":
      modalFooter.innerHTML = `
      <div class="col-12">
        <button type="button" class="btn btn-secondary float-end" data-mdb-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-success float-start" id="modalBtnConfirm">Confirm</button>
      </div> 
      `;
      const confirmButton = modalElement.querySelector("#modalBtnConfirm");

      // Check if the callback is a string or a function
      if (typeof confirmCallback === "string") {
        confirmButton.setAttribute("onclick", `${confirmCallback}()`);
      } else if (typeof confirmCallback === "function") {
        confirmButton.addEventListener("click", confirmCallback); // Attach callback
      }
      break;

    case "save":
      modalFooter.innerHTML = `
       <div class="col-12 text-center">
        <button type="button" class="btn btn-success" id="modalBtnSave">Save</button>
         </div>
      `;
      const saveButton = modalElement.querySelector("#modalBtnSave");

      // Check if the callback is a string or a function
      if (typeof saveCallback === "string") {
        saveButton.setAttribute("onclick", `${saveCallback}()`);
      } else if (typeof saveCallback === "function") {
        saveButton.addEventListener("click", saveCallback); // Attach callback
      }
      break;

    case "confirm":
      modalFooter.innerHTML = `
       <div class="col-12 text-center">
        <button type="button" class="btn btn-success" id="modalBtnConfirm">Confirm</button>
         </div>
      `;
      const confirmSingleButton = modalElement.querySelector("#modalBtnConfirm");

      // Check if the callback is a string or a function
      if (typeof confirmCallback === "string") {
        confirmSingleButton.setAttribute("onclick", `${confirmCallback}`);
      } else if (typeof confirmCallback === "function") {
        confirmSingleButton.addEventListener("click", confirmCallback); // Attach callback
      }
      break;

    case "update":
      modalFooter.innerHTML = `
       <div class="col-12 text-center">
        <button type="button" class="btn btn-warning" id="modalBtnUpdate">Update</button>
         </div>
      `;
      const updateButton = modalElement.querySelector("#modalBtnUpdate");

      // Check if the callback is a string or a function
      if (typeof updateCallback === "string") {
        updateButton.setAttribute("onclick", `${updateCallback}()`);
      } else if (typeof updateCallback === "function") {
        updateButton.addEventListener("click", updateCallback); // Attach callback
      }
      break;

    default:
      modalFooter.innerHTML = ""; // No footer if mode is not recognized
  }
}

function toggleModalSize(modalElement, originalSize, toggleSizeBtn) {
  const modalDialog = modalElement.querySelector(".modal-dialog");
  const isFullScreen = modalDialog.classList.contains("modal-fullscreen");

  if (isFullScreen) {
    modalDialog.classList.remove("modal-fullscreen");
    modalDialog.classList.add(originalSize);
    toggleSizeBtn.innerHTML = '<i class="fad fa-expand fa-2x"></i>';
  } else {
    modalDialog.classList.remove(originalSize);
    modalDialog.classList.add("modal-fullscreen");
    toggleSizeBtn.innerHTML = '<i class="fad fa-compress fa-2x"></i>';
  }
}

function initializeDatepickers(containerElement) {
  const datepickerElements = containerElement.querySelectorAll(".datepicker");
  const elementId = containerElement.id;
  datepickerElements.forEach((datepickerEl) => {
    const options = {
      confirmDateOnSelect: true,
      format: "dd-mm-yyyy",
    };

    new mdb.Datepicker(datepickerEl, options);
  });
}

function initializeSelects(containerElement) {
  const selectElements = containerElement.querySelectorAll(".filterSelect");
  const elementId = containerElement.id;
  selectElements.forEach((selectEl) => {
    const options = {
      filter: true, // Enable filtering in the select
    };

    new mdb.Select(selectEl, options);
  });
}

function hideTooltips() {
  const tooltips = document.querySelectorAll(".tooltip.show");
  tooltips.forEach((tooltip) => {
    tooltip.parentNode.removeChild(tooltip);
  });
}

// Function to close all modals
function killAllModals() {
  setTimeout(function () {
    var modals = document.querySelectorAll(".modal.fade.show");

    for (var i = 0; i < modals.length; i++) {
      var modal = modals[i];
      var mdbModal = mdb.Modal.getInstance(modal); // Get the instance if it exists

      if (mdbModal) {
        // Try to destroy the modal instance if MDB provides a method for it
        if (typeof mdbModal.dispose === "function") {
          mdbModal.dispose();
        } else {
          // If no dispose method, manually remove the modal from the DOM
          modal.parentNode.removeChild(modal);
        }
      }
    }
  }, 100);
}

// Function to close targeted modal
function killModal(modalId) {
  // Get the modal element by its ID
  var modalElement = document.getElementById(modalId);

  if (!modalElement) {
    console.error(`Modal with ID "${modalId}" not found.`);

    return;
  } else {
    console.log(`Modal with ID "${modalId}" found.`);
  }
  var modalInstance = mdb.Modal.getInstance(modalElement);
  modalInstance.hide();
}

// Function to show the loading indicator
function showLoadingIndicator(message = "Generating print", icon = "fa-spinner fa-spin-reverse", modalId = null) {
  const loadingHtml = `<div id="pageBackdrop"></div>
      <div id="printingObject" class="loading-overlay">
      
          <div class="col-12 text-center text-light">
              <h1>
                  <i class="fad ${icon} fa-spin fa-3x fa-fw text-light" style="--fa-primary-color: #0055A6; --fa-secondary-color: white;"></i><br>${message}<br><small>Please wait</small>
              </h1>
          </div>
      </div>
  `;

  if (modalId) {
    const modalBody = document.querySelector(`#${modalId} .modal-body`);
    if (modalBody) {
      // Append loading overlay to the modal body
      modalBody.insertAdjacentHTML("beforeend", loadingHtml);
    } else {
      console.error(`Modal with ID ${modalId} not found or does not have a modal-body.`);
    }
  } else {
    // Default to inserting into the document body
    document.body.insertAdjacentHTML("beforeend", loadingHtml);
  }
}

// Function to remove the loading indicator
function removeLoadingIndicator() {
  const loadingElement = document.getElementById("printingObject");
  const backdropElement = document.getElementById("pageBackdrop");
  if (loadingElement) {
    loadingElement.remove();
    backdropElement.remove();
  }
}

function autofill(f, s, t, g = "") {
  var dest = encodeURI(`${ROOT_URL}/includes/master/form_options.php?form=${f}&source=${s}&type=${t}&group=${g}&tenant=${TENANT_URL}`);
  loadModalContent(dest, "popupBox", "modal-xl", 1060, "true", "AutoText");
}

function savebox(source, type = "phrases", group = "") {
  const sourceElement = document.getElementById(source);
  if (!sourceElement) {
    showResponse("danger", "Field not found");
    return;
  }

  const phrase = String(sourceElement.value || "").trim();
  if (!phrase) {
    showResponse("warning", "There is no text to save");
    return;
  }

  if (type !== "phrases") {
    showResponse("warning", "Only standard phrases can be saved from this control");
    return;
  }

  const safePhrase = phrase
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;");

  const html = `
    <div class="mb-3">
      <label class="form-label" for="savePhraseCode">Code</label>
      <input type="text" id="savePhraseCode" class="form-control" maxlength="80">
      <div class="form-text">Use a short code that helps identify this phrase.</div>
    </div>
    <div class="mb-0">
      <label class="form-label" for="savePhrasePreview">Phrase</label>
      <textarea id="savePhrasePreview" class="form-control" rows="6" readonly>${safePhrase}</textarea>
    </div>
  `;

  loadModalContent(html, "savePhraseBox", "modal-md", 1060, "true", "Save Phrase", "cancelConfirm", () => saveboxConfirm(source, type, group));
}

function saveboxConfirm(source, type = "phrases", group = "") {
  if (typeof killModal === "function") {
    killModal("savePhraseBox");
  }

  const sourceElement = document.getElementById(source);
  const codeElement = document.getElementById("savePhraseCode");
  const phrase = sourceElement ? String(sourceElement.value || "").trim() : "";
  const code = codeElement ? String(codeElement.value || "").trim() : "";

  if (!phrase || !code) {
    showResponse("warning", "Please enter a code and phrase");
    return;
  }

  fetch(ROOT_URL + "/includes/jump/jump_functions.php", {
    method: "POST",
    body: new URLSearchParams({
      FUNCTION: "save",
      mode: "phrase",
      code: code,
      phrase: phrase,
      group_name: group,
      tenant: TENANT_URL
    })
  })
    .then((response) => response.text())
    .then((text) => {
      const ret = String(text || "").trim();
      if (ret === "s") {
        showResponse("success", "Phrase saved");
      } else if (ret === "e") {
        showResponse("warning", "That phrase code is already in use");
      } else {
        showResponse("danger", ret || "Phrase save failed");
      }
    })
    .catch(() => showResponse("danger", "Phrase save failed"));
}

function autofillElec(f, s, t) {
  var dest = encodeURI(`${ROOT_URL}/includes/master/form_options_elec.php?form=${f}&source=${s}&type=${t}&tenant=${TENANT_URL}`);
  loadModalContent(dest, "popupBox", "modal-xl", 1060, "true", "AutoText");
}

function resetBox(t, d) {
  const element = document.getElementById(t);
  if (!element) return;

  let resetValue = d;
  if (typeof resetValue === "undefined" || resetValue === null) {
    if (element.hasAttribute("data-original-value")) {
      resetValue = element.getAttribute("data-original-value");
    } else if (typeof element.defaultValue !== "undefined") {
      resetValue = element.defaultValue;
    }
  }
  if (typeof resetValue === "undefined" || resetValue === null) {
    resetValue = "None";
  }

  element.value = resetValue;
  const event = new Event("keyup");
  element.dispatchEvent(event);
}

function loadContentAndExecuteScripts(url, containerId, params, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open("POST", url, true);
  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        var container = document.getElementById(containerId);
        container.innerHTML = xhr.responseText;

        // Extract and execute any scripts in the loaded content
        var scripts = container.getElementsByTagName("script");
        for (var i = 0; i < scripts.length; i++) {
          var scriptElement = document.createElement("script");
          if (scripts[i].src) {
            // Check if the script is already loaded
            if (!document.querySelector('script[src="' + scripts[i].src + '"]')) {
              scriptElement.src = scripts[i].src;
              document.head.appendChild(scriptElement);
            }
          } else {
            scriptElement.textContent = scripts[i].textContent;
            document.body.appendChild(scriptElement);
          }
        }

        // Execute callback (if provided) after content and scripts are loaded
        if (typeof callback === "function") {
          callback();
        }
      } else {
        console.error("Failed to load content. Status: " + xhr.status);
      }
    }
  };
  xhr.onerror = function () {
    console.error("Request failed.");
  };
  xhr.send(params);
}

function pulseElementBackgroundClass(elementId, class1, class2, duration) {
  var element = document.getElementById(elementId);
  if (!element) {
    console.error("Element not found:", elementId);
    return;
  }

  // Start the pulse effect by toggling classes
  setInterval(function () {
    if (element.classList.contains(class1)) {
      element.classList.remove(class1);
      element.classList.add(class2);
    } else {
      element.classList.remove(class2);
      element.classList.add(class1);
    }
  }, duration);
}


function loadHelpSystemStyles() {
  const existing = document.getElementById("help-system-styles");
  if (existing) {
    if (existing.dataset.loaded === "true" || existing.sheet) {
      existing.dataset.loaded = "true";
      return Promise.resolve();
    }
    return new Promise((resolve) => existing.addEventListener("load", resolve, { once: true }));
  }

  return new Promise((resolve) => {
    const stylesheet = document.createElement("link");
    stylesheet.id = "help-system-styles";
    stylesheet.rel = "stylesheet";
    stylesheet.href = ROOT_URL + "/functions/help/help.css?v=4";
    stylesheet.addEventListener("load", () => {
      stylesheet.dataset.loaded = "true";
      resolve();
    }, { once: true });
    document.head.appendChild(stylesheet);
  });
}

function ensureHelpSystem() {
  if (document.getElementById("helpSystemSidebar")) return;

  document.body.insertAdjacentHTML(
    "beforeend",
    `
      <div id="helpSystemBackdrop" class="help-system-backdrop" aria-hidden="true"></div>
      <aside id="helpSystemSidebar" class="help-system-sidebar" role="dialog" aria-modal="true"
        aria-labelledby="helpSystemTitle" aria-hidden="true">
        <header class="help-system-header">
          <div>
            <div class="help-system-kicker">Contextual help</div>
            <h2 id="helpSystemTitle">Help</h2>
          </div>
          <button id="helpSystemClose" class="help-system-close" type="button" aria-label="Close help">
            <i class="fad fa-times" aria-hidden="true"></i>
          </button>
        </header>
        <div id="helpSystemContent" class="help-system-content"></div>
      </aside>
    `,
  );

  document.getElementById("helpSystemClose").addEventListener("click", closeHelpSystem);
  document.getElementById("helpSystemBackdrop").addEventListener("click", closeHelpSystem);
}

function enhanceHelpSystemTriggers(root = document) {
  loadHelpSystemStyles();

  const triggers = root.matches?.("[data-help-topic]")
    ? [root, ...root.querySelectorAll("[data-help-topic]")]
    : root.querySelectorAll("[data-help-topic]");

  triggers.forEach((trigger) => {
    const container = trigger.closest(".card-header, .note") || trigger;
    if (container.querySelector(":scope > .help-icon")) return;

    const button = document.createElement("button");
    button.className = "help-icon";
    button.type = "button";
    button.setAttribute("aria-label", "Open contextual help");
    button.textContent = "i";
    button.addEventListener("click", (event) => {
      event.preventDefault();
      event.stopPropagation();
      helpSystem(trigger.dataset.helpTopic);
    });
    if (container.matches(".card-header, .note")) {
      container.classList.add("help-system-has-icon");
    }
    container.appendChild(button);
  });
}

function closeHelpSystem() {
  const sidebar = document.getElementById("helpSystemSidebar");
  const backdrop = document.getElementById("helpSystemBackdrop");
  if (!sidebar || !backdrop) return;

  sidebar.classList.remove("is-open");
  backdrop.classList.remove("is-open");
  sidebar.setAttribute("aria-hidden", "true");
  backdrop.setAttribute("aria-hidden", "true");
  document.body.classList.remove("help-system-open");
}

async function helpSystem(topic) {
  if (!topic) return;

  await loadHelpSystemStyles();
  ensureHelpSystem();

  const sidebar = document.getElementById("helpSystemSidebar");
  const backdrop = document.getElementById("helpSystemBackdrop");
  const title = document.getElementById("helpSystemTitle");
  const content = document.getElementById("helpSystemContent");

  title.textContent = "Help";
  content.innerHTML =
    '<div class="help-system-loading"><i class="fad fa-spinner fa-spin" aria-hidden="true"></i> Loading help...</div>';
  sidebar.classList.add("is-open");
  backdrop.classList.add("is-open");
  sidebar.setAttribute("aria-hidden", "false");
  backdrop.setAttribute("aria-hidden", "false");
  document.body.classList.add("help-system-open");
  document.getElementById("helpSystemClose").focus();

  try {
    const response = await fetch(
      ROOT_URL + "/functions/help/help.php?topic=" + encodeURIComponent(topic),
    );
    const selected = await response.json();
    if (!response.ok) throw new Error(selected.error || "Help content is unavailable.");

    title.textContent = selected.title || "Help";
    content.innerHTML = "";

    (selected.images || []).forEach((image) => {
      const details = typeof image === "string" ? { src: image } : image;
      if (!details.src) return;

      const figure = document.createElement("figure");
      figure.className = "help-system-figure";
      const img = document.createElement("img");
      img.src = details.src.match(/^(https?:|data:|\/)/)
        ? details.src
        : ROOT_URL + "/functions/help/" + details.src.replace(/^\.?\//, "");
      img.alt = details.alt || "";
      figure.appendChild(img);

      if (details.caption) {
        const caption = document.createElement("figcaption");
        caption.textContent = details.caption;
        figure.appendChild(caption);
      }
      content.appendChild(figure);
    });

    const body = document.createElement("div");
    body.className = "help-system-body";
    body.innerHTML = (selected.text || selected.body || "").replaceAll(
      "{{ROOT_URL}}",
      ROOT_URL,
    );
    content.appendChild(body);
  } catch (error) {
    title.textContent = "Help unavailable";
    content.innerHTML = '<div class="alert alert-warning mb-0"></div>';
    content.firstElementChild.textContent = error.message;
  }
}

document.addEventListener("keydown", (event) => {
  if (event.key === "Escape") closeHelpSystem();
});

if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", () => enhanceHelpSystemTriggers());
} else {
  enhanceHelpSystemTriggers();
}

new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    mutation.addedNodes.forEach((node) => {
      if (node.nodeType === 1) enhanceHelpSystemTriggers(node);
    });
  });
}).observe(document.documentElement, { childList: true, subtree: true });
