package interceptor

import (
	"bytes"
	"io"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.opentelemetry.io/otel/trace"
	"go.uber.org/zap"
)

func Log(c *gin.Context) {
	// Starting time
	startTime := time.Now()

	var body []byte
	if tilog.GetLevel().Enabled(zap.DebugLevel) {
		// copy body for logging
		body, _ = io.ReadAll(c.Request.Body)
		c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
	}
	// Request method
	reqMethod := c.Request.Method

	// Request route
	reqUri := c.Request.RequestURI

	// Request IP
	clientIP := c.ClientIP()
	logger := tilog.WithContextL(c.Request.Context()).With(
		zap.String("method", reqMethod),
		zap.String("uri", reqUri),
		zap.String("client", clientIP),
	)
	logger.Info("begin")

	// Processing request
	c.Next()

	// End Time
	endTime := time.Now()

	// execution time
	latencyTime := endTime.Sub(startTime)

	// status code
	statusCode := c.Writer.Status()

	logger = logger.With(
		zap.Int("status", statusCode),
		zap.Duration("latency", latencyTime),
		zap.Any("params", c.Request.URL.Query()),
	)
	if errs := c.Errors.ByType(gin.ErrorTypePrivate); len(errs) > 0 {
		logger = logger.With(zap.String("error", errs.String()))
	}

	if tilog.GetLevel().Enabled(zap.DebugLevel) {
		logger = logger.With(zap.ByteString("body", body))
		logger.Debug("end")
	} else {
		logger.Info("end")
	}
}

// SetResponseTraceID is copied from https://github.com/tidbcloud/tiinf/blob/master/transport/http/tigin/middlewares.go to avoid import too many useless packages
func SetResponseTraceID(c *gin.Context) {
	spanCtx := trace.SpanContextFromContext(c.Request.Context())
	if spanCtx.HasTraceID() {
		c.Header("x-debug-trace-id", spanCtx.TraceID().String())
	}
	c.Next()
}
