// Reactive auth state for whichever server is active. Tokens are held per
// server by servers.js (each one is a separate PocketBase, so a session cannot
// be shared); this module mirrors the active one into `state` and keeps the
// richer profile in step, so every view can go on reading `state.user` without
// knowing that more than one server exists.
import { reactive, computed, watch } from "vue";
import { api } from "./api";
import {
  servers,
  serverById,
  sessionFor,
  setSession,
  clearSession,
  clearAllSessions,
  setActive,
  baseFor,
  HOME_ID,
} from "./servers";
import { applyProfilePrefs } from "./prefs";
import { t } from "./i18n";

export const state = reactive({
  token: "",
  user: null,
  // Full settings-panel profile (bio, theme, locale, ...), fetched separately
  // from /api/me since the login response only carries id/email/name.
  profile: null,
});

function syncFromActive() {
  const session = sessionFor(servers.activeId);
  state.token = session?.token || "";
  state.user = session?.user || null;
}
syncFromActive();

// Switching servers swaps the whole session: a different PocketBase, a
// different user record, a different set of preferences. Watching the active id
// *and* its token also covers a session being cleared underneath us — which is
// what api.js does when a server answers 401.
watch(
  () => [servers.activeId, sessionFor(servers.activeId)?.token],
  ([id], [prevId]) => {
    syncFromActive();
    if (id !== prevId) state.profile = null;
    if (state.token && !state.profile) refreshProfile().catch(() => {});
  }
);

export const isAuthenticated = computed(() => !!state.token);

// Roles that may manage users. A superadmin is an admin that also spans every
// organization; the API Server enforces the difference, the UI just needs to
// know whether to offer the Settings › Users tab at all.
const MANAGER_ROLES = ["admin", "superadmin"];

// Admin gate for the UI. Driven by the full profile (fetched from /api/me),
// which always reflects the current role from the DB — so a promotion/demotion
// takes effect on the next profile refresh without needing a re-login. It is
// per-server: being an admin on one server says nothing about the other.
export const isAdmin = computed(
  () => MANAGER_ROLES.includes(state.profile?.role) || MANAGER_ROLES.includes(state.user?.role)
);

// Logs into one server and makes it active. The login screen calls it for
// whichever server is active; the switcher's connect dialog calls it for one
// that isn't yet, which is why the credentials are checked against that
// server's own base before anything switches.
export async function connect(serverId, email, password) {
  const server = serverById(serverId);
  if (!server) throw new Error(t("servers.unknown"));
  // The API Server proxies login to PocketBase and relays its response
  // verbatim, so the user is under `record` (PocketBase's name) and the token
  // is PocketBase's own — this app no longer holds a server-minted JWT.
  const res = await api.loginAt(baseFor(server), email, password);
  setSession(serverId, res.token, res.record);
  state.profile = null;
  if (servers.activeId === serverId) syncFromActive();
  else setActive(serverId);
  await refreshProfile();
  return res;
}

export function login(email, password) {
  return connect(servers.activeId, email, password);
}

// Signs out of one server without leaving the app — the switcher's per-server
// action. Dropping the active one falls back to home, the same way an expired
// token does.
export function disconnect(serverId) {
  clearSession(serverId);
  if (servers.activeId === serverId && serverId !== HOME_ID) setActive(HOME_ID);
}

// Signs out everywhere. Leaving the app means leaving every server you reached
// from it — leaving a live token behind on a shared browser would be worse than
// the inconvenience of logging back in.
export function logout() {
  clearAllSessions();
  setActive(HOME_ID);
  state.token = "";
  state.user = null;
  state.profile = null;
}

// Fetches the full profile (used for Settings + to apply appearance prefs).
// Safe to call on app boot when a token already exists from a previous visit.
export async function refreshProfile() {
  if (!state.token) return null;
  const profile = await api.getMe();
  state.profile = profile;
  applyProfilePrefs(profile);
  return profile;
}
