/**
 * Request context for server code. The runner keeps the current request in an AsyncLocalStorage
 * and exposes it through `globalThis.__lecodesRequest` — a *global* seam on purpose: the compiled
 * server bundle carries its own copy of this module (chisel bundles the SDK in), so the host can't
 * hand it a value by import. `request` reads through that seam; outside a request (module load,
 * timers after the response) every member is undefined.
 */

export type RequestContext = {
  /** Endpoint id `<path>#<export>` (or the channel id for `onJoin`). */
  id: string
  headers: Record<string, string>
  ip?: string
  /** Bearer session token as sent by the client transport (raw; auth resolves it). */
  sessionToken?: string
  /** Set by the auth runtime after resolving the token — read via `auth.*`, not here. */
  auth?: unknown
}

type Provider = () => RequestContext | undefined
const seam = globalThis as unknown as { __lecodesRequest?: Provider }

/** Host hook (runner / test harness): install the current-request provider. */
export const setRequestProvider = (provider: Provider | null) => {
  if (provider) seam.__lecodesRequest = provider
  else delete seam.__lecodesRequest
}
/** @internal */
export const currentRequest = (): RequestContext | undefined => seam.__lecodesRequest?.()

/** The current request (server global). Undefined members outside a request. */
export const request = {
  get id(): string | undefined { return currentRequest()?.id },
  get headers(): Record<string, string> { return currentRequest()?.headers ?? {} },
  get ip(): string | undefined { return currentRequest()?.ip },
}
