package auth

import (
	"context"
	"errors"
)

// contextKey is a private type for context keys to prevent collisions.
type contextKey int

const (
	userKey contextKey = iota
	tokenKey
)

// SetUser stores a user in the context.
func SetUser(ctx context.Context, user *User) context.Context {
	return context.WithValue(ctx, userKey, user)
}

// GetUser retrieves the user from the context.
// Returns nil if no user is present.
func GetUser(ctx context.Context) *User {
	user, _ := ctx.Value(userKey).(*User)
	return user
}

// MustGetUser retrieves the user from the context.
// Panics if no user is present - use only in handlers protected by RequireAuth middleware.
// For non-middleware contexts, prefer GetUserOrError which returns an error.
func MustGetUser(ctx context.Context) *User {
	user := GetUser(ctx)
	if user == nil {
		panic("auth: user not found in context - ensure RequireAuth middleware is applied")
	}
	return user
}

// GetUserOrError retrieves the user from the context, returning an error if not present.
// Prefer this over MustGetUser when panic recovery is not guaranteed.
func GetUserOrError(ctx context.Context) (*User, error) {
	user := GetUser(ctx)
	if user == nil {
		return nil, errors.New("auth: user not found in context")
	}
	return user, nil
}

// IsAuthenticated returns true if a user is present in the context.
func IsAuthenticated(ctx context.Context) bool {
	return GetUser(ctx) != nil
}

// SetToken stores the raw token in the context.
func SetToken(ctx context.Context, token string) context.Context {
	return context.WithValue(ctx, tokenKey, token)
}

// GetToken retrieves the raw token from the context.
func GetToken(ctx context.Context) string {
	token, _ := ctx.Value(tokenKey).(string)
	return token
}
