import { sendRequest } from './networkUtils.js?v={{APP_QVER}}';
import { t, applyTranslations } from './i18n.js?v={{APP_QVER}}';
import {
  toggleVisibility,
  showToast as originalShowToast,
  attachEnterKeyListener,
  showCustomConfirmModal
} from './domUtils.js?v={{APP_QVER}}';
import { loadFileList } from './fileListView.js?v={{APP_QVER}}';
import { initFileActions } from './fileActions.js?v={{APP_QVER}}';
import { renderFileTable } from './fileListView.js?v={{APP_QVER}}';
import { loadFolderTree } from './folderManager.js?v={{APP_QVER}}';
import {
  openTOTPLoginModal as originalOpenTOTPLoginModal,
  openTOTPModal,
  closeTOTPModal,
  setLastLoginData,
  openApiModal
} from './authModals.js?v={{APP_QVER}}';
import { openUserPanel } from './userPanel.js?v={{APP_QVER}}';
import { openAdminPanel } from './adminPanel.js?v={{APP_QVER}}';
import { initializeApp, triggerLogout } from './appCore.js?v={{APP_QVER}}';
import { withBase } from './basePath.js?v={{APP_QVER}}';

// Production OIDC configuration (override via API as needed)
const currentOIDCConfig = {
  providerUrl: "https://your-oidc-provider.com",
  clientId: "",
  clientSecret: "",
  redirectUri: "https://yourdomain.com/api/auth/auth.php?oidc=callback",
  globalOtpauthUrl: ""
};
window.currentOIDCConfig = currentOIDCConfig;

// Shared permissions cache across modules (populated once per tab)
const PERMISSIONS_URL = '/api/profile/getUserPermissions.php';
const DEFAULT_HEADER_TITLE = 'FileRise';
const PRO_DEFAULT_HEADER_TITLE = 'FileRise Pro';

function resolveHeaderTitle(rawTitle, isPro) {
  const cleaned = String(rawTitle || '').trim();
  if (!cleaned || cleaned === DEFAULT_HEADER_TITLE) {
    return isPro ? PRO_DEFAULT_HEADER_TITLE : DEFAULT_HEADER_TITLE;
  }
  return cleaned;
}

async function fetchUserPermissionsOnce() {
  if (window.__FR_PERMISSIONS_CACHE) return window.__FR_PERMISSIONS_CACHE;
  if (window.__FR_PERMISSIONS_PROMISE) return window.__FR_PERMISSIONS_PROMISE;
  window.__FR_PERMISSIONS_PROMISE = (async () => {
    try {
      const r = await fetch(PERMISSIONS_URL, { credentials: 'include' });
      const data = await r.json();
      window.__FR_PERMISSIONS_CACHE = data || {};
      return window.__FR_PERMISSIONS_CACHE;
    } catch (e) {
      window.__FR_PERMISSIONS_CACHE = {};
      return {};
    } finally {
      window.__FR_PERMISSIONS_PROMISE = null;
    }
  })();
  return window.__FR_PERMISSIONS_PROMISE;
}



(function installToastFilter() {
  window.__FR_TOAST_FILTER__ = function (msgKeyOrText) {
    const isDemoMode = !!window.__FR_DEMO__;

    // Suppress the nag while doing TOTP step-up
    if (window.pendingTOTP && (msgKeyOrText === 'please_log_in_to_continue' ||
      /please log in/i.test(String(msgKeyOrText)))) {
      return null; // suppress
    }

    // Demo mode: swap login prompt for demo creds
    if (isDemoMode &&
        (msgKeyOrText === 'please_log_in_to_continue' ||
         /please log in/i.test(String(msgKeyOrText)))) {
      return "Demo site — use:\nUsername: demo\nPassword: demo";
    }

    // Try to translate keys; pass through plain text
    try {
      const maybe = t(msgKeyOrText);
      if (typeof maybe === 'string' && maybe !== msgKeyOrText) return maybe;
    } catch (e) { }
    return msgKeyOrText;
  };
})();

function queueWelcomeToast(name) {
  const uname = String(name || '').trim().slice(0, 80);
  if (!uname) return;
  // show immediately (if we don’t reload instantly)
  try {
    window.dispatchEvent(new CustomEvent('filerise:toast', {
      detail: { message: `Welcome back, ${uname}!`, duration: 2000 }
    }));
  } catch (e) { }

  // and persist for after-reload (flushed by main.js on boot)
  try {
    sessionStorage.setItem('welcomeMessage', `Welcome back, ${uname}!`);
  } catch (e) { }
}

/* ----------------- TOTP & Toast Overrides ----------------- */
// detect if we’re in a pending‑TOTP state
window.pendingTOTP = new URLSearchParams(window.location.search).get('totp_required') === '1';

// override showToast to suppress the "Please log in to continue." toast during TOTP

function showToast(msgKeyOrText, type) {
  const isDemoMode = !!window.__FR_DEMO__;

  // For the pre-login prompt in demo mode, show demo creds instead
  if (isDemoMode &&
      (msgKeyOrText === "please_log_in_to_continue" ||
       /please log in/i.test(String(msgKeyOrText)))) {
    return originalShowToast("Demo site — use: \nUsername: demo\nPassword: demo", 12000);
  }

  // Don’t nag during pending TOTP
  if (window.pendingTOTP && msgKeyOrText === "please_log_in_to_continue") {
    return;
  }

  // Translate if a key; otherwise pass through the raw text
  let msg = msgKeyOrText;
  try {
    const translated = t(msgKeyOrText);
    if (typeof translated === "string" && translated !== msgKeyOrText) {
      msg = translated;
    }
  } catch (e) { }

  return originalShowToast(msg, type);
}

window.showToast = showToast;

const originalFetch = window.fetch;

/*
 * @param {string} url
 * @param {object} options
 * @returns {Promise<Response>}
 */

export async function fetchWithCsrf(url, options = {}) {
  const original = window.fetch.bind(window);
  const wantJson = (options.headers && /json/i.test(options.headers['Content-Type'] || '')) || typeof options.body === 'string' && options.body.trim().startsWith('{');

  options = { credentials: 'include', ...options };
  options.headers = {
    'Accept': 'application/json',
    ...(options.headers || {})
  };
  if (window.csrfToken) {
    options.headers['X-CSRF-Token'] = window.csrfToken;
  }

  async function retryWithFreshCsrf(asFormFallback = false) {
    const tokRes = await original('/api/auth/token.php', { credentials: 'include' });
    if (tokRes.ok) {
      const body = await tokRes.json().catch(() => ({}));
      if (body?.csrf_token) {
        window.csrfToken = body.csrf_token;
        const meta = document.querySelector('meta[name="csrf-token"]');
        if (meta) meta.content = body.csrf_token;
        options.headers['X-CSRF-Token'] = body.csrf_token;
      }
    }
    if (asFormFallback && wantJson) {
      // convert JSON body into x-www-form-urlencoded
      const orig = options.body && typeof options.body === 'string' ? JSON.parse(options.body) : {};
      options.body = toFormBody(orig);
      options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
    }
    return original(url, options);
  }

  let res = await original(url, options);

  // If API doesn’t like JSON or token is stale
  if (res.status === 400 || res.status === 403 || res.status === 415) {
    // 1) retry with fresh CSRF keeping same encoding
    res = await retryWithFreshCsrf(false);
    if (!res.ok && wantJson) {
      // 2) retry again as form-encoded
      res = await retryWithFreshCsrf(true);
    }
  }
  return res;
}

// wrap the TOTP modal opener to disable other login buttons only for Basic/OIDC flows
function openTOTPLoginModal() {
  originalOpenTOTPLoginModal();

  const isFormLogin = Boolean(window.__lastLoginData);
  if (!isFormLogin) {
    // disable Basic‑Auth link
    const basicLink = document.querySelector('a[href$="api/auth/login_basic.php"], a[href$="/api/auth/login_basic.php"]');
    if (basicLink) {
      basicLink.style.pointerEvents = 'none';
      basicLink.style.opacity = '0.5';
    }
    // disable OIDC button
    const oidcBtn = document.getElementById("oidcLoginBtn");
    if (oidcBtn) {
      oidcBtn.disabled = true;
      oidcBtn.style.opacity = '0.5';
    }
    // hide the form login
    const authForm = document.getElementById("authForm");
    if (authForm) authForm.style.display = 'none';
  }
}

/* ----------------- Utility Functions ----------------- */
function updateItemsPerPageSelect() {
  const selectElem = document.querySelector(".form-control.bottom-select");
  if (selectElem) {
    selectElem.value = localStorage.getItem("itemsPerPage") || "10";
  }
}

function applyProxyBypassUI() {
  const bypass = localStorage.getItem("authBypass") === "true";
  const loginContainer = document.getElementById("loginForm");
  if (loginContainer) {
    loginContainer.style.display = bypass ? "none" : "";
  }
}

function updateLoginOptionsUI({ disableFormLogin, disableBasicAuth, disableOIDCLogin }) {
  const authForm = document.getElementById("authForm");
  if
    (authForm) {
    authForm.style.display = disableFormLogin ? "none" : "block";
    setTimeout(() => {
      const loginInput = document.getElementById('loginUsername');
      if (loginInput) loginInput.focus();
    }, 0);
  }
  const basicAuthLink = document.querySelector('a[href$="api/auth/login_basic.php"], a[href$="/api/auth/login_basic.php"]');
  if (basicAuthLink) basicAuthLink.style.display = disableBasicAuth ? "none" : "inline-block";
  const oidcLoginBtn = document.getElementById("oidcLoginBtn");
  if (oidcLoginBtn) oidcLoginBtn.style.display = disableOIDCLogin ? "none" : "inline-block";
}

function updateLoginOptionsUIFromStorage() {
  updateLoginOptionsUI({
    disableFormLogin: localStorage.getItem("disableFormLogin") === "true",
    disableBasicAuth: localStorage.getItem("disableBasicAuth") === "true",
    disableOIDCLogin: localStorage.getItem("disableOIDCLogin") === "true",
    authBypass: localStorage.getItem("authBypass") === "true"
  });
}

export function loadAdminConfigFunc() {
  if (window.__FR_SITE_CFG_PROMISE) return window.__FR_SITE_CFG_PROMISE;
  window.__FR_SITE_CFG_PROMISE = fetch("/api/public/siteConfig.php", { credentials: "include" })
    .then(async (response) => {
      // If a proxy or some edge returns 204/empty, handle gracefully
      let config = {};
      try { config = await response.json(); } catch (e) { config = {}; }

      const isPro = !!(config.pro && config.pro.active);
      const headerTitle = resolveHeaderTitle(config.header_title, isPro);
      localStorage.setItem("headerTitle", headerTitle);

      document.title = headerTitle;
      const lo = config.loginOptions || {};
      localStorage.setItem("disableFormLogin", String(!!lo.disableFormLogin));
      localStorage.setItem("disableBasicAuth", String(!!lo.disableBasicAuth));
      localStorage.setItem("disableOIDCLogin", String(!!lo.disableOIDCLogin));
      localStorage.setItem("globalOtpauthUrl", config.globalOtpauthUrl || "otpauth://totp/{label}?secret={secret}&issuer=FileRise");
      // These may be absent for non-admins; default them
      localStorage.setItem("authBypass", String(!!lo.authBypass));
      localStorage.setItem("authHeaderName", lo.authHeaderName || "X-Remote-User");

      updateLoginOptionsUIFromStorage();

      const headerTitleElem = document.querySelector(".header-title h1");
      if (headerTitleElem) headerTitleElem.textContent = headerTitle;
    })
    .catch(() => {
      // Fallback defaults if request truly fails
      const fallbackTitle = resolveHeaderTitle(
        DEFAULT_HEADER_TITLE,
        window.__FR_IS_PRO === true
      );
      localStorage.setItem("headerTitle", fallbackTitle);
      localStorage.setItem("disableFormLogin", "false");
      localStorage.setItem("disableBasicAuth", "false");
      localStorage.setItem("disableOIDCLogin", "false");
      localStorage.setItem("globalOtpauthUrl", "otpauth://totp/{label}?secret={secret}&issuer=FileRise");
      updateLoginOptionsUIFromStorage();

      const headerTitleElem = document.querySelector(".header-title h1");
      if (headerTitleElem) headerTitleElem.textContent = fallbackTitle;
      document.title = fallbackTitle;
    })
    .finally(() => { window.__FR_SITE_CFG_PROMISE = null; });
  return window.__FR_SITE_CFG_PROMISE;
}

function insertAfter(newNode, referenceNode) {
  referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

async function fetchProfilePicture() {
  try {
    const res = await fetch('/api/profile/getCurrentUser.php', {
      credentials: 'include'
    });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const info = await res.json();
    let pic = info.profile_picture || '';
    // --- take only what's after the *last* colon ---
    const parts = pic.split(':');
    pic = parts[parts.length - 1] || '';
    // strip any stray leading colons
    pic = pic.replace(/^:+/, '');
    // ensure exactly one leading slash
    if (pic) pic = '/' + pic.replace(/^\/+/, '');
    return pic ? withBase(pic) : '';
  } catch (e) {
    console.warn('fetchProfilePicture failed:', e);
    return '';
  }
}

export async function updateAuthenticatedUI(data) {
  // Save latest auth data for later reuse
  window.__lastAuthData = data;

  // 1) Remove loading overlay safely
  const loading = document.getElementById('loadingOverlay');
  if (loading) loading.remove();

  // 2) Show main UI
  document.querySelector('.main-wrapper').style.display = '';
  document.getElementById('loginForm').style.display = 'none';
  toggleVisibility("loginForm", false);
  toggleVisibility("mainOperations", true);
  toggleVisibility("uploadFileForm", true);
  toggleVisibility("fileListContainer", true);
  if (typeof window.applyDualPaneMode === 'function') {
    window.applyDualPaneMode();
  }
  attachEnterKeyListener("removeUserModal", "deleteUserBtn");
  attachEnterKeyListener("changePasswordModal", "saveNewPasswordBtn");
  document.querySelector(".header-buttons").style.visibility = "visible";

  // 3) Persist auth flags (unchanged)
  if (typeof data.totp_enabled !== "undefined") {
    localStorage.setItem("userTOTPEnabled", data.totp_enabled ? "true" : "false");
  }
  if (data.username) {
    localStorage.setItem("username", data.username);
  }
  if (typeof data.folderOnly !== "undefined") {
    localStorage.setItem("folderOnly", data.folderOnly ? "true" : "false");
    localStorage.setItem("readOnly", data.readOnly ? "true" : "false");
    localStorage.setItem("disableUpload", data.disableUpload ? "true" : "false");
  }

  // 4) Fetch up-to-date profile picture — ALWAYS overwrite localStorage
  const profilePicUrl = await fetchProfilePicture();
  localStorage.setItem("profilePicUrl", profilePicUrl);

  // 5) Build / update header buttons
  const headerButtons = document.querySelector(".header-buttons");
  const firstButton = headerButtons ? headerButtons.firstElementChild : null;

  // c) user dropdown on non-demo
{
    let dd = document.getElementById("userDropdown");

    // choose icon *or* img
    const avatarHTML = profilePicUrl
      ? `<img src="${profilePicUrl}" style="width:24px;height:24px;border-radius:50%;vertical-align:middle;">`
      : `<i class="material-icons">account_circle</i>`;

    // fallback username if missing
    const usernameText = data.username
      || localStorage.getItem("username")
      || "";

    if (!dd) {
      dd = document.createElement("div");
      dd.id = "userDropdown";
      dd.classList.add("user-dropdown");

      // toggle button
      const toggle = document.createElement("button");
      toggle.id = "userDropdownToggle";
      toggle.classList.add("btn", "btn-user");
      toggle.setAttribute("title", t("user_settings"));
      toggle.setAttribute("data-i18n-title", "user_settings");
      toggle.innerHTML = `
        ${avatarHTML}
        <span class="dropdown-username">${usernameText}</span>
        <span class="dropdown-caret"></span>
      `;
      dd.append(toggle);

      // menu
      const menu = document.createElement("div");
      menu.classList.add("user-menu");
      menu.innerHTML = `
        <div class="item" id="menuUserPanel">
          <i class="material-icons folder-icon">person</i>
          <span data-i18n-key="user_panel">${t("user_panel")}</span>
        </div>
        ${data.isAdmin ? `
        <div class="item" id="menuAdminPanel">
          <i class="material-icons folder-icon">admin_panel_settings</i>
          <span data-i18n-key="admin_panel">${t("admin_panel")}</span>
        </div>` : ''}
        <div class="item" id="menuApiDocs">
          <i class="material-icons folder-icon">description</i>
          <span data-i18n-key="api_docs">${t("api_docs")}</span>
        </div>
        <div class="item" id="menuLogout">
          <i class="material-icons folder-icon">logout</i>
          <span data-i18n-key="logout">${t("logout")}</span>
        </div>
      `;
      dd.append(menu);

      // insert
      const dm = document.getElementById("darkModeToggle");
      if (dm) insertAfter(dd, dm);
      else if (firstButton) insertAfter(dd, firstButton);
      else headerButtons.appendChild(dd);

      // open/close
      toggle.addEventListener("click", e => {
        e.stopPropagation();
        menu.classList.toggle("show");
      });
      document.addEventListener("click", () => menu.classList.remove("show"));

      // actions
      document.getElementById("menuUserPanel")
        .addEventListener("click", () => {
          menu.classList.remove("show");
          openUserPanel();
        });
      if (data.isAdmin) {
        document.getElementById("menuAdminPanel")
          .addEventListener("click", () => {
            menu.classList.remove("show");
            openAdminPanel();
          });
      }
      document.getElementById("menuApiDocs")
        .addEventListener("click", () => {
          menu.classList.remove("show");
          openApiModal();
        });
      document.getElementById("menuLogout")
        .addEventListener("click", () => {
          menu.classList.remove("show");
          triggerLogout();
        });

    } else {
      // update avatar & username only
      const tog = dd.querySelector("#userDropdownToggle");
      tog.innerHTML = `
        ${avatarHTML}
        <span class="dropdown-username">${usernameText}</span>
        <span class="dropdown-caret"></span>
      `;
      dd.style.display = "inline-block";
    }
  }

  // 6) Finalize
  initializeApp();
  applyTranslations();
  updateItemsPerPageSelect();
  updateLoginOptionsUIFromStorage();
}

function checkAuthentication(showLoginToast = true) {
  return sendRequest("/api/auth/checkAuth.php")
    .then(data => {
      if (data.setup) {
        const overlay = document.getElementById('loadingOverlay');
        if (overlay) overlay.remove();

        // keep app shell hidden during setup
        const wrap = document.querySelector('.main-wrapper');
        if (wrap) {
          wrap.setAttribute('hidden', '');
          wrap.style.display = 'none';
        }
        document.getElementById('loginForm').style.display = 'none';
        window.setupMode = true;
        if (showLoginToast) showToast(t('setup_no_users'));
        toggleVisibility("loginForm", false);
        toggleVisibility("mainOperations", false);
        document.querySelector(".header-buttons").style.visibility = "hidden";
        toggleVisibility("addUserModal", true);
        document.getElementById("newUsername").focus();
        return false;
      }
      window.setupMode = false;
      if (data.authenticated) {

        localStorage.setItem('isAdmin', data.isAdmin ? 'true' : 'false');
        localStorage.setItem("folderOnly", data.folderOnly);
        localStorage.setItem("readOnly", data.readOnly);
        localStorage.setItem("disableUpload", data.disableUpload);
        updateLoginOptionsUIFromStorage();
        applyProxyBypassUI();
        if (typeof data.totp_enabled !== "undefined") {
          localStorage.setItem("userTOTPEnabled", data.totp_enabled ? "true" : "false");
        }
        if (data.csrf_token) {
          window.csrfToken = data.csrf_token;
          document.querySelector('meta[name="csrf-token"]').content = data.csrf_token;
        }
        updateAuthenticatedUI(data);
        return data;

        // at the end of updateAuthenticatedUI(data)
        if (!window.__FR_FLAGS?.initialized && typeof initializeApp === 'function') {
          initializeApp();
          window.__FR_FLAGS.initialized = true;
        }
        if (typeof applyTranslations === 'function') applyTranslations();
        if (typeof updateLoginOptionsUIFromStorage === 'function') updateLoginOptionsUIFromStorage();
      } else {
        const overlay = document.getElementById('loadingOverlay');
        if (overlay) overlay.remove();

        // show the wrapper (so the login form can be visible)
        document.querySelector('.main-wrapper').style.display = '';
        document.getElementById('loginForm').style.display = '';
        if (showLoginToast) showToast(t('please_log_in_to_continue'));
        toggleVisibility("loginForm", !(localStorage.getItem("authBypass") === "true"));
        toggleVisibility("mainOperations", false);
        toggleVisibility("uploadFileForm", false);
        toggleVisibility("fileListContainer", false);
        const secondary = document.getElementById('fileListContainerSecondary');
        if (secondary) secondary.style.display = 'none';
        document.querySelector(".header-buttons").style.visibility = "hidden";
        return false;
      }
    })
    .catch(() => false);
}

/* ----------------- Authentication Submission ----------------- */
async function primeCsrfStrict() {
  const r = await fetch('/api/auth/token.php', { credentials: 'include' });
  const j = await r.json().catch(() => ({}));
  if (!r.ok || !j.csrf_token) throw new Error('CSRF missing');
  window.csrfToken = j.csrf_token;
  const m = document.querySelector('meta[name="csrf-token"]');
  if (m) m.content = j.csrf_token;
}

function toFormBody(obj) {
  const p = new URLSearchParams();
  for (const [k, v] of Object.entries(obj || {})) p.set(k, v == null ? '' : String(v));
  return p.toString();
}

async function safeJson(res) {
  const ct = res.headers.get('content-type') || '';
  if (!/application\/json/i.test(ct)) return null;
  try { return await res.clone().json(); } catch (e) { return null; }
}

async function sniffTOTP(res, bodyMaybe) {
  if (res.headers.get('X-TOTP-Required') === '1') return true;
  if (res.redirected && /[?&]totp_required=1\b/.test(res.url)) return true;
  const body = bodyMaybe ?? await safeJson(res);
  if (body && (body.totp_required || body.error === 'TOTP_REQUIRED')) return true;
  try {
    const txt = await res.clone().text();
    if (/\btotp_required\s*=\s*1\b/i.test(txt)) return true;
  } catch (e) { }
  return false;
}

async function isAuthedNow() {
  try {
    const r = await fetch('/api/auth/checkAuth.php', { credentials: 'include' });
    const j = await r.json().catch(() => ({}));
    return !!j.authenticated;
  } catch (e) { return false; }
}

function rafTick(times = 2) {
  return new Promise(res => {
    const step = () => { if (--times <= 0) res(); else requestAnimationFrame(step); };
    requestAnimationFrame(step);
  });
}

async function fetchAuthSnapshot() {
  try {
    const r = await fetch('/api/auth/checkAuth.php', { credentials: 'include' });
    return await r.json();
  } catch (e) { return {}; }
}

async function syncPermissionsToLocalStorage() {
  try {
    const perm = await fetchUserPermissionsOnce();
    if (perm && typeof perm === 'object') {
      localStorage.setItem('folderOnly', perm.folderOnly ? 'true' : 'false');
      localStorage.setItem('readOnly', perm.readOnly ? 'true' : 'false');
      localStorage.setItem('disableUpload', perm.disableUpload ? 'true' : 'false');
    }
  } catch (e) { /* non-fatal */ }
}

// ——— main ———
let __loginInFlight = false;

function isDefinitiveLoginError(message) {
  return /invalid credentials|invalid username format|too many failed login attempts/i.test(String(message || ''));
}

function handleLoginFailureTip(message) {
  const msg = String(message || '');
  if (/too many failed login attempts/i.test(msg)) {
    if (typeof window.__frShowLoginLockoutTip === 'function') {
      window.__frShowLoginLockoutTip();
    }
    return;
  }
  if (/invalid credentials/i.test(msg)) {
    if (typeof window.__frRecordLoginFailure === 'function') {
      window.__frRecordLoginFailure();
    }
  }
}

async function submitLogin(data) {
  if (__loginInFlight) return;
  __loginInFlight = true;

  const payload = {
    username: String(data.username || '').trim(),
    password: String(data.password || '').trim(),
    remember_me: data.remember_me ? 1 : 0
  };

  setLastLoginData(payload);
  window.__lastLoginData = payload;

  try {
    await primeCsrfStrict();

    // Attempt #1 — JSON
    let res = await fetchWithCsrf('/api/auth/auth.php', {
      method: 'POST',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
      body: JSON.stringify(payload)
    });
    let body = await safeJson(res);

    // TOTP requested?
    if (await sniffTOTP(res, body)) {
      if (typeof window.__frResetLoginFailure === 'function') {
        window.__frResetLoginFailure();
      }
      try { await primeCsrfStrict(); } catch (e) { }
      window.pendingTOTP = true;
      try {
        const auth = await import(withBase('/js/auth.js?v={{APP_QVER}}'));
        if (typeof auth.openTOTPLoginModal === 'function') auth.openTOTPLoginModal();
      } catch (e) { }
      return;
    }

    // Full success (no TOTP)
    if (body && (body.success || body.status === 'ok' || body.authenticated)) {
      if (typeof window.__frResetLoginFailure === 'function') {
        window.__frResetLoginFailure();
      }

      await syncPermissionsToLocalStorage();
      return afterLogin();
    }

    // Cookie set but non-JSON body — double check session
    if (!body && await isAuthedNow()) {
      if (typeof window.__frResetLoginFailure === 'function') {
        window.__frResetLoginFailure();
      }

      await syncPermissionsToLocalStorage();

      return afterLogin();
    }

    if (body?.error && /Too many failed login attempts/i.test(body.error)) {
      if (typeof window.__frShowLoginLockoutTip === 'function') {
        window.__frShowLoginLockoutTip();
      }
      showToast(body.error);
      const btn = document.querySelector("#authForm button[type='submit']");
      if (btn) {
        btn.disabled = true;
        setTimeout(() => {
          btn.disabled = false;
          showToast(t('login_try_again'));
        }, 30 * 60 * 1000);
      }
      return;
    }

    if (body?.error && isDefinitiveLoginError(body.error)) {
      handleLoginFailureTip(body.error);
      const loginErr = body?.error ? t('login_failed_detail', { error: body.error }) : t('login_failed');
      showToast(loginErr);
      return;
    }

    // Attempt #2 — form fallback
    res = await fetchWithCsrf('/api/auth/auth.php', {
      method: 'POST',
      credentials: 'include',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' },
      body: toFormBody(payload)
    });
    body = await safeJson(res);

    if (await sniffTOTP(res, body)) {
      if (typeof window.__frResetLoginFailure === 'function') {
        window.__frResetLoginFailure();
      }
      try { await primeCsrfStrict(); } catch (e) { }
      window.pendingTOTP = true;
      try {
        const auth = await import(withBase('/js/auth.js?v={{APP_QVER}}'));
        if (typeof auth.openTOTPLoginModal === 'function') auth.openTOTPLoginModal();
      } catch (e) { }
      return;
    }

    if (body && (body.success || body.status === 'ok' || body.authenticated)) {
      if (typeof window.__frResetLoginFailure === 'function') {
        window.__frResetLoginFailure();
      }
      await syncPermissionsToLocalStorage();

      return afterLogin();
    }

    if (!body && await isAuthedNow()) {
      if (typeof window.__frResetLoginFailure === 'function') {
        window.__frResetLoginFailure();
      }

      await syncPermissionsToLocalStorage();

      return afterLogin();
    }

    // Rate limit still respected
    if (body?.error && /Too many failed login attempts/i.test(body.error)) {
      if (typeof window.__frShowLoginLockoutTip === 'function') {
        window.__frShowLoginLockoutTip();
      }
      showToast(body.error);
      const btn = document.querySelector("#authForm button[type='submit']");
      if (btn) {
        btn.disabled = true;
        setTimeout(() => {
          btn.disabled = false;
          showToast(t('login_try_again'));
        }, 30 * 60 * 1000);
      }
      return;
    }

    if (body?.error) {
      handleLoginFailureTip(body.error);
    }
    const loginErr = body?.error ? t('login_failed_detail', { error: body.error }) : t('login_failed');
    showToast(loginErr);

  } catch (e) {
    const errMsg = e && e.message ? e.message : t('unknown_error');
    showToast(t('login_failed_detail', { error: errMsg }));
  } finally {
    __loginInFlight = false;
  }
}

window.submitLogin = submitLogin;

/* ----------------- Other Helpers ----------------- */
window.changeItemsPerPage = function (value) {
  localStorage.setItem("itemsPerPage", value);
  if (typeof renderFileTable === "function") renderFileTable(window.currentFolder || "root");
};

function resetUserForm() {
  document.getElementById("newUsername").value = "";
  document.getElementById("addUserPassword").value = "";
}

function closeAddUserModal() {
  toggleVisibility("addUserModal", false);
  resetUserForm();
}

function closeRemoveUserModal() {
  toggleVisibility("removeUserModal", false);
  document.getElementById("removeUsernameSelect").innerHTML = "";
}

function loadUserList() {
  // Updated path: from "/api/getUsers.php" to "/api/admin/getUsers.php"
  fetch("/api/admin/getUsers.php", { credentials: "include" })
    .then(response => response.json())
    .then(data => {
      // Assuming the endpoint returns an array of users.
      const users = Array.isArray(data) ? data : (data.users || []);
      const selectElem = document.getElementById("removeUsernameSelect");
      selectElem.innerHTML = "";
      users.forEach(user => {
        const option = document.createElement("option");
        option.value = user.username;
        option.textContent = user.username;
        selectElem.appendChild(option);
      });
      if (selectElem.options.length === 0) {
        showToast(t('remove_user_none'));
        closeRemoveUserModal();
      }
    })
    .catch(() => { /* handle errors if needed */ });
}
window.loadUserList = loadUserList;

function initAuth() {
  checkAuthentication(false);
  loadAdminConfigFunc();
  const authForm = document.getElementById("authForm");
  if (authForm) {
    authForm.addEventListener("submit", function (event) {
      event.preventDefault();
      const rememberMe = document.getElementById("rememberMeCheckbox")
        ? document.getElementById("rememberMeCheckbox").checked
        : false;
      const formData = {
        username: document.getElementById("loginUsername").value.trim(),
        password: document.getElementById("loginPassword").value.trim(),
        remember_me: rememberMe
      };
      submitLogin(formData);
    });
  }

  document.getElementById("addUserBtn").addEventListener("click", function () {
    resetUserForm();
    toggleVisibility("addUserModal", true);
    document.getElementById("newUsername").focus();
  });

  // remove your old saveUserBtn click-handler…

  // instead:
  const addUserForm = document.getElementById("addUserForm");
  addUserForm.addEventListener("submit", function (e) {
    e.preventDefault();   // stop the browser from reloading the page

    const newUsername = document.getElementById("newUsername").value.trim();
    const newPassword = document.getElementById("addUserPassword").value.trim();
    const isAdmin = document.getElementById("isAdmin").checked;

    if (!newUsername || !newPassword) {
      showToast(t('username_password_required'));
      return;
    }

    let url = "/api/admin/addUser.php";
    if (window.setupMode) url += "?setup=1";

    fetchWithCsrf(url, {
      method: "POST",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username: newUsername, password: newPassword, isAdmin })
    })
      .then(r => r.json())
      .then(data => {
        if (data.success) {
          showToast(t('user_add_success'));
          closeAddUserModal();
          checkAuthentication(false);
          if (window.setupMode) {
            toggleVisibility("loginForm", true);
          }
        } else {
          const errMsg = data.error || t('user_add_error_default');
          showToast(t('user_add_error', { error: errMsg }));
        }
      })
      .catch(() => {
        showToast(t('user_add_error', { error: t('user_add_error_default') }));
      });
  });
  document.getElementById("cancelUserBtn").addEventListener("click", closeAddUserModal);

  document.getElementById("removeUserBtn").addEventListener("click", function () {
    loadUserList();
    toggleVisibility("removeUserModal", true);
  });
  document.getElementById("deleteUserBtn").addEventListener("click", async function () {
    const selectElem = document.getElementById("removeUsernameSelect");
    const usernameToRemove = selectElem.value;
    if (!usernameToRemove) {
      showToast(t('select_user_remove_prompt'));
      return;
    }
    const confirmed = await showCustomConfirmModal("Are you sure you want to delete user " + usernameToRemove + "?");
    if (!confirmed) return;
    fetchWithCsrf("/api/admin/removeUser.php", {
      method: "POST",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username: usernameToRemove })
    })
      .then(response => response.json())
      .then(data => {
        if (data.success) {
          showToast(t('user_remove_success'));
          closeRemoveUserModal();
          loadUserList();
        } else {
          const errMsg = data.error || t('user_remove_error_default');
          showToast(t('user_remove_error', { error: errMsg }));
        }
      })
      .catch(() => { });
  });
  document.getElementById("cancelRemoveUserBtn").addEventListener("click", closeRemoveUserModal);
  document.getElementById("changePasswordBtn").addEventListener("click", function () {
    if (window.__FR_DEMO__) {
      showToast(t('password_change_disabled_demo'));
      return;
    }
    document.getElementById("changePasswordModal").style.display = "block";
    document.getElementById("oldPassword").focus();
  });
  document.getElementById("closeChangePasswordModal").addEventListener("click", function () {
    document.getElementById("changePasswordModal").style.display = "none";
  });
  document.getElementById("saveNewPasswordBtn").addEventListener("click", function () {
    if (window.__FR_DEMO__) {
      showToast(t('password_change_disabled_demo'));
      return;
    }
    const oldPassword = document.getElementById("oldPassword").value.trim();
    const newPassword = document.getElementById("newPassword").value.trim();
    const confirmPassword = document.getElementById("confirmPassword").value.trim();
    if (!oldPassword || !newPassword || !confirmPassword) {
      showToast(t('fill_all_fields'));
      return;
    }
    if (newPassword !== confirmPassword) {
      showToast(t('passwords_do_not_match'));
      return;
    }
    const data = { oldPassword, newPassword, confirmPassword };
    fetchWithCsrf("/api/profile/changePassword.php", {
      method: "POST",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data)
    })
      .then(response => response.json())
      .then(result => {
        if (result.success) {
          showToast(result.success);
          document.getElementById("oldPassword").value = "";
          document.getElementById("newPassword").value = "";
          document.getElementById("confirmPassword").value = "";
          document.getElementById("changePasswordModal").style.display = "none";
        } else {
          const errMsg = result.error || t('password_change_error_default');
          showToast(t('password_change_error', { error: errMsg }));
        }
      })
      .catch(() => { showToast(t('password_change_error_generic')); });
  });
}

document.addEventListener("DOMContentLoaded", function () {
  updateItemsPerPageSelect();
  updateLoginOptionsUI({
    disableFormLogin: localStorage.getItem("disableFormLogin") === "true",
    disableBasicAuth: localStorage.getItem("disableBasicAuth") === "true",
    disableOIDCLogin: localStorage.getItem("disableOIDCLogin") === "true"
  });

  const oidcLoginBtn = document.getElementById("oidcLoginBtn");
  if (oidcLoginBtn) {
    oidcLoginBtn.addEventListener("click", () => {
      window.location.href = withBase("/api/auth/auth.php?oidc=initiate");
    });
  }

  // If TOTP is pending, show modal and skip normal auth init
  if (window.pendingTOTP) {
    openTOTPLoginModal();
    return;
  }
});

export { initAuth, checkAuthentication, openTOTPLoginModal };
