package middleware

import (
	"bytes"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"runtime/debug"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

func NewLogger() gin.HandlerFunc {
	//lg := logger.Logger()
	return func(c *gin.Context) {
		// 开始时间
		startTime := time.Now()               // 处理请求
		endTime := time.Now()                 // 执行时间
		latencyTime := endTime.Sub(startTime) // 请求方式
		path := c.Request.URL.Path
		query := c.Request.URL.RawQuery
		data, _ := ioutil.ReadAll(c.Request.Body)
		log.Printf("[%s] %s %d %s %s %s %s %s %s", path, c.Request.Method, c.Writer.Status(), query,
			string(data), c.ClientIP(), c.Request.UserAgent(), c.Errors.ByType(gin.ErrorTypePrivate).String(), latencyTime.String())

		c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
		c.Next()
	}
}

// GinRecovery recover掉项目可能出现的panic,并记录日志
func GinRecovery(stack bool) gin.HandlerFunc {
	//logger := logger.Logger()
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				// Check for a broken connection, as it is not really a
				// condition that warrants a panic stack trace.
				var brokenPipe bool
				if ne, ok := err.(*net.OpError); ok {
					if se, ok := ne.Err.(*os.SyscallError); ok {
						if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
							brokenPipe = true
						}
					}
				}

				httpRequest, _ := httputil.DumpRequest(c.Request, false)
				if brokenPipe {
					log.Printf("[%s] %s %s", c.Request.URL.Path, err, string(httpRequest))
					// If the connection is dead, we can't write a status to it.
					c.Error(err.(error)) // nolint: errcheck
					c.Abort()
					return
				}

				log.Printf("[%s] %s %s %s", "[Recovery from panic]", err, string(httpRequest), string(debug.Stack()))

				c.AbortWithStatus(http.StatusInternalServerError)
			}
		}()
		c.Next()
	}
}