// Filename: internal/middleware/logging.go

package middleware

import (
	"bytes"
	"io"
	"regexp"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
)

const (
	RedactedBodyKey       = "redactedBody"
	RedactedAuthHeaderKey = "redactedAuthHeader"
	RedactedValue         = `"[REDACTED]"`
)

// 预编译正则表达式（全局变量，提升性能）
var (
	// JSON 敏感字段脱敏
	jsonSensitiveKeys = regexp.MustCompile(`("(?i:api_key|apikey|token|password|secret|authorization|key|keys|auth)"\s*:\s*)"[^"]*"`)

	// Bearer Token 脱敏
	bearerTokenPattern = regexp.MustCompile(`^(Bearer\s+)\S+$`)

	// URL 中的 key 参数脱敏
	queryKeyPattern = regexp.MustCompile(`([?&](?i:key|token|apikey)=)[^&\s]+`)
)

// RedactionMiddleware 请求数据脱敏中间件
func RedactionMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 1. 脱敏请求体
		if shouldRedactBody(c) {
			redactRequestBody(c)
		}

		// 2. 脱敏认证头
		redactAuthHeader(c)

		// 3. 脱敏 URL 查询参数
		redactQueryParams(c)

		c.Next()
	}
}

// shouldRedactBody 判断是否需要脱敏请求体
func shouldRedactBody(c *gin.Context) bool {
	method := c.Request.Method
	contentType := c.GetHeader("Content-Type")

	// 只处理包含 JSON 的 POST/PUT/PATCH/DELETE 请求
	return (method == "POST" || method == "PUT" || method == "PATCH" || method == "DELETE") &&
		strings.Contains(contentType, "application/json")
}

// redactRequestBody 脱敏请求体
func redactRequestBody(c *gin.Context) {
	bodyBytes, err := io.ReadAll(c.Request.Body)
	if err != nil {
		return
	}

	// 恢复请求体供后续使用
	c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))

	// 脱敏敏感字段
	bodyString := string(bodyBytes)
	redactedBody := jsonSensitiveKeys.ReplaceAllString(bodyString, `$1`+RedactedValue)

	c.Set(RedactedBodyKey, redactedBody)
}

// redactAuthHeader 脱敏认证头
func redactAuthHeader(c *gin.Context) {
	authHeader := c.GetHeader("Authorization")
	if authHeader == "" {
		return
	}

	if bearerTokenPattern.MatchString(authHeader) {
		redacted := bearerTokenPattern.ReplaceAllString(authHeader, `${1}[REDACTED]`)
		c.Set(RedactedAuthHeaderKey, redacted)
	} else {
		// 对于非 Bearer 的 token，全部脱敏
		c.Set(RedactedAuthHeaderKey, "[REDACTED]")
	}

	// 同时处理其他敏感 Header
	sensitiveHeaders := []string{"X-Api-Key", "X-Goog-Api-Key", "Api-Key"}
	for _, header := range sensitiveHeaders {
		if value := c.GetHeader(header); value != "" {
			c.Set("redacted_"+header, "[REDACTED]")
		}
	}
}

// redactQueryParams 脱敏 URL 查询参数
func redactQueryParams(c *gin.Context) {
	rawQuery := c.Request.URL.RawQuery
	if rawQuery == "" {
		return
	}

	redacted := queryKeyPattern.ReplaceAllString(rawQuery, `${1}[REDACTED]`)
	if redacted != rawQuery {
		c.Set("redactedQuery", redacted)
	}
}

// LogrusLogger Gin 请求日志中间件（使用 Logrus）
func LogrusLogger(logger *logrus.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		method := c.Request.Method

		// 处理请求
		c.Next()

		// 计算延迟
		latency := time.Since(start)
		statusCode := c.Writer.Status()
		clientIP := c.ClientIP()

		// 构建日志字段
		fields := logrus.Fields{
			"status":     statusCode,
			"latency_ms": latency.Milliseconds(),
			"ip":         clientIP,
			"method":     method,
			"path":       path,
		}

		// 添加请求 ID（如果存在）
		if requestID := getRequestID(c); requestID != "" {
			fields["request_id"] = requestID
		}

		// 添加脱敏后的数据
		if redactedBody, exists := c.Get(RedactedBodyKey); exists {
			fields["body"] = redactedBody
		}

		if redactedAuth, exists := c.Get(RedactedAuthHeaderKey); exists {
			fields["authorization"] = redactedAuth
		}

		if redactedQuery, exists := c.Get("redactedQuery"); exists {
			fields["query"] = redactedQuery
		}

		// 添加用户信息（如果已认证）
		if user := getAuthenticatedUser(c); user != "" {
			fields["user"] = user
		}

		// 根据状态码选择日志级别
		entry := logger.WithFields(fields)

		if len(c.Errors) > 0 {
			fields["errors"] = c.Errors.String()
			entry.Error("Request failed")
		} else {
			switch {
			case statusCode >= 500:
				entry.Error("Server error")
			case statusCode >= 400:
				entry.Warn("Client error")
			case statusCode >= 300:
				entry.Info("Redirect")
			default:
				// 只在 Debug 模式记录成功请求
				if logger.Level >= logrus.DebugLevel {
					entry.Debug("Request completed")
				}
			}
		}
	}
}

// getRequestID 获取请求 ID
func getRequestID(c *gin.Context) string {
	if id, exists := c.Get("request_id"); exists {
		if requestID, ok := id.(string); ok {
			return requestID
		}
	}
	return ""
}

// getAuthenticatedUser 获取已认证用户标识
func getAuthenticatedUser(c *gin.Context) string {
	// 尝试从不同来源获取用户信息
	if user, exists := c.Get("adminUser"); exists {
		if authToken, ok := user.(interface{ GetID() string }); ok {
			return authToken.GetID()
		}
	}

	if user, exists := c.Get("authToken"); exists {
		if authToken, ok := user.(interface{ GetID() string }); ok {
			return authToken.GetID()
		}
	}

	return ""
}
