// `AccountStore` is the session-wide cache for the caller's
// `user.account.get` aggregate. The lobby shell and every post-login
// screen read the identity (display name, immutable user_name, time
// zone, …) from the same rune, so navigating between Overview and
// Profile does not refetch and does not flash the
// `lobby.account_loading` placeholder.
//
// `ensure(client)` fetches once on first call, dedupes concurrent
// callers onto a single in-flight promise, and resolves immediately
// from the cache thereafter. `set(account)` is the write-through
// path used by Profile after `user.profile.update` /
// `user.settings.update` succeeds — both the shell and the screen
// pick up the change without an extra round-trip. `clear()` resets
// the cache on logout so a different user signing in on the same
// browser does not briefly see the previous identity.
//
// The store is intentionally narrow: it caches one struct, never
// retries on failure (the caller decides), and exposes no error
// state of its own. Callers that need a tighter error surface (the
// Profile form) catch the rejection from `ensure(client)` directly.

import type { GalaxyClient } from "../api/galaxy-client";
import { getMyAccount, type Account } from "../api/account";

class AccountStore {
	current: Account | null = $state(null);
	#inFlight: Promise<Account> | null = null;

	/**
	 * ensure returns the cached `Account` when present, otherwise issues
	 * `user.account.get` through the supplied client and caches the
	 * result. Concurrent callers during the first fetch share the same
	 * in-flight promise so the gateway only sees one request per
	 * session.
	 */
	ensure(client: GalaxyClient): Promise<Account> {
		if (this.current !== null) {
			return Promise.resolve(this.current);
		}
		if (this.#inFlight !== null) {
			return this.#inFlight;
		}
		const pending = getMyAccount(client)
			.then((account) => {
				this.current = account;
				return account;
			})
			.finally(() => {
				this.#inFlight = null;
			});
		this.#inFlight = pending;
		return pending;
	}

	/**
	 * set replaces the cached `Account` with the supplied value. Used
	 * by the Profile screen after a successful save so both the form
	 * and the shell identity strip pick up the new fields without a
	 * second round-trip.
	 */
	set(next: Account): void {
		this.current = next;
	}

	/**
	 * clear resets the cache. Called on logout so a different user
	 * signing in on the same browser does not briefly see the
	 * previous identity through the rune.
	 */
	clear(): void {
		this.current = null;
		this.#inFlight = null;
	}
}

export const account = new AccountStore();
