import { derived, writable } from 'svelte/store';
import { getRole, onClearAuth, onSetAuth } from './auth';

export type Role = 'guest' | 'host' | 'admin';

/**
 * The viewer's LIVE role.
 *
 * The JWT is never reissued — the backend slides the session row forward instead and
 * deliberately ignores the token's own role claim (`auth/middleware.rs`: "the live user row
 * is authoritative"). So `getRole()`, which decodes the claim, is frozen for the lifetime of
 * the token: up to 30 days for a guest. A guest promoted to host saw no Host-Dashboard until
 * they signed out and back in, even though `/me/context` had already told the client their
 * real role on the very next page load — it was fetched and the `role` field dropped on the
 * floor in 4 of its 6 call sites.
 *
 * This store is seeded from the claim (so there is no flash of the wrong nav on boot) and
 * corrected by every `/me/context` response via `setRole`. Read this instead of calling
 * `getRole()` ad hoc.
 */
export const role = writable<Role | null>(getRole());

/** True for host and admin — the "can moderate" predicate used across the UI. */
export const isStaff = derived(role, ($role) => $role === 'host' || $role === 'admin');

/** Apply the authoritative role from a `/me/context` response. */
export function setRole(next: Role | null): void {
	role.set(next);
}

/** Re-seed from the token, e.g. straight after a login/join that minted a new one. */
export function syncRoleFromToken(): void {
	role.set(getRole());
}

// Bind the store to the identity lifecycle. The store is a module-level singleton seeded
// ONCE at import, and `goto()` navigations re-import nothing — so without these hooks the
// previous user's role survives a logout→login in the same tab. A host who left and a guest
// who then joined kept `isStaff === true` and were offered "Beitrag entfernen" on other
// people's photos (the backend 403s it, so it was a false affordance rather than an
// escalation — but the feed never fetches /me/context, so it never self-corrected either).
// The mirror case is just as wrong: a guest recovering into a host account got no host
// affordances at all.
onClearAuth(() => role.set(null));
onSetAuth(syncRoleFromToken);
