package httputil

import (
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/samber/lo"
	"go.uber.org/zap"

	"github.com/tidbcloud/tidb-management-service/utilities/grpc"
)

var (
	ignoredPaths = []string{"/metrics", "/healthz", "/readyz", "/pprof", "/version", "/debug", "/swagger", "/ping"}
)

func GinServerPayloadLogger(c *gin.Context) {
	start := time.Now()
	method := c.Request.Method
	url := c.Request.URL
	ip := c.ClientIP()

	// dump request body
	br := newBodyReader(c.Request.Body, grpc.StringEntryMaxSize)
	c.Request.Body = br

	// dump response body
	bw := newBodyWriter(c.Writer, grpc.StringEntryMaxSize)
	c.Writer = bw

	c.Next()

	if ok := lo.ContainsBy(ignoredPaths, func(item string) bool {
		return strings.Contains(url.Path, item)
	}); ok {
		return
	}

	status := c.Writer.Status()
	latency := time.Since(start)
	ctx := c.Request.Context()

	if status >= http.StatusBadRequest {
		grpc.GetPayloadLogger(ctx).Error(
			"<--- http server (gin)",
			zap.String("method", method),
			zap.Int("status", status),
			zap.String("url", url.String()),
			zap.String("request", br.body.String()),
			zap.String("response", bw.body.String()),
			zap.Duration("cost", latency),
			zap.String("client_ip", ip),
		)
	} else {
		grpc.GetPayloadLogger(ctx).Info(
			"<--- http server (gin)",
			zap.String("method", method),
			zap.Int("status", status),
			zap.String("url", url.String()),
			zap.String("request", br.body.String()),
			zap.String("response", bw.body.String()),
			zap.Duration("cost", latency),
			zap.String("client_ip", ip),
		)
	}
}
