/**
 * P5 authorization SEAM (FIX 6a). These interfaces MIRROR relay-auth's frozen §6a shapes
 * (`UpgradeContext` / `AuthzOutcome` / `DpopContext` / `Authorizer`). P5 (`relay-auth/`) is not
 * built in this package's build graph, so — per the "program against interfaces / DI seams,
 * don't hard-import an unbuilt sibling" rule — P1 defines the port here and injects an impl.
 *
 * INTEGRATION POINT: when relay-auth lands, replace these local declarations with
 *   `import type { UpgradeContext, AuthzOutcome, DpopContext, Authorizer } from 'relay-auth'`
 * (structurally identical). P1 holds NO authz logic — the decision is P5's alone.
 */
import type { CapabilityRight } from 'relay-contracts'

/** Proof-of-possession material P5 needs; P1 passes it through, never inspects it. */
export interface DpopContext {
  readonly proof: string | null
  readonly publicKeyThumbprint: string | null
}

/** Everything P5's `onUpgrade`/`onReattach` needs to make the deny-by-default decision. */
export interface UpgradeContext {
  readonly capabilityRaw: string // opaque token string; P5 verifies the signature
  readonly originHeader: string // retained for Origin/CSWSH check (P5)
  readonly expectedAud: string // = the resolved subdomain (Host-confusion guard, INV1)
  readonly requestedHostId: string // P1 NAMES the resolved host; P5 gates token.host against it
  readonly requiredRight: CapabilityRight
  readonly remoteAddrHash: string // salted hash (audit only, INV10)
  readonly activeSessionCount: number
  readonly dpop: DpopContext
  readonly principal: string | null // P5 resolves from the signed token (INV3)
}

/** P5's verdict. The `ok` branch carries the VERIFIED token's `jti` (OQ5 resolved). */
export type AuthzOutcome =
  | { readonly ok: true; readonly hostId: string; readonly principal: string; readonly jti: string }
  | { readonly ok: false; readonly status: 401 | 403 }

/** The single authorizer (P5). P1 injects it and supplies the ctx; P5 makes every decision. */
export interface Authorizer {
  onUpgrade(ctx: UpgradeContext, now: number): Promise<AuthzOutcome>
  onReattach(ctx: UpgradeContext & { readonly sessionId: string }, now: number): Promise<AuthzOutcome>
}
