// Package logger provides HTTP middleware and context utilities for logging.
package logger

import (
	"context"

	"git.dcentral.systems/toolz/goplt/pkg/logger"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

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

// ContextKey is a custom type for context keys to avoid collisions.
// It is exported so modules can use it for setting context values.
type ContextKey string

const (
	requestIDKey ContextKey = "request_id"
	userIDKey    ContextKey = "user_id"
)

// RequestIDMiddleware creates a Gin middleware that:
// 1. Generates a unique request ID for each request (or uses existing one from header)
// 2. Adds the request ID to the request context
// 3. Adds the request ID to the response headers
// 4. Makes the request ID available for logging
func RequestIDMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// Check if request ID already exists in header
		requestID := c.GetHeader(RequestIDHeader)

		// Generate new request ID if not present
		if requestID == "" {
			requestID = uuid.New().String()
		}

		// Add request ID to context
		ctx := context.WithValue(c.Request.Context(), requestIDKey, requestID)
		c.Request = c.Request.WithContext(ctx)

		// Add request ID to response header
		c.Header(RequestIDHeader, requestID)

		// Continue processing
		c.Next()
	}
}

// RequestIDFromContext extracts the request ID from the context.
func RequestIDFromContext(ctx context.Context) string {
	if requestID, ok := ctx.Value(requestIDKey).(string); ok {
		return requestID
	}
	return ""
}

// SetRequestID sets the request ID in the context.
func SetRequestID(ctx context.Context, requestID string) context.Context {
	return context.WithValue(ctx, requestIDKey, requestID)
}

// SetUserID sets the user ID in the context.
func SetUserID(ctx context.Context, userID string) context.Context {
	return context.WithValue(ctx, userIDKey, userID)
}

// UserIDFromContext extracts the user ID from the context.
func UserIDFromContext(ctx context.Context) string {
	if userID, ok := ctx.Value(userIDKey).(string); ok {
		return userID
	}
	return ""
}

// LoggingMiddleware creates a Gin middleware that logs HTTP requests.
// It uses the logger from the context and includes request ID.
func LoggingMiddleware(l logger.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Get logger with context
		log := l.WithContext(c.Request.Context())

		// Log request
		log.Info("HTTP request",
			logger.String("method", c.Request.Method),
			logger.String("path", c.Request.URL.Path),
			logger.String("remote_addr", c.ClientIP()),
		)

		// Process request
		c.Next()

		// Log response
		log.Info("HTTP response",
			logger.Int("status", c.Writer.Status()),
			logger.Int("size", c.Writer.Size()),
		)
	}
}
