function ShowKModal(config, afterRender) {
  const {
    backgroundColor = "#fff",
    headerColor = "#1AA1B8",
    type = "new",
    id = null,
    width = 400,
    height = 300,
    title = "Modal Title",
  } = config;

  // Remove existing modal and overlay if any
  const existingModal = document.getElementById(
    "k-modal-" + config.siteUrl + "-" + config.listName
  );
  const existingOverlay = document.getElementById(
    "k-modal-overlay-" + config.siteUrl + "-" + config.listName
  );
  if (existingModal) existingModal.remove();
  if (existingOverlay) existingOverlay.remove();

  var anotherModalOverlayExist = document.querySelectorAll(
    "[id*=k-modal-overlay-]"
  );

  var zindexNumberoverlay =
    900 + parseInt(anotherModalOverlayExist.length) * 50 + 1;
  var zindexNumbermodal =
    900 + parseInt(anotherModalOverlayExist.length) * 50 + 2;

  // Create overlay
  const overlay = document.createElement("div");
  overlay.id = "k-modal-overlay-" + config.siteUrl + "-" + config.listName;
  overlay.style.position = "fixed";
  overlay.style.top = 0;
  overlay.style.left = 0;
  overlay.style.width = "100%";
  overlay.style.height = "100%";
  overlay.style.backgroundColor = "rgba(0,0,0,0.3)";
  overlay.style.zIndex = zindexNumberoverlay;
  overlay.style.cursor = "default";

  // Prevent scrolling
  document.body.style.overflow = "hidden";

  // Modal container
  const modal = document.createElement("div");
  if (config.type == "new")
    modal.id =
      "k-modal-" + config.siteUrl + "-" + config.listName + "-" + config.id;
  if (config.type == "edit")
    modal.id =
      "k-modal-" + config.siteUrl + "-" + config.listName + "-" + config.id;
  modal.style.position = "fixed";
  modal.style.left = "50%";
  modal.style.top = "50%";
  modal.style.transform = "translate(-50%, -50%)";
  modal.style.width = width + "px";
  modal.style.height = height + "px";
  modal.style.background = backgroundColor;
  modal.style.borderRadius = "10px";
  modal.style.zIndex = zindexNumbermodal;
  modal.style.display = "flex";
  modal.style.flexDirection = "column";
  modal.style.boxShadow = "rgba(0, 0, 0, 0.35) 0px 5px 15px";
  modal.style.padding = "10px";
  modal.style.cursor = "default";
  modal.style.direction = "rtl";
  modal.style.fontSize = "8px !important";

  if (config.defaultColumns) {
    debugger;
    modal.setAttribute("defaultColumns", config.defaultColumns);
    var saveValue =
      config.savedefaultColumns != undefined ? config.savedefaultColumns : true;
    modal.setAttribute("savedefaultColumns", saveValue);
  }

  // Header (top bar)
  const header = document.createElement("div");
  header.style.display = "flex";
  header.style.justifyContent = "space-between";
  header.style.alignItems = "center";
  header.style.cursor = "move";
  header.style.marginBottom = "10px";

  const titleEl = document.createElement("span");
  titleEl.textContent = title;
  titleEl.style.fontWeight = "bold";

  const closeBtn = document.createElement("button");
  closeBtn.textContent = "✖";
  closeBtn.style.border = "none";
  closeBtn.style.background = "transparent";
  closeBtn.style.cursor = "pointer";
  closeBtn.style.fontSize = "16px";
  closeBtn.style.padding = "0";
  closeBtn.style.margin = "0";
  closeBtn.style.width = "50px";
  closeBtn.style.minWidth = "0";

  closeBtn.onclick = () => {
    closeModal(config.siteUrl, config.listName);
  };

  if (!config.TitleVisible) {
    titleEl.style.color = "transparent";
  }
  header.appendChild(titleEl);
  header.appendChild(closeBtn);

  // Create section header helper
  function createSectionHeader(text) {
    const wrapper = document.createElement("div");
    wrapper.style.margin = "10px 0";

    const title = document.createElement("div");
    title.textContent = text;
    title.style.fontWeight = "bold";
    title.style.color = headerColor;
    title.style.fontSize = "12px";

    const line = document.createElement("div");
    line.style.height = "2px";
    line.style.backgroundColor = headerColor;
    line.style.marginTop = "4px";
    line.style.width = "100%";

    wrapper.appendChild(title);
    wrapper.appendChild(line);
    return wrapper;
  }

  // Body
  const body = document.createElement("div");
  body.className = "k-modal-body";
  body.id = "k-modal-body-" + config.siteUrl + "-" + config.listName;
  body.style.flex = "1";
  body.style.overflowY = "auto";
  body.style.padding = "10px";

  // Footer
  const footer = document.createElement("div");
  footer.style.display = "flex";
  if (type == "new") {
    footer.style.justifyContent = "end";
  } else {
    footer.style.justifyContent = "space-between";
  }
  footer.style.marginTop = "10px";

  const saveBtn = document.createElement("button");
  saveBtn.textContent = "✔";
  saveBtn.style.cursor = "pointer";
  saveBtn.style.backgroundColor = "transparent";
  saveBtn.style.border = "none";
  saveBtn.style.transform = "scale(1.5)";
  saveBtn.style.padding = "0";
  saveBtn.style.margin = "0";
  saveBtn.style.width = "50px";
  saveBtn.style.minWidth = "0";
  saveBtn.onclick = async () => {
    await K_SaveModal(
      config.siteUrl,
      config.listName,
      modal.id,
      config.gridData,
      config.callback
    );
  };
  const deleteBtn = document.createElement("button");
  deleteBtn.textContent = "🗑";
  deleteBtn.style.cursor = "pointer";
  deleteBtn.style.backgroundColor = "transparent";
  deleteBtn.style.border = "none";
  deleteBtn.style.transform = "scale(1.5)";
  deleteBtn.style.padding = "0";
  deleteBtn.style.margin = "0";
  deleteBtn.style.width = "50px";
  deleteBtn.style.minWidth = "0";
  deleteBtn.onclick = () =>
    DeleteKModal(config, config.gridData, config.callback);
  deleteBtn.style.display = type === "edit" ? "inline-block" : "none";

  footer.appendChild(deleteBtn);
  footer.appendChild(saveBtn);

  modal.appendChild(header);
  modal.appendChild(body);
  modal.appendChild(footer);

  document.body.appendChild(overlay);
  document.body.appendChild(modal);

  // Draggable modal
  let isDragging = false;
  let offsetX, offsetY;

  header.addEventListener("mousedown", (e) => {
    isDragging = true;
    offsetX = e.clientX - modal.getBoundingClientRect().left;
    offsetY = e.clientY - modal.getBoundingClientRect().top;
    document.body.style.userSelect = "none";
  });

  document.addEventListener("mousemove", (e) => {
    if (!isDragging) return;
    const newLeft = e.clientX - offsetX;
    const newTop = e.clientY - offsetY;
    const maxLeft = window.innerWidth - modal.offsetWidth;
    const maxTop = window.innerHeight - modal.offsetHeight;
    modal.style.left = Math.min(Math.max(newLeft, 0), maxLeft) + "px";
    modal.style.top = Math.min(Math.max(newTop, 0), maxTop) + "px";
    modal.style.transform = "none";
  });

  document.addEventListener("mouseup", () => {
    isDragging = false;
    document.body.style.userSelect = "auto";
  });

  if (afterRender) afterRender(body);

  if (config.type == "edit")
    loadSharePointItemModal(config.siteUrl, config.listName, config.id);

  if (config.type == "new") {
    const modalDiv = document.querySelector(
      `[id*='k-modal-${config.siteUrl}-${config.listName}-']`
    );
    defaultColumnsArray = JSON.parse(modalDiv.getAttribute("defaultColumns"));

    const elements = document.querySelectorAll(
      "[id^='K_Modal_" + config.listName + "']"
    );

    elements.forEach((el) => {
      const parts = el.id.split("_");

      // only accept IDs with exactly 4 parts: ["K", "Modal", "listName", "Name"]
      if (parts.length !== 4) return;

      const fieldName = parts[3];

      // check if SharePoint item has that field
      defaultColumnsArray.forEach((dfc) => {
        if (fieldName == Object.entries(dfc)[0][0]) {
          el.value = Object.entries(dfc)[0][1];
        }
      });
    });
  }
}

async function DeleteKModal(config, gridData, callback) {
  console.log(config);
  var okToDelte = confirm("آیا از حذف مورد اطمینان دارید؟");
  if (okToDelte) {
    await DeleteModalListSelectedItem(
      config.siteUrl,
      config.listName,
      config.id
    );
    if (gridData) {
      data = JSON.parse(config.gridData[2]);

      data = data.filter((item) => item.ID != config.id);
    }
  }

  if (callback) await callback();

  closeModal(config.siteUrl, config.listName);

  if (gridData) {
    CreateGrid(config.gridData[0], config.gridData[1], data);
  }
}

async function loadSharePointItemModal(siteUrl, listName, itemId) {
  showLoader();

  try {
    const endpoint = `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items(${itemId})`;

    const response = await fetch(endpoint, {
      method: "GET",
      headers: { Accept: "application/json;odata=verbose" },
    });

    if (!response.ok) throw new Error("Failed to fetch item.");

    const data = await response.json();
    const item = data.d;

    // populate the K_ fields
    setTimeout(() => {
      populateFieldsFromItemModal(item, listName, siteUrl);
    }, 100);

    hideLoader();
  } catch (err) {
    hideLoader();
  }
}

function populateFieldsFromItemModal(item, listName, siteUrl) {
  const elements = document.querySelectorAll(
    "[id^='K_Modal_" + listName + "']"
  );

  const modalDiv = document.querySelector(
    `[id*='k-modal-${siteUrl}-${listName}-']`
  );
  defaultColumnsArray = JSON.parse(modalDiv.getAttribute("defaultColumns"));

  elements.forEach((el) => {
    const parts = el.id.split("_");

    // only accept IDs with exactly 4 parts: ["K", "Modal", "listName", "Name"]
    if (parts.length !== 4) return;

    const fieldName = parts[3];

    // check if SharePoint item has that field
    if(defaultColumnsArray) {
      defaultColumnsArray.forEach((dfc) => {
        if (fieldName == Object.entries(dfc)[0][0]) {
          el.value = Object.entries(dfc)[0][1];
        }
      });
    }

    if (item[fieldName] !== undefined) {
      if (el.classList.contains("kform-radio-group")) {
        var allOptions = document.querySelectorAll("[id^='" + el.id + "_']");
        allOptions.forEach((opt) => {
          if (opt.value == item[fieldName]) opt.checked = "checked";
        });
      } else if (el.classList.contains("kform-multilookup")) {
        if(item[fieldName]) {
        el.setValue(item[fieldName].results);
        }
      } else if (
        el.getAttribute("type") == "text" &&
        el.getAttribute("data-original-type") == "number"
      ) {
        let raw = item[fieldName].toString().replace(/[^\d]/g, "");
        if (raw) {
          el.value = raw.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        } else el.value = "";
        el.setSelectionRange(el.value.length, el.value.length);
      } else if (el.tagName == "TEXTAREA") {
        if (item[fieldName] != null) {
          if (item[fieldName].includes("div")) {
            const htmlString = item[fieldName];
            const temp = document.createElement("div");
            temp.innerHTML = htmlString;

            const innerText = temp.textContent.trim();

            el.value = innerText;
          } else {
            el.value = item[fieldName];
          }
        }
      } else if (el.getAttribute("data-jdp") == "true") {
        el.value = new Date(item[fieldName]).toLocaleDateString(
          "fa-IR-u-nu-latn"
        );
      } else if(el.getAttribute("input-type") == "userpicker") {
        debugger
        fetch(
            `${siteUrl}/_api/web/getuserbyid(${item[fieldName]})`,
            {
              method: "POST",
              headers: {
                Accept: "application/json;odata=verbose",
                "Content-Type": "application/json;odata=verbose",
                "X-RequestDigest":
                  document.getElementById("__REQUESTDIGEST").value,
              },
            }
          )
            .then((res) => res.json())
            .then((data) => {
              const user = data.d;
                el.value = user.Title;
                el.dataset.login = user.LoginName;
            })
            .catch((err) => {
              console.error("User picker failed:", err);
            });
      } else {
        el.value = item[fieldName];
      }

      el.dispatchEvent(new Event("change", { bubbles: true }));
    }
  });
}

///////////////////////////////////////////////////////////////////////////////////////////////////// Save

async function saveDirtyGridsModal(Parentid, modalId) {
  if (Parentid) {
    var ParentID = Parentid;
  } else {
    var ParentID = modalId.split("-")[4];
  }

  const grids = document.querySelectorAll(`[id="${modalId}"] .K_Dirty_Grid`);

  for (const grid of grids) {
    const siteUrl = grid.getAttribute("SiteURL");
    const listName = grid.getAttribute("ListName");
    const ParentList = grid.getAttribute("ParentList");

    if (!siteUrl || !listName) {
      console.warn("Grid missing SiteURL or ListName:", grid);
      continue;
    }

    const rows = grid.querySelectorAll(".K_Dirty_Tr");

    for (const tr of rows) {
      const itemId = tr.getAttribute("K_Item_ID");
      const body = {};

      // defaults columns
      if (
        grid.getAttribute("defaultColumns") != null &&
        grid.getAttribute("savedefaultColumns")
      ) {
        defaultColumns = JSON.parse(grid.getAttribute("defaultColumns"));

        for (const dcol of defaultColumns) {
          for (
            var dcolIndex = 0;
            dcolIndex < Object.entries(dcol).length;
            dcolIndex++
          ) {
            const [key, value] = Object.entries(dcol)[dcolIndex];
            body[key] = value;
          }
        }
      }

      debugger;
      // collect inputs
      const inputs = tr.querySelectorAll("[id^='K_Grid_Input_']");

      inputs.forEach((input) => {
        const id = input.id;

        const parts = id.split("_");

        const columnName = parts[4];
        if (input.classList.contains("p-date-picker")) {
          datesArray = input.value.split("/");

          body[columnName] = new Date(
            farvardin.solarToGregorian(
              parseInt(datesArray[0]),
              parseInt(datesArray[1]),
              parseInt(datesArray[2])
            )
          );
        } else if (input.getAttribute("Lookup")) {
          body[columnName + "Id"] = input.value;
        } else {
          body[columnName] = input.value;
        }
      });

      if (itemId.includes("NewItem")) {
        await spAddItemModal(siteUrl, listName, body, ParentID, ParentList);
      } else if (!isNaN(itemId)) {
        await spUpdateItemModal(siteUrl, listName, itemId, body);
      }
    }
  }
}

async function spAddItemModal(siteUrl, listName, body, ParentID, ParentList) {
  body["__metadata"] = { type: await getListItemTypeModal(siteUrl, listName) };

  if (ParentID) {
    body[ParentList + "Id"] = ParentID;
  }
  const endpoint = `${siteUrl}/_api/web/lists/getByTitle('${listName}')/items`;

  const result = await fetch(endpoint, {
    method: "POST",
    headers: {
      Accept: "application/json;odata=verbose",
      "Content-Type": "application/json;odata=verbose",
      "X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
    },
    body: JSON.stringify(body),
  });

  if (!result.ok) {
    console.error("ADD FAILED:", await result.text());
  } else {
    console.log("Item Added:", await result.json());
  }
}

async function spUpdateItemModal(siteUrl, listName, itemId, body) {
  body["__metadata"] = { type: await getListItemTypeModal(siteUrl, listName) };

  const endpoint = `${siteUrl}/_api/web/lists/getByTitle('${listName}')/items(${itemId})`;

  const result = await fetch(endpoint, {
    method: "POST",
    headers: {
      Accept: "application/json;odata=verbose",
      "Content-Type": "application/json;odata=verbose",
      "IF-MATCH": "*",
      "X-HTTP-Method": "MERGE",
      "X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
    },
    body: JSON.stringify(body),
  });

  if (!result.ok) {
    console.error("UPDATE FAILED:", await result.text());
  } else {
    console.log("Item Updated");
  }
}

async function getListItemTypeModal(siteUrl, listName) {
  const endpoint = `${siteUrl}/_api/web/lists/getByTitle('${listName}')?$select=ListItemEntityTypeFullName`;

  const response = await fetch(endpoint, {
    method: "GET",
    headers: {
      Accept: "application/json;odata=verbose",
    },
  });

  const data = await response.json();
  return data.d.ListItemEntityTypeFullName;
}

async function saveDirtyInputsToSharePointModal(
  siteUrl,
  listName,
  modalId,
  gridData
) {
  var modal = document.querySelector(`[id^="${modalId}"]`);
  defaultColumns = modal.getAttribute("defaultColumns");

  let itemId = modalId.split("-")[4];

  // find only the editable inputs
  const inputs = document.querySelectorAll(
    `[id="${modalId}"] input, [id="${modalId}"] select, [id="${modalId}"] textarea, [id="${modalId}"] .kform-radio-group, [id="${modalId}"] .kform-multilookup`
  );
  const payload = {};

  // Parent List ID
  if (defaultColumns) {
    debugger;
    defaultColumns = JSON.parse(defaultColumns);

    for (const dcol of defaultColumns) {
      const [key, value] = Object.entries(dcol)[0];
      payload[key] = value;
    }
  }

  // default global columns
  if (gridData) {
    if (gridData[1].defaultGlobalColumns) {
      defaultGlobalColumns = JSON.parse(gridData[1].defaultGlobalColumns);

      for (const dcol of defaultGlobalColumns) {
        for (
          var dcolIndex = 0;
          dcolIndex < Object.entries(dcol).length;
          dcolIndex++
        ) {
          const [key, value] = Object.entries(dcol)[dcolIndex];
          payload[key] = document.getElementById("Form").getAttribute(value);
        }
      }
    }
  }

  inputs.forEach(async (input) => {
    const parts = input.id.split("_");
    if (parts.length !== 4) return;

    const fieldName = parts[3];

    if (input.classList.contains("kform-radio-group")) {
      const allOptions = document.querySelectorAll("[id^='" + input.id + "_']");
      let checkedOption = "";
      allOptions.forEach((opt) => {
        if (opt.checked) checkedOption = opt.value;
      });
      payload[fieldName] = checkedOption;
    } else if (input.classList.contains("kform-multilookup")) {
      if (input.getValue().length != 0) {
        payload[fieldName] = { results: input.getValue() };
      }
    } else if (input.classList.contains("kform-lookup-select")) {
      if (input.value == "") {
        payload[fieldName] = null;
      } else {
        payload[fieldName] = input.value;
      }
    } else if (input.classList.contains("p-date-picker")) {
      datesArray = input.value.split("/");

      if (input.value != "") {
        payload[fieldName] = new Date(
          farvardin.solarToGregorian(
            parseInt(datesArray[0]),
            parseInt(datesArray[1]),
            parseInt(datesArray[2])
          )
        );
      }
    } else if (input.getAttribute("input-type") == "userpicker") {
      debugger;
      payload[fieldName] = await ensureUser(
        _spPageContextInfo.webAbsoluteUrl,
        input.dataset.login
      );
    } else if (input.getAttribute("type") == "number") {
      inputValue = input.value;
      if (inputValue == "") {
        inputValue = null;
      }
      payload[fieldName] = inputValue;
    } else {
      payload[fieldName] = input.value;
    }
  });

  payload.__metadata = { type: await getListItemTypeModal(siteUrl, listName) };

  let endpoint = `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items`;
  let method = "POST"; // default to create

  if (itemId && !itemId.includes("NewItem")) {
    endpoint += `(${itemId})`;
    method = "MERGE"; // update existing
  }

  console.log(payload);

  const response = await fetch(endpoint, {
    method: method,
    headers: {
      Accept: "application/json;odata=verbose",
      "Content-Type": "application/json;odata=verbose",
      "X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
      "IF-MATCH": "*",
      "X-HTTP-Method": method === "MERGE" ? "MERGE" : undefined,
    },
    body: JSON.stringify(payload),
  });

  // Only parse JSON if there is content
  let data = null;
  const text = await response.text();
  if (text) {
    data = JSON.parse(text);
  }

  if (!response.ok) {
    throw new Error("Failed to save item: " + text);
  }
  payload.ID = !itemId.includes("NewItem") ? parseInt(itemId) : itemId;
  // Return new ID if created, else existing ID
  return {
    itemId: itemId.includes("NewItem")
      ? parseInt(data?.d?.ID)
      : parseInt(itemId),
    payload: JSON.stringify(payload),
  };
}

async function K_SaveModal(site, list, modalId, gridData, callback) {
  showLoader();
  var { itemId, payload } = await saveDirtyInputsToSharePointModal(
    site,
    list,
    modalId,
    gridData
  );
  await saveDirtyGridsModal(itemId, modalId);

  if (callback) await callback();

  closeModal(site, list);

  if (gridData) {
    payload = JSON.parse(payload);
    var jsonstring = gridData[2];
    allData = JSON.parse(jsonstring);

    Object.keys(payload).forEach((key) => {
      const value = payload[key];

      if (isIsoDate(value)) {
        payload[key] = new Date(value).toLocaleDateString("fa-IR-u-nu-latn");
      }
    });

    for (var i = 0; i < allData.length; i++) {
      if (allData[i].ID == payload.ID) {
        payload.ID = itemId;
        allData[i] = payload;
      }
    }
    console.log(allData);
    CreateGrid(gridData[0], gridData[1], allData);
  }
  hideLoader();
}

function isIsoDate(value) {
  return (
    typeof value === "string" &&
    /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/.test(value)
  );
}

// Close modal
function closeModal(site, list) {
  document.querySelector(`[id^='k-modal-${site}-${list}']`)?.remove();
  document.getElementById(`k-modal-overlay-${site}-${list}`)?.remove();
  document.body.style.overflow = "auto";
}

function DeleteModalListSelectedItem(site, listName, itemId) {
  return fetch(
    `${site}/_api/web/lists/getbytitle('${listName}')/items(${itemId})`,
    {
      method: "POST",
      headers: {
        Accept: "application/json;odata=verbose",
        "Content-Type": "application/json;odata=verbose",
        "X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
        "IF-MATCH": "*",
        "X-HTTP-Method": "DELETE",
      },
    }
  );
}
