// Shared, reactive auth + saved-articles state (Svelte 5 runes in a module).
import { SvelteSet } from 'svelte/reactivity';
import { getJSON, postJSON, delJSON } from './api.js';

// Cache the last-known user so a refresh paints the signed-in UI immediately
// instead of flashing "signed out" for the /api/auth/me round-trip. The session
// is still revalidated on every load (see refresh) — a stale/expired one just
// corrects within a beat instead of greeting you logged-out every time.
const AUTH_CACHE = 'goodnews:auth_user';
function _loadUser() {
  try { return JSON.parse(localStorage.getItem(AUTH_CACHE) || 'null'); } catch { return null; }
}
function _saveUser(u) {
  try {
    if (u) localStorage.setItem(AUTH_CACHE, JSON.stringify(u));
    else localStorage.removeItem(AUTH_CACHE);
  } catch { /* ignore */ }
}

export const auth = $state({ user: _loadUser(), ready: false });
export const savedIds = new SvelteSet(); // reactive set of saved article ids
export const followKeys = new SvelteSet(); // reactive set of "kind:value" follows

const fkey = (kind, value) => `${kind}:${String(value).toLowerCase()}`;
export const isFollowing = (kind, value) => followKeys.has(fkey(kind, value));

export async function refresh() {
  try {
    auth.user = await getJSON('/api/auth/me');
  } catch {
    auth.user = null;
  } finally {
    auth.ready = true;
    _saveUser(auth.user);
  }
  if (auth.user) { await loadSaved(); await loadFollows(); }
  else { savedIds.clear(); followKeys.clear(); }
}

export async function loadFollows() {
  try {
    const list = await getJSON('/api/follows');
    followKeys.clear();
    for (const f of list) followKeys.add(fkey(f.kind, f.value));
  } catch {
    /* not signed in / transient */
  }
}

// Optimistic follow/unfollow of a source or tag; reverts on failure.
export async function toggleFollow(kind, value) {
  if (!auth.user) return false;
  const key = fkey(kind, value);
  const willFollow = !followKeys.has(key);
  if (willFollow) followKeys.add(key);
  else followKeys.delete(key);
  try {
    if (willFollow) await postJSON('/api/follows', { kind, value: String(value) });
    else await delJSON(`/api/follows?kind=${kind}&value=${encodeURIComponent(value)}`);
  } catch {
    if (willFollow) followKeys.delete(key);
    else followKeys.add(key);
  }
  return followKeys.has(key);
}

export async function loadSaved() {
  try {
    const ids = await getJSON('/api/saved/ids');
    savedIds.clear();
    for (const id of ids) savedIds.add(id);
  } catch {
    /* not signed in / transient — leave as-is */
  }
}

// Optimistic toggle; reverts on failure.
export async function toggleSave(id) {
  if (!auth.user) return false;
  const willSave = !savedIds.has(id);
  if (willSave) savedIds.add(id);
  else savedIds.delete(id);
  try {
    if (willSave) await postJSON(`/api/saved/${id}`, {});
    else await delJSON(`/api/saved/${id}`);
  } catch {
    if (willSave) savedIds.delete(id);
    else savedIds.add(id);
  }
  return savedIds.has(id);
}

// Request a magic link. Reply is intentionally identical for any address.
export function startEmail(email) {
  return postJSON('/api/auth/email/start', { email });
}

export async function verifyToken(token) {
  const res = await postJSON('/api/auth/email/verify', { token });
  auth.user = res.user;
  await loadSaved();
  await loadFollows();
  return res;
}

export async function logout() {
  try {
    await postJSON('/api/auth/logout', {});
  } finally {
    clearLocal();
  }
}

// Clear client auth state without a logout call (cookie already cleared server-side,
// e.g. after delete-account or sign-out-everywhere).
export function clearLocal() {
  auth.user = null;
  _saveUser(null);
  savedIds.clear();
  followKeys.clear();
}
