package middleware

import (
	"bytes"
	"io/ioutil"
	"log"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/niangaodev/art-code/models"
	"github.com/niangaodev/art-code/repositories"
	"github.com/niangaodev/art-code/utils"
)

// OperationLogMiddleware 操作日志中间件
func OperationLogMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 开始时间
		startTime := time.Now()

		// 读取请求参数
		var requestBody []byte
		if c.Request.Method != "GET" {
			body, err := ioutil.ReadAll(c.Request.Body)
			if err != nil {
				log.Printf("Error reading request body: %v", err)
			} else {
				requestBody = body
				// 重置请求体，以便后续处理
				c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody))
			}
		}

		// 执行请求
		c.Next()

		// 结束时间
		endTime := time.Now()
		// 计算请求持续时间（毫秒）
		duration := int(endTime.Sub(startTime).Milliseconds())

		// 获取用户信息
		userID, exists := c.Get("userID")
		if !exists {
			return
		}

		username, _ := c.Get("username")

		// 获取IP归属地
		ip := c.ClientIP()
		var region string
		// 使用 recover 保护 GetRegion 调用
		func() {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("Panic in GetRegion for IP %s (operation log): %v", ip, r)
					region = "Unknown"
				}
			}()
			region = utils.GetRegion(ip)
		}()

		// 确保 region 不为空，如果为空则设置为 "Unknown"
		if region == "" {
			region = "Unknown"
		}

		// 记录调试信息
		log.Printf("Creating operation log: UserID=%d, IP=%s, Region=%s, Path=%s", userID.(uint), ip, region, c.Request.URL.Path)

		// 构建操作日志
		path := c.Request.URL.Path
		method := c.Request.Method
		operationLog := &models.OperationLog{
			UserID:   userID.(uint),
			Username: username.(string),
			IP:       ip,
			Region:   region,
			Path:     path,
			Method:   method,
			Action:   utils.GetOperationAction(path, method),
			Params:   string(requestBody),
			Status:   c.Writer.Status(),
			Duration: duration,
		}

		// 异步记录日志，避免影响响应
		go func() {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("Panic in CreateOperationLog goroutine: %v", r)
				}
			}()

			if err := repositories.CreateOperationLog(operationLog); err != nil {
				log.Printf("Error creating operation log for UserID=%d, IP=%s, Region=%s: %v", userID.(uint), ip, region, err)
			} else {
				log.Printf("Successfully created operation log: UserID=%d, IP=%s, Region=%s", userID.(uint), ip, region)
			}
		}()
	}
}
