// The Web App can be pointed at more than one DriverVault API Server. One is
// the "home" server — the one that served this app, reached same-origin through
// the BFF's /api proxy — and any number of others are added by URL and called
// straight from the browser, which works because an API Server that a phone can
// reach is internet-facing already.
//
// Each server is its own PocketBase with its own users, so a session cannot be
// carried across: every server holds its own token under its own key. Only one
// server is active at a time and the whole app reads from it, so switching
// swaps the garage, the charging page and the settings together.
//
// This module deliberately knows nothing about auth.js — api.js and auth.js
// both read it, and auth.js watches the active id rather than being called from
// here, which keeps the imports one-way.
import { reactive, computed } from "vue";
import { t } from "./i18n";

// Same-origin default: the BFF proxies /api to the API Server it was configured
// with, so the home server needs no URL of its own.
export const DEFAULT_API_BASE = import.meta.env.VITE_API_BASE || "/api";
export const HOME_ID = "home";

const LIST_KEY = "cc_servers";
const ACTIVE_KEY = "cc_active_server";
const sessionKey = (id) => `cc_session_${id}`;

// Pre-multi-server keys, read once at boot so an upgrade doesn't sign anyone
// out or forget the server they had pointed the app at.
const LEGACY_TOKEN_KEY = "cc_token";
const LEGACY_USER_KEY = "cc_user";
const LEGACY_SERVER_KEY = "cc_server_url";

// A server address as typed. Trailing slashes go, and a bare origin gets "/api"
// appended — every API Server route lives under it, so entering just
// "https://garage.example.com" should work without the user knowing that.
export function normalizeUrl(url) {
  const trimmed = (url || "").trim().replace(/\/+$/, "");
  if (!trimmed) return "";
  try {
    const u = new URL(trimmed);
    if (u.pathname === "" || u.pathname === "/") return `${u.origin}/api`;
  } catch {
    // Not an absolute URL (a relative base like "/api"): take it as given.
  }
  return trimmed;
}

function loadList() {
  let stored = [];
  try {
    stored = JSON.parse(localStorage.getItem(LIST_KEY) || "[]");
  } catch {
    stored = [];
  }
  if (!Array.isArray(stored)) stored = [];
  const list = stored
    .filter((s) => s && s.id)
    .map((s) => ({ id: String(s.id), name: String(s.name || ""), url: normalizeUrl(s.url) }))
    // Home is the only entry allowed to have no URL — it falls back to the
    // same-origin default. Anything else without one is unusable.
    .filter((s) => s.id === HOME_ID || s.url);
  if (!list.some((s) => s.id === HOME_ID)) list.unshift({ id: HOME_ID, name: "", url: "" });
  return list;
}

function saveList() {
  localStorage.setItem(LIST_KEY, JSON.stringify(servers.list));
}

function loadSession(id) {
  try {
    const parsed = JSON.parse(localStorage.getItem(sessionKey(id)) || "null");
    return parsed && parsed.token ? { token: parsed.token, user: parsed.user || null } : null;
  } catch {
    return null;
  }
}

// Carries a pre-multi-server session onto the home server. Any custom base the
// user had set on the login screen becomes home's URL, so the same server keeps
// answering after the upgrade.
function migrateLegacy() {
  const token = localStorage.getItem(LEGACY_TOKEN_KEY);
  const legacyUrl = localStorage.getItem(LEGACY_SERVER_KEY);
  if (!token && !legacyUrl) return;
  if (token && !localStorage.getItem(sessionKey(HOME_ID))) {
    let user = null;
    try {
      user = JSON.parse(localStorage.getItem(LEGACY_USER_KEY) || "null");
    } catch {
      user = null;
    }
    localStorage.setItem(sessionKey(HOME_ID), JSON.stringify({ token, user }));
  }
  if (legacyUrl && !localStorage.getItem(LIST_KEY)) {
    localStorage.setItem(
      LIST_KEY,
      JSON.stringify([{ id: HOME_ID, name: "", url: normalizeUrl(legacyUrl) }])
    );
  }
  localStorage.removeItem(LEGACY_TOKEN_KEY);
  localStorage.removeItem(LEGACY_USER_KEY);
  localStorage.removeItem(LEGACY_SERVER_KEY);
}

export const servers = reactive({
  list: [],
  activeId: HOME_ID,
  // id -> {token, user} | null. Mirrors localStorage so a switch is instant and
  // a reload keeps every server you were signed into.
  sessions: {},
});

migrateLegacy();
servers.list = loadList();
for (const s of servers.list) servers.sessions[s.id] = loadSession(s.id);
const storedActive = localStorage.getItem(ACTIVE_KEY);
servers.activeId = servers.list.some((s) => s.id === storedActive) ? storedActive : HOME_ID;

export const activeServer = computed(
  () => servers.list.find((s) => s.id === servers.activeId) || servers.list[0]
);

// The base URL every request against `server` goes to.
export function baseFor(server) {
  return (server?.url || "").trim() || DEFAULT_API_BASE;
}

export const activeBase = computed(() => baseFor(activeServer.value));

// What to call a server in the UI: its own name, else the host it lives on,
// else — for a home server with no URL — a generic label for "the one serving
// this page".
export function displayName(server) {
  if (!server) return "";
  if (server.name) return server.name;
  const base = (server.url || "").trim();
  if (!base) return t("servers.home");
  try {
    return new URL(base).host;
  } catch {
    return base;
  }
}

export function serverById(id) {
  return servers.list.find((s) => s.id === id) || null;
}

export function sessionFor(id) {
  return servers.sessions[id] || null;
}

export function isConnected(id) {
  return !!servers.sessions[id]?.token;
}

export function setSession(id, token, user) {
  servers.sessions[id] = { token, user: user || null };
  localStorage.setItem(sessionKey(id), JSON.stringify(servers.sessions[id]));
}

export function clearSession(id) {
  servers.sessions[id] = null;
  localStorage.removeItem(sessionKey(id));
}

export function clearAllSessions() {
  for (const s of servers.list) clearSession(s.id);
}

export function setActive(id) {
  if (!serverById(id)) return;
  servers.activeId = id;
  localStorage.setItem(ACTIVE_KEY, id);
}

export function addServer({ name, url }) {
  const server = {
    id: `s${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,
    name: (name || "").trim(),
    url: normalizeUrl(url),
  };
  servers.list.push(server);
  saveList();
  return server;
}

export function updateServer(id, { name, url }) {
  const server = serverById(id);
  if (!server) return null;
  if (name !== undefined) server.name = (name || "").trim();
  if (url !== undefined) {
    const next = normalizeUrl(url);
    // Moving a server to a different address invalidates the token held for it:
    // it was minted by the PocketBase behind the old one.
    if (next !== server.url) clearSession(id);
    server.url = next;
  }
  saveList();
  return server;
}

// Removing a server forgets its session too. Home cannot be removed — it is the
// app's own server, and there would be nothing left to fall back to.
export function removeServer(id) {
  if (id === HOME_ID) return;
  clearSession(id);
  servers.list = servers.list.filter((s) => s.id !== id);
  saveList();
  if (servers.activeId === id) setActive(HOME_ID);
}
