package http_middleware

import (
	"fmt"
	"git.aionnect.com/aionnect/go-common/utils"
	"git.aionnect.com/aionnect/go-common/utils/date"
	"git.aionnect.com/aionnect/go-common/utils/logger"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
)

// Recovery中间件(统一错误处理)
func Recovery(hostPrefix string, logger *logger.Logger) gin.HandlerFunc {
	return func(ctxt *gin.Context) {
		defer func() {
			if err := recover(); err != nil && logger != nil {
				stack := string(utils.GetStack(4))
				if i, ok := ctxt.Get(HTTPRequestStartTime); ok {
					if start, ok := i.(date.Datetime); ok {
						end := date.Now()
						latency := end.Sub(start)
						logger = logger.WithField("latency", fmt.Sprintf("%v", latency))
					}
				}
				clientIP := ctxt.ClientIP()
				comment := ctxt.Errors.ByType(gin.ErrorTypePrivate).String()
				req, fields := splitUri(hostPrefix, ctxt)
				logHttpRequest := true
				if i, ok := ctxt.Get(IsNoLogHTTPRequest); ok {
					if isNoLogHttpRequest, ok := i.(bool); ok && isNoLogHttpRequest {
						logHttpRequest = false
					}
				}
				if logHttpRequest {
					if reader, ok := ctxt.Request.Body.(*reqBodyLogReader); ok {
						logger = logger.WithField("requestBody", reader.buffer.String())
					}
				}
				logger = logger.
					WithField("clientIP", clientIP).
					WithField("comment", comment).
					WithFields(fields)

				var res *utils.Res
				if r, ok := err.(*utils.Res); ok {
					res = r
				} else if r, ok := err.(utils.Res); ok {
					res = &r
				}
				if res != nil {
					httpStatus := http.StatusBadRequest
					var s1, s2 string
					if nil != &res.Head {
						if res.Head.HttpStatus > 0 {
							httpStatus = res.Head.HttpStatus
						}
						s1 = res.Head.ErrMsg
						s2 = res.Head.Detail
						if strings.Contains(s2, s1) {
							s1 = ""
						}
						if strings.Contains(s1, s2) {
							s2 = ""
						}
					} else {
						res.Head = utils.ResHead{ErrCode: -1, ErrMsg: "未定义"}
					}
					if i, ok := ctxt.Get(IsLogHTTPResponse); ok {
						if isLogHttpResponse, ok := i.(bool); ok && isLogHttpResponse {
							respData, _ := res.MarshalJSON()
							logger = logger.WithField("responseBody", string(respData))
						}
					}
					logger.
						WithCaller(4).
						WithField("tag", "Custom warn").
						WithField("httpStatus", httpStatus).
						WithField("errCode", res.Head.ErrCode).
						WithField("errMsg", strings.TrimSpace(fmt.Sprintf("%d %s %s", res.Head.ErrCode, s1, s2))).
						Warn(req)
					ctxt.JSON(httpStatus, res)
					ctxt.Abort()
				} else {
					res := utils.E(9999, "未定义", nil)
					if i, ok := ctxt.Get(IsLogHTTPResponse); ok {
						if isLogHttpResponse, ok := i.(bool); ok && isLogHttpResponse {
							logger = logger.WithField("responseBody", `{"head":{"errcode":9999,"errmsg":"未定义"}}`)
						}
					}
					logger.
						WithCaller(5).
						WithField("tag", "Catch Exception").
						WithField("httpStatus", http.StatusBadRequest).
						WithField("errCode", 9999).
						WithField("errMsg", fmt.Sprintf("9999 %s", err)).
						Error(req)
					println(stack)
					ctxt.JSON(http.StatusBadRequest, res)
					ctxt.Abort()
				}
			}
		}()
		ctxt.Next()
	}
}