// Package traefikoidc provides OIDC authentication middleware for Traefik.
// requestState bundles read-mostly fields for a single ServeHTTP call.
package traefikoidc

import "net/http"

// requestState is a per-request context object allocated at the top of
// ServeHTTP and threaded through to downstream handlers. It caches values
// that would otherwise require a Yaegi-dispatched lock acquisition each time
// they're read:
//
//   - The metadata snapshot (atomic.Value.Load once, not per-handler).
//   - SessionData getter results (one RLock on sd.sessionMutex covers all
//     fields, instead of 5-7 separate RLock/RUnlock pairs scattered through
//     the handler chain).
//
// The struct is alloc'd at request entry, populated under at most one RLock
// of sd.sessionMutex, and discarded at request exit. It is NOT shared across
// requests and never written from another goroutine, so no synchronization
// on its fields is required.
//
// Cross-request global caches (tokenCache, JWKCache, sessionEntries,
// sessionInvalidationCache) remain — they're orthogonal. requestState's job
// is to eliminate redundant per-handler reads of values that don't change
// within a single request.
type requestState struct {
	// Globals snapshotted once.
	metadata *MetadataSnapshot

	// SessionData fields snapshotted under one RLock. The pointer to the
	// SessionData is retained so handlers that genuinely need to mutate
	// (Save, Clear, etc.) still have access.
	session *SessionData

	authenticated     bool
	accessToken       string
	idToken           string
	refreshToken      string
	userIdentifier    string
	createdAtUnixSec  int64

	// Output: scheme/host/redirect path determined at top of ServeHTTP.
	scheme      string
	host        string
	redirectURL string

	// Carry the next handler so forwardAuthorized doesn't need to close over t.
	next http.Handler
}

// captureSession populates requestState's SessionData-derived fields under a
// single RLock of sd.sessionMutex. Returns the populated rs for chaining.
//
// Replaces a sequence of SessionData.GetX() calls each of which acquires
// sd.sessionMutex.RLock(). Under Yaegi each RLock costs ~1-5ms of
// interpreter dispatch; batching saves the rest.
func (rs *requestState) captureSession(sd *SessionData) *requestState {
	if sd == nil {
		return rs
	}
	rs.session = sd
	sd.sessionMutex.RLock()
	rs.authenticated = sd.getAuthenticatedUnsafe()
	rs.accessToken = sd.getAccessTokenUnsafe()
	rs.idToken = sd.getIDTokenUnsafe()
	rs.refreshToken = sd.getRefreshTokenUnsafe()
	rs.userIdentifier = sd.getUserIdentifierUnsafe()
	rs.createdAtUnixSec = sd.getCreatedAtUnsafe()
	sd.sessionMutex.RUnlock()
	return rs
}
