package middleware

import (
	"context"
	"net/http"

	"github.com/google/uuid"

	"{{GO_MODULE}}/pkg/httpcontext"
	"{{GO_MODULE}}/pkg/logging"
)

// RequestIDHeader is the header name for request IDs.
const RequestIDHeader = "X-Request-ID"

// RequestID returns middleware that generates/extracts request IDs.
//
// If X-Request-ID header is present in the incoming request, uses that value.
// This allows clients to set their own request IDs for tracking purposes.
// Otherwise generates a new UUID.
//
// The request ID is stored in context using httpcontext.SetRequestID and
// also set in the X-Request-ID response header for client correlation.
//
// This middleware is idempotent - if a request ID is already present in the
// context (from a previous middleware), it will not be overwritten.
//
// Usage:
//
//	r.Use(middleware.RequestID())
//	r.Use(middleware.RequestLogger(logger))
//
// In handlers, retrieve the request ID:
//
//	requestID, ok := httpcontext.GetRequestID(r.Context())
func RequestID() func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// Check if request ID already in context (idempotent)
			if existingID, ok := httpcontext.GetRequestID(r.Context()); ok && existingID != "" {
				// Already set, set response header and continue
				w.Header().Set(RequestIDHeader, existingID)
				next.ServeHTTP(w, r)
				return
			}

			// Try to get request ID from incoming header
			requestID := r.Header.Get(RequestIDHeader)

			// If not present, generate a new UUID
			if requestID == "" {
				requestID = uuid.New().String()
			}

			// Store in context (both httpcontext and logging)
			ctx := httpcontext.SetRequestID(r.Context(), requestID)
			ctx = logging.WithRequestID(ctx, requestID)

			// Set response header for client correlation
			w.Header().Set(RequestIDHeader, requestID)

			// Continue with request ID in context
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

// GetRequestID returns the request ID from context.
// This is a convenience wrapper around httpcontext.GetRequestID.
//
// Returns the request ID string if present, empty string if not found.
func GetRequestID(ctx context.Context) string {
	requestID, _ := httpcontext.GetRequestID(ctx)
	return requestID
}
