package middleware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-nunu/nunu-layout-advanced/internal/model"
	"github.com/go-nunu/nunu-layout-advanced/internal/service"
	"github.com/go-nunu/nunu-layout-advanced/pkg/jwt"
	"io"
	"net/http"
	"strconv"
)

// OperationLogMiddleware 记录操作日志到数据库
func OperationLogMiddleware(logService service.LogService) gin.HandlerFunc {
	return func(c *gin.Context) {

		var requestBody []byte
		if c.Request.Body != nil {
			requestBody, _ = io.ReadAll(c.Request.Body)
			c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
		}

		blw := &bodyLogWriter{
			body:           bytes.NewBufferString(""),
			ResponseWriter: c.Writer,
		}
		c.Writer = blw

		c.Next()

		go func() {
			ctxCopy := c.Copy()
			statusCode := ctxCopy.Writer.Status()

			var userID uint
			if claims, exists := ctxCopy.Get("claims"); exists {
				if customClaims, ok := claims.(*jwt.MyCustomClaims); ok {
					userID = customClaims.UserId
				}
			}

						// 如果JWT和Query中都没有，尝试从请求体中获取
			if userID == 0 && len(requestBody) > 0 {
				var bodyData map[string]interface{}
				if err := json.Unmarshal(requestBody, &bodyData); err == nil {
					if uidVal, ok := bodyData["uid"]; ok {
						if uidFloat, ok := uidVal.(float64); ok {
							userID = uint(uidFloat)
						}
					}
				}
			}

			if userID == 0 {
				if uidStr := ctxCopy.Query("uid"); uidStr != "" {
					if uid, err := strconv.ParseUint(uidStr, 10, 64); err == nil {
						userID = uint(uid)
					}
				}
			}

			if userID == 0 && (ctxCopy.Request.URL.Path == "/api/v1/login" || ctxCopy.Request.URL.Path == "/api/v1/user/login") && statusCode == http.StatusOK {
				var response struct {
					Data struct {
						ID uint `json:"id"`
					} `json:"data"`
				}
				if err := json.Unmarshal(blw.body.Bytes(), &response); err == nil {
					userID = response.Data.ID
				}
			}

			var traceID string
			if id, ok := ctxCopy.Get(TraceIDKey); ok {
				traceID, _ = id.(string)
			}

			var requestBodyForLog interface{}
			if len(requestBody) > 0 {
				if err := json.Unmarshal(requestBody, &requestBodyForLog); err != nil {
					// 如果解析失败, 则按原始字符串存储
					requestBodyForLog = string(requestBody)
				}
			}

			var responseBodyForLog interface{}
			responseBodyBytes := blw.body.Bytes()
			if len(responseBodyBytes) > 0 {
				if err := json.Unmarshal(responseBodyBytes, &responseBodyForLog); err != nil {
					// 如果解析失败, 则按原始字符串存储
					responseBodyForLog = blw.body.String()
				}
			}

						// 只记录请求体到 ExtraData
			extraData, _ := json.Marshal(requestBodyForLog)

			logEntry := &model.Log{
				TraceId:    traceID,
				Uid:        int64(userID),
				RequestIp:  ctxCopy.ClientIP(),
				Api:        ctxCopy.Request.RequestURI,
				Message:    fmt.Sprintf("[%s] %s - %d", ctxCopy.Request.Method, ctxCopy.Request.URL.Path, statusCode),
				ExtraData:  extraData,
				UserAgent:  ctxCopy.Request.UserAgent(),
				StatusCode: statusCode,
			}

			_ = logService.AddLog(ctxCopy, logEntry)
		}()
	}
}
