package logger

import (
	"bytes"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

// LogToFile 日志记录到文件
func LogToFile() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 初始化bodyLogWriter
		blw := &bodyLogWriter{
			body:           bytes.NewBufferString(""),
			ResponseWriter: ctx.Writer,
		}
		ctx.Writer = blw

		// 开始时间
		startTime := time.Now()
		// 请求方式
		reqMethod := ctx.Request.Method
		// 请求路由
		reqUri := ctx.Request.RequestURI
		//如果是查询日志,则跳出,不记录日志
		if strings.Contains(reqUri, "/api/blade-log/usual") {
			ctx.Next()
			return
		}
		//请求参数
		request := getRequestBody(ctx)
		// 请求IP
		clientIP := ctx.ClientIP()

		// 处理请求
		ctx.Next()

		// 结束时间
		endTime := time.Now()
		// 执行时间
		latencyTime := endTime.Sub(startTime)
		// 状态码
		statusCode := ctx.Writer.Status()
		// 响应
		response := blw.body.String()

		//日志格式
		Logger.WithFields(logrus.Fields{
			"status_code":  statusCode,
			"latency_time": latencyTime,
			"client_ip":    clientIP,
			"req_method":   reqMethod,
			"request":      request,
			"response":     response,
			"req_uri":      reqUri,
			"t":            time.Now().UnixMilli(), //用于es中按时间排序
		}).Info()
	}
}

func getRequestBody(ctx *gin.Context) interface{} {
	if strings.Contains(ctx.ContentType(), "multipart/form-data") {
		return "multipart"
	}

	switch ctx.Request.Method {
	case http.MethodGet:
		fallthrough
	case http.MethodDelete:
		return ctx.Request.URL.Query()
	case http.MethodPost:
		fallthrough
	case http.MethodPut:
		fallthrough
	case http.MethodPatch:
		var bodyBytes []byte
		bodyBytes, err := ioutil.ReadAll(ctx.Request.Body)
		if err != nil {
			return nil
		}
		ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
		return string(bodyBytes)
	}
	return nil
}

// bodyLogWriter 定义一个存储响应内容的结构体
type bodyLogWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

// Write 读取响应数据
func (w bodyLogWriter) Write(b []byte) (int, error) {
	w.body.Write(b)
	return w.ResponseWriter.Write(b)
}
