export const AUTH_REMEMBER_ME_KEY = "authRememberMe";
const AUTH_PERSISTENCE_KEY = "authTokenPersistence";
const AUTH_USER_KEY = "authUserKey";
const AUTH_CSRF_COOKIE = "XSRF-TOKEN";
export const AUTH_USER_CHANGED_EVENT = "auth-user-changed";

export type AuthPersistence = "local" | "session";

function safeGet(storage: Storage, key: string): string | null {
  try {
    return storage.getItem(key);
  } catch {
    return null;
  }
}

function safeSet(storage: Storage, key: string, value: string) {
  try {
    storage.setItem(key, value);
  } catch {
    // ignore storage failures
  }
}

function safeRemove(storage: Storage, key: string) {
  try {
    storage.removeItem(key);
  } catch {
    // ignore storage failures
  }
}

function emitAuthChanged() {
  window.dispatchEvent(new Event("auth-changed"));
}

function normalizePersistence(value: string | null | undefined): AuthPersistence {
  return value === "session" ? "session" : "local";
}

function persistPreference(persistence: AuthPersistence) {
  safeSet(window.localStorage, AUTH_PERSISTENCE_KEY, persistence);
  safeSet(window.localStorage, AUTH_REMEMBER_ME_KEY, persistence === "local" ? "1" : "0");
}

function getStoredPersistence(): AuthPersistence {
  const explicit = safeGet(window.localStorage, AUTH_PERSISTENCE_KEY);
  if (explicit) return normalizePersistence(explicit);
  const rememberMe = safeGet(window.localStorage, AUTH_REMEMBER_ME_KEY);
  if (rememberMe === "0") return "session";
  return "local";
}

export function getRememberMePref(): boolean {
  return getAuthPersistencePreference() === "local";
}

export function setRememberMePref(value: boolean) {
  persistPreference(value ? "local" : "session");
}

export function getAuthPersistencePreference(): AuthPersistence {
  return getStoredPersistence();
}

export function setAuthPersistencePreference(persistence: AuthPersistence) {
  persistPreference(persistence);
  emitAuthChanged();
}

export function getAuthUserKey(): string {
  return safeGet(window.localStorage, AUTH_USER_KEY) ?? "anon";
}

export function getUserScopedStorageKey(baseKey: string, userKey = getAuthUserKey()): string {
  const normalizedUser = userKey.trim() || "anon";
  return `${baseKey}:${encodeURIComponent(normalizedUser)}`;
}

export function setAuthUserKey(value: string | null | undefined, emit = true) {
  const previous = getAuthUserKey();
  const next = typeof value === "string" ? value.trim() : "";
  if (!next) {
    safeRemove(window.localStorage, AUTH_USER_KEY);
  } else {
    safeSet(window.localStorage, AUTH_USER_KEY, next);
  }
  if (previous !== (next || "anon")) window.dispatchEvent(new Event(AUTH_USER_CHANGED_EVENT));
  if (emit) emitAuthChanged();
}

export function clearAuthClientState(emit = true) {
  // Only emit "auth-changed" when this call actually transitions from
  // "signed in" to "signed out". The response interceptor calls this on every
  // 401; without this guard each 401 re-dispatches "auth-changed", which
  // re-fetches /auth/me, which 401s again — an infinite request loop whenever
  // the user is logged out (login page, expired session).
  const had = safeGet(window.localStorage, AUTH_USER_KEY) != null;
  safeRemove(window.localStorage, AUTH_USER_KEY);
  if (had) window.dispatchEvent(new Event(AUTH_USER_CHANGED_EVENT));
  if (emit && had) emitAuthChanged();
}

export function getCsrfToken(): string | null {
  try {
    const parts = document.cookie.split(";").map((part) => part.trim());
    const match = parts.find((part) => part.startsWith(`${AUTH_CSRF_COOKIE}=`));
    if (!match) return null;
    return decodeURIComponent(match.slice(AUTH_CSRF_COOKIE.length + 1));
  } catch {
    return null;
  }
}
