// Package userid extracts the calling user identifier from the trusted
// `X-User-ID` header injected by gateway and exposes it through the request
// context.
//
// Backend trusts the header value because the network segment between gateway
// and backend is the trust boundary (see `ARCHITECTURE.md` §15). The
// middleware therefore only validates the syntactic shape (UUID) and rejects
// malformed or absent values with the standard `400 invalid_request` envelope.
package userid

import (
	"context"
	"net/http"
	"strings"

	"galaxy/backend/internal/server/httperr"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// Header is the canonical case-correct header name carrying the trusted user
// id forwarded by gateway.
const Header = "X-User-ID"

// userIDContextKey is the unexported context key used to store the parsed
// user id. The unexported value type prevents accidental collisions with
// keys defined in unrelated packages.
type userIDContextKey struct{}

// Middleware returns the gin middleware that requires a syntactically valid
// `X-User-ID` header on every authenticated user request and stores the
// parsed UUID on the request context.
func Middleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		raw := strings.TrimSpace(c.GetHeader(Header))
		if raw == "" {
			httperr.Abort(c, http.StatusBadRequest, httperr.CodeInvalidRequest, Header+" header is required")
			return
		}

		userID, err := uuid.Parse(raw)
		if err != nil {
			httperr.Abort(c, http.StatusBadRequest, httperr.CodeInvalidRequest, Header+" header must be a valid UUID")
			return
		}

		c.Request = c.Request.WithContext(WithValue(c.Request.Context(), userID))
		c.Next()
	}
}

// FromContext returns the user id stored on ctx by Middleware. The boolean
// reports whether a value was found.
func FromContext(ctx context.Context) (uuid.UUID, bool) {
	if ctx == nil {
		return uuid.Nil, false
	}
	value, ok := ctx.Value(userIDContextKey{}).(uuid.UUID)
	if !ok {
		return uuid.Nil, false
	}
	return value, true
}

// WithValue stores userID on ctx under the package-private context key.
// Exposed for tests that need to build a context outside the middleware.
func WithValue(ctx context.Context, userID uuid.UUID) context.Context {
	return context.WithValue(ctx, userIDContextKey{}, userID)
}
