package middleware

import (
	"bytes"
	"fmt"
	"go-admin/common/global"
	"go-admin/logger"
	config2 "go-admin/tools/config"
	"io"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"

	"go-admin/app/admin/models"
	"go-admin/tools"
)

// LoggerToFile 日志记录到文件
func LoggerToFile() gin.HandlerFunc {

	return func(c *gin.Context) {
		RequestInLog(c)
		defer RequestOutLog(c)
		c.Next()

	}
}

// RequestInLog 请求进入日志
func RequestInLog(c *gin.Context) {
	// 开始时间
	startTime := time.Now()
	c.Set("startExecTime", startTime)

	// 请求参数
	bodyBytes, _ := io.ReadAll(c.Request.Body)
	c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
	c.Set("req", string(bodyBytes))

}

// RequestOutLog 请求输出日志
func RequestOutLog(c *gin.Context) {
	// 请求方式
	reqMethod := c.Request.Method

	// 请求路由
	reqUri := c.Request.RequestURI

	// 请求IP
	clientIP := c.ClientIP()

	// 请求参数
	req, _ := c.Get("req")
	fmt.Println(req)

	// 状态码
	statusCode := c.Writer.Status()

	// 返回参数
	response, _ := c.Get("response")
	fmt.Println(response)

	// 结束时间
	endTime := time.Now()

	// 执行时间
	st, _ := c.Get("startExecTime")
	startTime, _ := st.(time.Time)
	latencyTime := endTime.Sub(startTime)

	/// 日志格式
	fmt.Printf("%s [INFO] %s %s %3d %13v %15s \r\n",
		startTime.Format("2006-01-02 15:04:05"),
		reqMethod,
		reqUri,
		statusCode,
		latencyTime,
		clientIP,
	)

	logger.Info(
		"log request",
		logger.Field("status", statusCode),
		logger.Field("spendTime", latencyTime),
		logger.Field("clientId", clientIP),
		logger.Field("method", reqMethod),
		logger.Field("uri", reqUri),
		logger.Field("reqBody", req),
		logger.Field("response", response),
		logger.Field("requestId", tools.GenerateMsgIDFromContext(c)),
	)

	//只有在白名单中的url才记录操作日志
	resultUrl := strings.Replace(c.Request.RequestURI, "/api/v1", "", 1)
	_, ok := global.WHILTE[resultUrl]

	if c.Request.Method != "GET" && c.Request.Method != "OPTIONS" && config2.LoggerConfig.EnabledDB && ok {
		reqParam, respParam := "", ""
		if req != nil {
			reqParam = req.(string)
		}

		if response != nil {
			respParam = response.(string)
		}
		SetDBOperLog(c, clientIP, statusCode, reqUri, reqMethod, latencyTime, reqParam, respParam)
	}
}

// SetDBOperLog 写入操作日志表
func SetDBOperLog(c *gin.Context, clientIP string, statusCode int, reqUri string, reqMethod string,
	latencyTime time.Duration, req string, resp string) {
	menu := models.Menu{}
	menu.Path = reqUri
	menu.Action = reqMethod
	menuList, _ := menu.Get()
	sysOperLog := models.SysOperLog{}
	sysOperLog.OperIp = clientIP
	sysOperLog.OperLocation = tools.GetLocation(clientIP)
	sysOperLog.Status = tools.IntToString(statusCode)
	sysOperLog.OperName = tools.GetUserName(c)
	sysOperLog.RequestMethod = c.Request.Method
	sysOperLog.OperUrl = reqUri
	if reqUri == "/login" {
		sysOperLog.Title = "用户登录"
		sysOperLog.OperName = "-"
	} else if strings.Contains(reqUri, "/api/v1/getCaptcha") {
		sysOperLog.Title = "验证码"
	}

	// 从白名单中读取对应的操作类型
	resultUrl := strings.Replace(c.Request.RequestURI, "/api/v1", "", 1)
	nType, _ := global.WHILTE[resultUrl]
	sysOperLog.BusinessType = strconv.Itoa(nType)

	sysOperLog.Method = reqMethod
	if len(menuList) > 0 {
		sysOperLog.Title = menuList[0].Title //事件
		menu.Title = menuList[0].Title
		sysOperLog.MenuTitle, _ = menu.GetParentTitle() //操作模块
	}

	sysOperLog.CreateBy = tools.GetUserName(c)
	sysOperLog.OperTime = tools.GetCurrentTime()
	sysOperLog.LatencyTime = (latencyTime).String()
	sysOperLog.UserAgent = c.Request.UserAgent()
	if c.Err() == nil {
		sysOperLog.Status = "0"
	} else {
		sysOperLog.Status = "1"
	}

	sysOperLog.OperParam = req
	sysOperLog.JsonResult = resp

	_, _ = sysOperLog.Create()
}
