(() => {
  const el = (id) => document.getElementById(id);

  const loginScreenEl = el("loginScreen");
  const shellEl = document.querySelector(".shell");
  const loginFormEl = el("loginForm");
  const loginPanelPasswordEl = el("loginPanelPassword");
  const loginPanelPinEl = el("loginPanelPin");
  const loginKeypadEl = el("loginKeypad");
  const loginPinHiddenEl = el("loginPin");
  const loginErrorEl = el("loginError");
  const loginPinErrorEl = el("loginPinError");
  const loginTabPasswordEl = el("loginTabPassword");
  const loginTabPinEl = el("loginTabPin");
  const userMenuBtnEl = el("mirUserBtn");
  const userMenuPanelEl = el("mirUserPanel");
  const changePasswordDialogEl = el("changePasswordDialog");
  const changePasswordFormEl = el("changePasswordForm");
  const changePasswordErrorEl = el("changePasswordError");

  let currentUser = null;
  let ready = false;
  let loginMode = "password";
  let pinDigits = [];
  let pinSubmitting = false;

  const t = (key, vars) => window.I18n?.t(key, vars) ?? key;

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

  function showError(msg, mode = loginMode) {
    const target = mode === "pin" ? loginPinErrorEl : loginErrorEl;
    const other = mode === "pin" ? loginErrorEl : loginPinErrorEl;
    if (other) {
      other.textContent = "";
      other.setAttribute("hidden", "");
    }
    if (!target) return;
    target.textContent = msg || "";
    if (msg) target.removeAttribute("hidden");
    else target.setAttribute("hidden", "");
  }

  function renderPinCells() {
    document.querySelectorAll(".loginPinCell").forEach((cell, index) => {
      cell.classList.toggle("filled", index < pinDigits.length);
      cell.classList.toggle("active", index === pinDigits.length && pinDigits.length < 4);
    });
  }

  function resetPin() {
    pinDigits = [];
    pinSubmitting = false;
    if (loginPinHiddenEl) loginPinHiddenEl.value = "";
    renderPinCells();
    showError("", "pin");
  }

  async function submitPinFromKeypad() {
    if (pinSubmitting || pinDigits.length !== 4) return;
    pinSubmitting = true;
    setLoginLoading(true);
    showError("", "pin");
    try {
      await loginPin(pinDigits.join(""));
    } catch (e) {
      const msg = String(e.message || "");
      if (msg.includes("invalid pin") || msg.includes("401")) {
        showError(t("login.error.invalidPin"), "pin");
      } else {
        showError(msg || t("login.error.invalidPinShort"), "pin");
      }
      resetPin();
      setLoginLoading(false);
    }
  }

  function appendPinDigit(digit) {
    if (pinSubmitting || pinDigits.length >= 4) return;
    pinDigits.push(digit);
    if (loginPinHiddenEl) loginPinHiddenEl.value = pinDigits.join("");
    renderPinCells();
    if (pinDigits.length === 4) submitPinFromKeypad();
  }

  function backspacePin() {
    if (pinSubmitting) return;
    pinDigits.pop();
    if (loginPinHiddenEl) loginPinHiddenEl.value = pinDigits.join("");
    renderPinCells();
    showError("", "pin");
  }

  function setLoginLoading(loading) {
    loginScreenEl?.classList.toggle("is-loading", loading);
    document.querySelectorAll(".loginSubmitLabel").forEach((label) => {
      label.textContent = loading ? t("login.submitting") : t("login.submit");
    });
  }

  function setLoginMode(mode) {
    loginMode = mode;
    const pin = mode === "pin";
    loginPanelPasswordEl?.toggleAttribute("hidden", pin);
    loginPanelPinEl?.toggleAttribute("hidden", !pin);
    loginTabPasswordEl?.classList.toggle("active", !pin);
    loginTabPinEl?.classList.toggle("active", pin);
    loginTabPasswordEl?.setAttribute("aria-selected", pin ? "false" : "true");
    loginTabPinEl?.setAttribute("aria-selected", pin ? "true" : "false");
    showError("", "password");
    showError("", "pin");
    if (pin) {
      resetPin();
      renderPinCells();
    }
  }

  function permissionLevel(resource) {
    const perms = currentUser?.permissions || {};
    return perms[resource] || "none";
  }

  function isDistributor() {
    return currentUser?.group_id === "group_distributors";
  }

  function canAccessPage(page) {
    if (page === "config") return isDistributor();

    const map = {
      dashboard: "dashboard",
      maps: "maps",
      missions: "missions",
      sounds: "sounds",
      transitions: "maps",
      "user-groups": "users",
      "io-modules": "integrations",
      paths: "maps",
      "path-guides": "maps",
      users: "users",
      integrations: "integrations",
    };
    const resource = map[page];
    if (!resource) return true;
    return permissionLevel(resource) !== "none";
  }

  function canWrite(resource) {
    return permissionLevel(resource) === "write";
  }

  function applyNavPermissions() {
    if (window.NavApp?.applyPermissions) {
      window.NavApp.applyPermissions();
    }
    document.body.classList.toggle("auth-readonly-config", !canWrite("config"));
    document.body.classList.toggle("auth-readonly-maps", !canWrite("maps"));
    document.body.classList.toggle("auth-readonly-missions", !canWrite("missions"));
    document.body.classList.toggle("auth-readonly-sounds", !canWrite("sounds") && !canWrite("integrations"));
    document.body.classList.toggle("auth-readonly-integrations", !canWrite("integrations"));
    document.body.classList.toggle("auth-readonly-users", !canWrite("users"));
    document.body.classList.toggle("auth-readonly-user-groups", !canWrite("users"));
    document.body.classList.toggle("auth-readonly-io-modules", !canWrite("integrations"));
    document.body.classList.toggle("auth-readonly-paths", !canWrite("maps"));
    document.body.classList.toggle("auth-readonly-path-guides", !canWrite("maps"));
  }

  function updateUserMenu() {
    if (!currentUser) return;
    if (window.TopbarApp?.updateUserMenu) {
      window.TopbarApp.updateUserMenu(currentUser);
      return;
    }
    if (userMenuBtnEl) {
      const label = (currentUser.group_name || "USER").toUpperCase();
      userMenuBtnEl.title = `${currentUser.display_name || currentUser.username} (${currentUser.group_name || ""})`;
      const labelEl = el("mirUserLabel");
      if (labelEl) labelEl.textContent = label;
    }
  }

  function unlockApp() {
    setLoginLoading(false);
    document.body.classList.remove("auth-logged-out");
    if (loginScreenEl) {
      loginScreenEl.setAttribute("hidden", "");
      loginScreenEl.style.display = "none";
    }
    if (shellEl) {
      shellEl.classList.remove("auth-locked");
      shellEl.style.display = "";
    }
    applyNavPermissions();
    ready = true;
    window.dispatchEvent(new CustomEvent("lm:auth-ready", { detail: { user: currentUser } }));
    updateUserMenu();
  }

  function lockApp() {
    ready = false;
    currentUser = null;
    document.body.classList.add("auth-logged-out");
    window.TopbarApp?.hideJoystickOverlay?.();
    if (shellEl) shellEl.classList.add("auth-locked");
    if (loginScreenEl) {
      loginScreenEl.removeAttribute("hidden");
      loginScreenEl.style.display = "";
    }
    showError("", "password");
    showError("", "pin");
    resetPin();
  }

  async function tryRestoreSession() {
    try {
      const data = await apiJson("/api/auth/me");
      if (!data?.user) {
        lockApp();
        return false;
      }
      currentUser = data.user;
      unlockApp();
      return true;
    } catch {
      lockApp();
      return false;
    }
  }

  async function loginPassword(username, password) {
    showError("", "password");
    const data = await apiJson("/api/auth/login", {
      method: "POST",
      body: JSON.stringify({ username, password }),
    });
    currentUser = data.user;
    unlockApp();
  }

  async function loginPin(pin) {
    showError("", "pin");
    const data = await apiJson("/api/auth/login", {
      method: "POST",
      body: JSON.stringify({ pin }),
    });
    currentUser = data.user;
    unlockApp();
  }

  async function logout() {
    try {
      await window.TopbarApp?.disengageJoystick?.();
    } catch {
      /* ignore */
    }
    window.TopbarApp?.hideJoystickOverlay?.();
    try {
      await apiJson("/api/auth/logout", { method: "POST", body: "{}" });
    } catch {
      /* ignore */
    }
    currentUser = null;
    ready = false;
    lockApp();
    userMenuPanelEl?.setAttribute("hidden", "");
    window.dispatchEvent(new Event("lm:auth-logout"));
  }

  async function saveProfile() {
    const display_name = el("mirProfileDisplayName")?.value?.trim() || "";
    if (!display_name) throw new Error(t("auth.profile.displayNameRequired"));
    const data = await apiJson("/api/auth/profile", {
      method: "PUT",
      body: JSON.stringify({ display_name }),
    });
    currentUser = data.user;
    updateUserMenu();
  }

  function bindEvents() {
    loginTabPasswordEl?.addEventListener("click", (evt) => {
      evt.preventDefault();
      setLoginMode("password");
    });
    loginTabPinEl?.addEventListener("click", (evt) => {
      evt.preventDefault();
      setLoginMode("pin");
    });

    loginFormEl?.addEventListener("submit", async (evt) => {
      evt.preventDefault();
      const username = el("loginUsername")?.value?.trim() || "";
      const password = el("loginPasswordInput")?.value || "";
      if (!username || !password) {
        showError(t("login.error.missingCredentials"), "password");
        return;
      }
      setLoginLoading(true);
      showError("", "password");
      try {
        await loginPassword(username, password);
      } catch (e) {
        const msg = String(e.message || "");
        if (msg.includes("credentials") || msg.includes("401")) {
          showError(t("login.error.badCredentials"), "password");
        } else if (msg.includes("fetch") || msg.includes("Failed")) {
          showError(t("login.error.serverUnreachable"), "password");
        } else {
          showError(msg || t("login.error.failed"), "password");
        }
        setLoginLoading(false);
      }
    });

    loginKeypadEl?.addEventListener("click", (evt) => {
      const btn = evt.target.closest("[data-key]");
      if (!btn || pinSubmitting) return;
      const key = btn.getAttribute("data-key");
      if (key === "back") {
        backspacePin();
        return;
      }
      if (/^[0-9]$/.test(key)) appendPinDigit(key);
    });

    document.addEventListener("keydown", (evt) => {
      if (loginMode !== "pin" || pinSubmitting) return;
      if (/^[0-9]$/.test(evt.key)) {
        evt.preventDefault();
        appendPinDigit(evt.key);
      } else if (evt.key === "Backspace") {
        evt.preventDefault();
        backspacePin();
      }
    });

    el("mirUserSignOutBtn")?.addEventListener("click", (evt) => {
      evt.preventDefault();
      logout();
    });

    el("mirUserChangePasswordBtn")?.addEventListener("click", (evt) => {
      evt.preventDefault();
      userMenuPanelEl?.setAttribute("hidden", "");
      changePasswordErrorEl && (changePasswordErrorEl.textContent = "");
      changePasswordDialogEl?.showModal();
    });

    el("mirProfileSaveBtn")?.addEventListener("click", async (evt) => {
      evt.preventDefault();
      try {
        await saveProfile();
        userMenuPanelEl?.setAttribute("hidden", "");
      } catch (e) {
        alert(e.message || t("auth.profile.saveFailed"));
      }
    });

    changePasswordFormEl?.addEventListener("submit", async (evt) => {
      evt.preventDefault();
      const current = el("changePasswordCurrent")?.value || "";
      const next = el("changePasswordNew")?.value || "";
      const confirm = el("changePasswordConfirm")?.value || "";
      if (next !== confirm) {
        if (changePasswordErrorEl) changePasswordErrorEl.textContent = t("auth.changePassword.mismatch");
        return;
      }
      try {
        await apiJson("/api/auth/password", {
          method: "PUT",
          body: JSON.stringify({ current_password: current, new_password: next }),
        });
        changePasswordDialogEl?.close();
        changePasswordFormEl.reset();
      } catch (e) {
        if (changePasswordErrorEl) changePasswordErrorEl.textContent = e.message || t("auth.changePassword.failed");
      }
    });
  }

  window.AuthApp = {
    isReady: () => ready,
    getUser: () => currentUser,
    canAccessPage,
    canWrite,
    logout,
    whenReady(fn) {
      if (ready) fn(currentUser);
      else window.addEventListener("lm:auth-ready", () => fn(currentUser), { once: true });
    },
  };

  bindEvents();
  window.addEventListener("lm:locale-change", () => {
    const loading = loginScreenEl?.classList.contains("is-loading");
    setLoginLoading(loading);
  });
  setLoginMode("password");
  shellEl?.classList.add("auth-locked");
  if (window.location.search) {
    try {
      history.replaceState({}, "", window.location.pathname);
    } catch {
      /* ignore */
    }
  }
  tryRestoreSession();
})();
