(() => {
  const PAGE_SIZE = 10;

  const PERM_RESOURCES = [
    { key: "dashboard", labelKey: "userGroups.perm.dashboard" },
    { key: "config", labelKey: "userGroups.perm.config" },
    { key: "maps", labelKey: "userGroups.perm.maps" },
    { key: "missions", labelKey: "userGroups.perm.missions" },
    { key: "sounds", labelKey: "userGroups.perm.sounds" },
    { key: "integrations", labelKey: "userGroups.perm.integrations" },
    { key: "users", labelKey: "userGroups.perm.users" },
  ];

  const ICONS = {
    group: `<svg class="userGroupsMirIcon" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true"><circle cx="7" cy="7" r="2.8" fill="none" stroke="currentColor" stroke-width="1.3"/><circle cx="13" cy="7" r="2.8" fill="none" stroke="currentColor" stroke-width="1.3"/><path d="M3.5 16c0-2.5 1.6-4.5 3.5-4.5s3.5 2 3.5 4.5M10 16c0-2.5 1.6-4.5 3.5-4.5s3.5 2 3.5 4.5" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>`,
    edit: `<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M9.5 2.5l2 2L5 11H3v-2L9.5 2.5z" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/></svg>`,
    delete: `<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M4 4l6 6M10 4l-6 6" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>`,
  };

  const el = (id) => document.getElementById(id);
  const t = (key, vars) => window.I18n?.t(key, vars) ?? key;

  const listEl = el("userGroupList");
  const emptyEl = el("userGroupListEmpty");
  const tableEl = el("userGroupsTable");
  const filterInputEl = el("userGroupsFilterInput");
  const filterCountEl = el("userGroupsFilterCount");
  const pageLabelEl = el("userGroupsPageLabel");
  const dialogEl = el("userGroupEditDialog");
  const formEl = el("userGroupEditForm");
  const titleEl = el("userGroupEditTitle");
  const deleteBtnEl = el("userGroupEditDeleteBtn");
  const permsBodyEl = el("userGroupEditPermsBody");
  const deleteConfirmDialogEl = el("userGroupDeleteConfirmDialog");
  const deleteConfirmTextEl = el("userGroupDeleteConfirmText");

  const fields = {
    name: el("userGroupEditName"),
    allowPin: el("userGroupEditAllowPin"),
  };

  const store = {
    groups: [],
    editingId: null,
    pendingDeleteId: null,
    filter: "",
    page: 1,
    permSelects: {},
  };

  function canWrite() {
    if (!window.AuthApp?.canWrite) return true;
    return window.AuthApp.canWrite("users");
  }

  function isDistributor() {
    return window.AuthApp?.getUser?.()?.group_id === "group_distributors";
  }

  function canManageGroup(group) {
    if (!group) return canWrite();
    if (isDistributor()) return canWrite();
    return canWrite() && group.id !== "group_distributors" && group.id !== "group_administrators";
  }

  function escapeHtml(str) {
    return String(str)
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;");
  }

  async function apiJson(url, opts = {}) {
    const res = await fetch(url, { credentials: "include", ...opts });
    const text = await res.text();
    let data = null;
    try {
      data = text ? JSON.parse(text) : null;
    } catch {
      data = null;
    }
    if (!res.ok) throw new Error((data && data.error) || text || res.statusText);
    return data;
  }

  async function refreshAll() {
    const data = await apiJson("/api/user_groups");
    store.groups = Array.isArray(data.groups) ? data.groups : [];
  }

  function groupById(id) {
    return store.groups.find((g) => g.id === id) || null;
  }

  function filteredGroups() {
    const q = store.filter.trim().toLowerCase();
    let items = [...store.groups].sort((a, b) => (a.name || "").localeCompare(b.name || ""));
    if (q) {
      items = items.filter((g) => (g.name || "").toLowerCase().includes(q));
    }
    return items;
  }

  function pageCount(total) {
    return Math.max(1, Math.ceil(total / PAGE_SIZE));
  }

  function pagedItems(items) {
    const totalPages = pageCount(items.length);
    if (store.page > totalPages) store.page = totalPages;
    if (store.page < 1) store.page = 1;
    const start = (store.page - 1) * PAGE_SIZE;
    return items.slice(start, start + PAGE_SIZE);
  }

  function updatePagerUi(totalItems) {
    const totalPages = pageCount(totalItems);
    if (filterCountEl) filterCountEl.textContent = t("userGroups.itemsFound", { n: totalItems });
    if (pageLabelEl) pageLabelEl.textContent = t("userGroups.pageOf", { page: store.page, total: totalPages });
    const atStart = store.page <= 1;
    const atEnd = store.page >= totalPages;
    el("userGroupsPageFirst")?.toggleAttribute("disabled", atStart);
    el("userGroupsPagePrev")?.toggleAttribute("disabled", atStart);
    el("userGroupsPageNext")?.toggleAttribute("disabled", atEnd);
    el("userGroupsPageLast")?.toggleAttribute("disabled", atEnd);
  }

  function permSummary(group) {
    const perms = group.permissions || {};
    const writeCount = PERM_RESOURCES.filter((r) => perms[r.key] === "write").length;
    const readCount = PERM_RESOURCES.filter((r) => perms[r.key] === "read").length;
    if (writeCount === PERM_RESOURCES.length) return t("userGroups.permSummaryAllWrite");
    if (writeCount === 0 && readCount === 0) return t("userGroups.permSummaryNone");
    return t("userGroups.permSummaryMixed", { write: writeCount, read: readCount });
  }

  function renderList() {
    if (!listEl) return;
    const items = filteredGroups();
    const pageItems = pagedItems(items);
    updatePagerUi(items.length);

    listEl.innerHTML = "";
    const showEmpty = items.length === 0;
    if (tableEl) tableEl.hidden = showEmpty;
    if (emptyEl) {
      emptyEl.hidden = !showEmpty;
      emptyEl.textContent = store.filter.trim() ? t("userGroups.emptyFilter") : t("userGroups.empty");
    }

    pageItems.forEach((group) => {
      const tr = document.createElement("tr");
      tr.className = "mapsMirRow userGroupsMirRow";
      tr.dataset.id = group.id;

      const manageable = canManageGroup(group);
      const canDelete = manageable && !group.builtin && (group.user_count || 0) === 0;
      const actions = canWrite()
        ? `<div class="mapsMirRowActions">
            <button type="button" class="mapsMirIconBtn userGroupEditBtn" data-edit="${escapeHtml(group.id)}" title="${escapeHtml(t("common.edit"))}" ${manageable ? "" : "disabled"}>${ICONS.edit}</button>
            <button type="button" class="mapsMirIconBtn mapsMirIconBtn--danger userGroupDeleteBtn" data-delete="${escapeHtml(group.id)}" title="${escapeHtml(t("common.delete"))}" ${canDelete ? "" : "disabled"}>${ICONS.delete}</button>
          </div>`
        : "";

      const pinLabel = group.allow_pin ? t("userGroups.pinYes") : t("userGroups.pinNo");
      const usersLabel = t("userGroups.userCount", { n: group.user_count || 0 });

      tr.innerHTML = `
        <td class="userGroupsMirCellIcon">${ICONS.group}</td>
        <td class="userGroupsMirCellName">
          <button type="button" class="mapsMirNameLink userGroupsMirNameLink" data-edit="${escapeHtml(group.id)}" ${manageable ? "" : "disabled"}>${escapeHtml(group.name || "—")}</button>
        </td>
        <td>${escapeHtml(usersLabel)}</td>
        <td>${escapeHtml(pinLabel)}</td>
        <td class="userGroupsMirCellPerms">${escapeHtml(permSummary(group))}</td>
        <td class="mapsMirCellFunctions">${actions}</td>
      `;
      listEl.appendChild(tr);
    });
  }

  function buildPermRows(permissions = {}) {
    if (!permsBodyEl) return;
    permsBodyEl.innerHTML = "";
    store.permSelects = {};
    PERM_RESOURCES.forEach((res) => {
      const tr = document.createElement("tr");
      const select = document.createElement("select");
      select.className = "userGroupsPermSelect";
      select.dataset.resource = res.key;
      ["none", "read", "write"].forEach((level) => {
        const opt = document.createElement("option");
        opt.value = level;
        opt.textContent = t(`userGroups.permLevel.${level}`);
        select.appendChild(opt);
      });
      select.value = permissions[res.key] || "none";
      store.permSelects[res.key] = select;

      tr.innerHTML = `<th scope="row">${escapeHtml(t(res.labelKey))}</th>`;
      const td = document.createElement("td");
      td.appendChild(select);
      tr.appendChild(td);
      permsBodyEl.appendChild(tr);
    });
  }

  function readPermissionsFromForm() {
    const perms = {};
    PERM_RESOURCES.forEach((res) => {
      const select = store.permSelects[res.key];
      perms[res.key] = select?.value || "none";
    });
    return perms;
  }

  function openCreateDialog() {
    store.editingId = null;
    if (titleEl) titleEl.textContent = t("userGroups.createTitle");
    if (fields.name) {
      fields.name.value = "";
      fields.name.disabled = false;
    }
    if (fields.allowPin) fields.allowPin.checked = false;
    buildPermRows(defaultPermissionsForNewGroup());
    deleteBtnEl?.toggleAttribute("hidden", true);
    dialogEl?.showModal();
  }

  function defaultPermissionsForNewGroup() {
    return {
      dashboard: "write",
      config: "none",
      maps: "none",
      missions: "read",
      sounds: "read",
      integrations: "read",
      users: "none",
    };
  }

  function openEditDialog(id) {
    const group = groupById(id);
    if (!group || !canManageGroup(group)) return;
    store.editingId = id;
    if (titleEl) titleEl.textContent = t("userGroups.editTitle");
    if (fields.name) fields.name.value = group.name || "";
    if (fields.allowPin) fields.allowPin.checked = !!group.allow_pin;
    buildPermRows(group.permissions || {});
    const canDelete = !group.builtin && (group.user_count || 0) === 0;
    deleteBtnEl?.toggleAttribute("hidden", !canDelete);
    dialogEl?.showModal();
  }

  async function saveGroup(evt) {
    evt?.preventDefault();
    const name = (fields.name?.value || "").trim();
    if (!name) {
      alert(t("userGroups.error.missing"));
      return;
    }
    const payload = {
      name,
      allow_pin: !!fields.allowPin?.checked,
      permissions: readPermissionsFromForm(),
    };
    try {
      if (store.editingId) {
        await apiJson(`/api/user_groups/${encodeURIComponent(store.editingId)}`, {
          method: "PUT",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
        });
      } else {
        await apiJson("/api/user_groups", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
        });
      }
      dialogEl?.close();
      await refreshAll();
      renderList();
    } catch (e) {
      alert(e.message);
    }
  }

  function openDeleteConfirm(id) {
    const group = groupById(id);
    if (!group || group.builtin || (group.user_count || 0) > 0) return;
    store.pendingDeleteId = id;
    if (deleteConfirmTextEl) {
      deleteConfirmTextEl.textContent = t("userGroups.deleteConfirmText", { name: group.name || "" });
    }
    deleteConfirmDialogEl?.showModal();
  }

  function openDeleteConfirmFromDialog() {
    if (store.editingId) openDeleteConfirm(store.editingId);
  }

  async function confirmDelete() {
    const id = store.pendingDeleteId;
    if (!id) return;
    try {
      await apiJson(`/api/user_groups/${encodeURIComponent(id)}`, { method: "DELETE" });
      store.pendingDeleteId = null;
      deleteConfirmDialogEl?.close();
      dialogEl?.close();
      await refreshAll();
      renderList();
    } catch (e) {
      alert(e.message);
    }
  }

  function clearFilters() {
    store.filter = "";
    store.page = 1;
    if (filterInputEl) filterInputEl.value = "";
    renderList();
  }

  function bindEvents() {
    el("userGroupCreateBtn")?.addEventListener("click", () => {
      if (canWrite()) openCreateDialog();
    });
    formEl?.addEventListener("submit", saveGroup);
    el("userGroupEditCancelBtn")?.addEventListener("click", () => dialogEl?.close());
    deleteBtnEl?.addEventListener("click", openDeleteConfirmFromDialog);

    listEl?.addEventListener("click", (evt) => {
      const editBtn = evt.target.closest("[data-edit]");
      const deleteBtn = evt.target.closest("[data-delete]");
      if (editBtn?.dataset.edit) openEditDialog(editBtn.dataset.edit);
      else if (deleteBtn?.dataset.delete) openDeleteConfirm(deleteBtn.dataset.delete);
    });

    deleteConfirmDialogEl?.addEventListener("cancel", (evt) => {
      evt.preventDefault();
      store.pendingDeleteId = null;
      deleteConfirmDialogEl?.close();
    });
    el("userGroupDeleteCancelBtn")?.addEventListener("click", () => {
      store.pendingDeleteId = null;
      deleteConfirmDialogEl?.close();
    });
    el("userGroupDeleteYesBtn")?.addEventListener("click", confirmDelete);

    filterInputEl?.addEventListener("input", () => {
      store.filter = filterInputEl.value;
      store.page = 1;
      renderList();
    });
    el("userGroupsClearFiltersBtn")?.addEventListener("click", clearFilters);
    el("userGroupsPageFirst")?.addEventListener("click", () => {
      store.page = 1;
      renderList();
    });
    el("userGroupsPagePrev")?.addEventListener("click", () => {
      store.page = Math.max(1, store.page - 1);
      renderList();
    });
    el("userGroupsPageNext")?.addEventListener("click", () => {
      store.page += 1;
      renderList();
    });
    el("userGroupsPageLast")?.addEventListener("click", () => {
      store.page = pageCount(filteredGroups().length);
      renderList();
    });
    el("userGroupsHelpBtn")?.addEventListener("click", () => alert(t("userGroups.helpBody")));

    window.addEventListener("lm:locale-change", () => {
      if (store.editingId || dialogEl?.open) {
        const perms = readPermissionsFromForm();
        buildPermRows(perms);
      }
      renderList();
    });
  }

  async function onPageShow() {
    if (!window.AuthApp?.canAccessPage?.("user-groups")) return;
    document.body.classList.toggle("auth-readonly-user-groups", !canWrite());
    try {
      await refreshAll();
      renderList();
    } catch (e) {
      if (emptyEl) {
        emptyEl.hidden = false;
        emptyEl.textContent = e.message;
      }
      if (tableEl) tableEl.hidden = true;
    }
  }

  function onPageHide() {
    dialogEl?.close();
    deleteConfirmDialogEl?.close();
  }

  bindEvents();
  window.UserGroupsApp = { onPageShow, onPageHide };
})();
