package auth

import (
	"context"
	"net/http"

	"github.com/google/uuid"
)

type contextKey string

const (
	userIDContextKey contextKey = "paliad.userID"
	claimsContextKey contextKey = "paliad.claims"
)

// UserIDFromContext returns the authenticated user's UUID, populated by
// WithUserID middleware (which runs after the session middleware).
// Returns (uuid.Nil, false) if no user is in context.
func UserIDFromContext(ctx context.Context) (uuid.UUID, bool) {
	v, ok := ctx.Value(userIDContextKey).(uuid.UUID)
	if !ok {
		return uuid.Nil, false
	}
	return v, true
}

// withVerifiedClaims stores signature-verified JWT claims in the request
// context. Called only from Client.Middleware after VerifyToken succeeds.
func withVerifiedClaims(ctx context.Context, claims *VerifiedClaims) context.Context {
	return context.WithValue(ctx, claimsContextKey, claims)
}

// verifiedClaimsFromContext returns the signature-verified JWT claims
// attached by Client.Middleware.
func verifiedClaimsFromContext(ctx context.Context) (*VerifiedClaims, bool) {
	v, ok := ctx.Value(claimsContextKey).(*VerifiedClaims)
	return v, ok
}

// ClaimsFromContext is the public accessor for the verified JWT claims
// attached by Client.Middleware. Handlers that need the raw email claim
// (onboarding uses it to seed paliad.users.email) go through this.
func ClaimsFromContext(ctx context.Context) (*VerifiedClaims, bool) {
	return verifiedClaimsFromContext(ctx)
}

// WithUserID reads the `sub` claim from verified JWT claims attached by
// Client.Middleware and injects the user's UUID into the request context.
// Must run after Client.Middleware — the claims are only set there, after
// signature verification succeeds.
func (c *Client) WithUserID(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		claims, ok := verifiedClaimsFromContext(r.Context())
		if !ok {
			next.ServeHTTP(w, r)
			return
		}
		uid, err := uuid.Parse(claims.Sub)
		if err != nil {
			next.ServeHTTP(w, r)
			return
		}
		ctx := context.WithValue(r.Context(), userIDContextKey, uid)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}
