function initializeGroupEditor() {
  $(".groupSpecificProperties").click((e) => {
    const groupPropertyAction = e.currentTarget.id;
    if (groupPropertyAction === "enableGroupProps") {
      $("#groupSpecificPropertiesModal").modal("show");
      $("#gsproperties-label").text(i18next.t("Confirm Enable Group Specific Properties"));
      $("#groupSpecificPropertiesModal .modal-body span").text(
        i18next.t(
          "This will create a group-specific properties table for this group.  You should then add needed properties with the Group-Specific Properties Form Editor.",
        ),
      );
      $("#setgroupSpecificProperties").text(i18next.t("Enable Group Specific Properties"));
      $("#setgroupSpecificProperties").data("action", 1);
    } else {
      $("#groupSpecificPropertiesModal").modal("show");
      $("#gsproperties-label").text(i18next.t("Confirm Disable Group Specific Properties"));
      $("#groupSpecificPropertiesModal .modal-body span").text(
        i18next.t(
          "Are you sure you want to remove the group-specific person properties?  All group member properties data will be lost!",
        ),
      );
      $("#setgroupSpecificProperties").text(i18next.t("Disable Group Specific Properties"));
      $("#setgroupSpecificProperties").data("action", 0);
    }
  });

  $("#setgroupSpecificProperties").click((e) => {
    const action = $("#setgroupSpecificProperties").data("action");
    $.ajax({
      method: "POST",
      url: `${window.CRM.root}/api/groups/${groupID}/setGroupSpecificPropertyStatus`,
      data: JSON.stringify({ GroupSpecificPropertyStatus: action }),
      contentType: "application/json; charset=utf-8",
      dataType: "json",
    })
      .done((data) => {
        location.reload();
      })
      .fail((xhr, status, error) => {
        console.error("Failed to set group specific property status:", error);
        window.CRM.notify(i18next.t("Failed to update properties. Please try again."), {
          type: "danger",
          delay: 5000,
        });
      });
  });

  $("#selectGroupIDDiv").hide();
  $("#cloneGroupRole").click((e) => {
    if (e.target.checked) {
      $("#selectGroupIDDiv").show();
    } else {
      $("#selectGroupIDDiv").hide();
      $("#seedGroupID").prop("selectedIndex", 0);
    }
  });

  $("#groupEditForm").submit((e) => {
    e.preventDefault();

    const formData = {
      groupName: $("input[name='Name']").val(),
      description: $("textarea[name='Description']").val(),
      groupType: $("select[name='GroupType'] option:selected").val(),
    };

    $.ajax({
      method: "POST",
      url: `${window.CRM.root}/api/groups/${groupID}`,
      data: JSON.stringify(formData),
      contentType: "application/json; charset=utf-8",
      dataType: "json",
    })
      .done((data) => {
        if (data.groupType === i18next.t("Sunday School")) {
          window.location.href = `${window.CRM.root}/groups/sundayschool/dashboard`;
        } else {
          window.location.href = `${window.CRM.root}/groups/dashboard`;
        }
      })
      .fail((xhr, status, error) => {
        console.error("Failed to update group:", error);
        window.CRM.notify(i18next.t("Failed to update group. Please try again."), {
          type: "danger",
          delay: 5000,
        });
      });
  });

  $("#addNewRole").click((e) => {
    const newRoleName = $("#newRole").val();

    $.ajax({
      method: "POST",
      url: `${window.CRM.root}/api/groups/${groupID}/roles`,
      data: JSON.stringify({ roleName: newRoleName }),
      contentType: "application/json; charset=utf-8",
      dataType: "json",
    })
      .done((data) => {
        const newRole = data.newRole;
        const newRow = {
          lst_OptionName: newRole.roleName,
          lst_OptionID: newRole.roleID,
          lst_OptionSequence: newRole.sequence,
        };
        roleCount += 1;
        dataT.row.add(newRow);
        dataT.rows().invalidate().draw(true);
        $("#newRole").val("");
        window.CRM.notify(i18next.t("Role added successfully."), {
          type: "success",
          delay: 3000,
        });
      })
      .fail((xhr, status, error) => {
        console.error("Failed to add new role:", error);
        window.CRM.notify(i18next.t("Failed to add role. Please try again."), {
          type: "danger",
          delay: 5000,
        });
      });
  });

  $(document).on("click", ".deleteRole", (e) => {
    const roleID = e.currentTarget.id.split("-")[1];
    $.ajax({
      method: "DELETE",
      url: `${window.CRM.root}/api/groups/${groupID}/roles/${roleID}`,
      encode: true,
      dataType: "json",
    })
      .done((data) => {
        dataT.clear();
        dataT.rows.add(data);
        // If we delete the default group role, set the default group role to 1 before re-rendering
        if (roleID == defaultRoleID) {
          defaultRoleID = 1;
        }
        dataT.rows().invalidate().draw(true);
        window.CRM.notify(i18next.t("Role deleted successfully."), {
          type: "success",
          delay: 3000,
        });
      })
      .fail((xhr, status, error) => {
        console.error("Failed to delete role:", error);
        window.CRM.notify(i18next.t("Failed to delete role. Please try again."), {
          type: "danger",
          delay: 5000,
        });
      });
  });

  $(document).on("click", ".rollOrder", (e) => {
    const roleID = e.currentTarget.id.split("-")[1];
    const roleSequenceAction = e.currentTarget.id.split("-")[0];
    let newRoleSequence = 0;

    const currentRoleSequence = dataT
      .cell((idx, data, node) => {
        return data.lst_OptionID == roleID;
      }, 2)
      .data();

    if (roleSequenceAction === "roleUp") {
      newRoleSequence = Number(currentRoleSequence) - 1;
    } else if (roleSequenceAction === "roleDown") {
      newRoleSequence = Number(currentRoleSequence) + 1;
    }

    const replaceRow = dataT.row((idx, data, node) => {
      return data.lst_OptionSequence == newRoleSequence;
    });

    const d = replaceRow.data();
    d.lst_OptionSequence = currentRoleSequence;
    setGroupRoleOrder(groupID, d.lst_OptionID, d.lst_OptionSequence);
    replaceRow.data(d);

    dataT
      .cell((idx, data, node) => {
        return data.lst_OptionID == roleID;
      }, 2)
      .data(newRoleSequence);

    setGroupRoleOrder(groupID, roleID, newRoleSequence);
    dataT.rows().invalidate().draw(true);
    dataT.order([[2, "asc"]]).draw();
  });

  $(document).on("change", ".roleName", (e) => {
    const groupRoleName = e.target.value;
    const roleID = e.target.id.split("-")[1];
    $.ajax({
      method: "POST",
      url: `${window.CRM.root}/api/groups/${groupID}/roles/${roleID}`,
      data: JSON.stringify({ groupRoleName }),
      contentType: "application/json; charset=utf-8",
      dataType: "json",
    })
      .done((data) => {
        // Role name updated successfully
        window.CRM.notify(i18next.t("Role name updated."), {
          type: "success",
          delay: 3000,
        });
      })
      .fail((xhr, status, error) => {
        console.error("Failed to update role name:", error);
        window.CRM.notify(i18next.t("Failed to update role name. Please try again."), {
          type: "danger",
          delay: 5000,
        });
      });
  });

  $(document).on("click", ".defaultRole", (e) => {
    const roleID = e.target.id.split("-")[1];
    $.ajax({
      method: "POST",
      url: `${window.CRM.root}/api/groups/${groupID}/defaultRole`,
      data: JSON.stringify({ roleID }),
      contentType: "application/json; charset=utf-8",
      dataType: "json",
    })
      .done((data) => {
        defaultRoleID = roleID;
        dataT.rows().invalidate().draw(true);
        window.CRM.notify(i18next.t("Default role updated."), {
          type: "success",
          delay: 3000,
        });
      })
      .fail((xhr, status, error) => {
        console.error("Failed to set default role:", error);
        window.CRM.notify(i18next.t("Failed to set default role. Please try again."), {
          type: "danger",
          delay: 5000,
        });
      });
  });

  const dataTableConfig = {
    data: groupRoleData,
    columns: [
      {
        width: "auto",
        title: i18next.t("Role Name"),
        data: "lst_OptionName",
        render: (data, type, full, meta) => {
          if (type === "display") {
            const isReadOnly = data === "Student" || data === "Teacher";
            // i18next-disable-next-line
            const displayValue = isReadOnly ? i18next.t(data) : data;
            const readOnlyAttr = isReadOnly ? " readonly" : "";
            // Escape HTML to prevent XSS
            const escapedValue = $("<div>").text(displayValue).html();
            return `<input type="text" class="roleName" id="roleName-${full.lst_OptionID}" value="${escapedValue}"${readOnlyAttr}>`;
          }
          return data;
        },
      },
      {
        width: "auto",
        title: i18next.t("Make Default"),
        data: null,
        render: (data, type, full, meta) => {
          if (full.lst_OptionID == defaultRoleID) {
            return `<strong><i class="fa-solid fa-check me-1"></i>${i18next.t("Default")}</strong>`;
          } else {
            return `<button type="button" id="defaultRole-${full.lst_OptionID}" class="btn btn-success defaultRole">${i18next.t("Default")}</button>`;
          }
        },
      },
      {
        width: "200px",
        title: i18next.t("Sequence"),
        data: "lst_OptionSequence",
        className: "dt-body-center",
        render: (data, type, full, meta) => {
          if (type === "display") {
            let sequenceCell = "";
            if (data > 1) {
              sequenceCell += `<button type="button" id="roleUp-${full.lst_OptionID}" class="btn rollOrder"> <i class="fa-solid fa-arrow-up"></i></button>&nbsp;`;
            }
            sequenceCell += data;
            if (data != roleCount) {
              sequenceCell += `&nbsp;<button type="button" id="roleDown-${full.lst_OptionID}" class="btn rollOrder"> <i class="fa-solid fa-arrow-down"></i></button>`;
            }
            return sequenceCell;
          }
          return data;
        },
      },
      {
        width: "auto",
        title: i18next.t("Delete"),
        data: null,
        render: (data, type, full, meta) => {
          const isProtected = full.lst_OptionName === "Student" || full.lst_OptionName === "Teacher";
          const disabledAttr = isProtected ? " disabled" : "";
          return `<button type="button" id="roleDelete-${full.lst_OptionID}" class="btn btn-danger deleteRole"${disabledAttr}>${i18next.t("Delete")}</button>`;
        },
      },
    ],
    order: [[3, "asc"]],
  };
  $.extend(dataTableConfig, window.CRM.plugin.dataTable);
  dataT = $("#groupRoleTable").DataTable(dataTableConfig);
}

// Wait for locales to load before initializing
$(document).ready(function () {
  window.CRM.onLocalesReady(initializeGroupEditor);
});

function setGroupRoleOrder(groupID, roleID, groupRoleOrder) {
  $.ajax({
    method: "POST",
    url: `${window.CRM.root}/api/groups/${groupID}/roles/${roleID}`,
    data: JSON.stringify({ groupRoleOrder }),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
  })
    .done((data) => {
      // Role order updated successfully
    })
    .fail((xhr, status, error) => {
      console.error("Failed to update role order:", error);
    });
}
