/**
 * Curated SPA-facing view of the session user, served by the BFF at
 * `GET /api/auth/me`. Mirrors the `PublicUser` shape the BFF returns
 * (apps/portal-bff/src/auth/auth.controller.ts) — internal claims
 * like `amr` stay server-side and never reach the SPA.
 */
export interface CurrentUser {
  readonly oid: string;
  readonly tid: string;
  readonly username: string;
  readonly displayName: string;
  /**
   * Entra app roles assigned on the BFF's app registration. Present
   * on `/api/admin/auth/me` (admin portal) — the admin SPA uses it
   * to surface role badges + admin-only UI. Omitted on the user
   * portal's `/api/auth/me` per ADR-0009 §"curated public view"; the
   * shell consults `/api/me/capabilities` for binary access hints.
   */
  readonly roles?: readonly string[];
}

/**
 * The four observable states of authentication on the SPA, modelled
 * as a discriminated union so consumers can `switch` on `kind` and
 * the type narrows automatically.
 *
 *   - `loading` — first /me call hasn't returned yet.
 *   - `anonymous` — BFF answered 401, no session cookie or expired.
 *   - `authenticated` — BFF returned the user payload.
 *   - `error` — network failure, 5xx, or unexpected shape. Distinct
 *     from `anonymous` so the UI can surface a different message
 *     ("can't reach server" vs. "please sign in").
 */
export type AuthState =
  | { readonly kind: 'loading' }
  | { readonly kind: 'anonymous' }
  | { readonly kind: 'authenticated'; readonly user: CurrentUser }
  | { readonly kind: 'error' };
