package api

import (
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/auth-server/commons/metrics"
	tierrs "github.com/tidbcloud/tiinf/errs"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"github.com/tidbcloud/tiinf/transport/http/tigin"
)

const (
	MAX_BODY_SIZE = 5 * 1024 * 1024
)

func CheckRequestBodySize(c *gin.Context) {
	ctx := c.Request.Context()
	x := c.Request.ContentLength
	if x > MAX_BODY_SIZE {
		tilog.Error(ctx, "ERROR:CheckRequestBodySize exceed max size!")
		c.JSON(http.StatusForbidden, APIError{
			Code:    http.StatusForbidden,
			Message: "CheckRequestBodySize exceed max size!",
		})
		c.Abort()
		return
	}
	c.Next()
}

func CheckAuthByTestHeader(c *gin.Context) {
	userEmail := c.GetHeader("X-Test-User-Email")
	userID := c.GetHeader("X-Test-User-ID")
	if userEmail == "" || userID == "" {
		msg := "X-Test-User-Email or X-Test-User-ID in hear is empty when running in test mode"
		tilog.Info(c.Request.Context(), msg)
		tigin.AbortWithError(c, tierrs.NewUnauthorized("unauthorized, "+msg, nil))
		return
	}
	userIDInt, err := strconv.ParseUint(userID, 10, 64)
	if err != nil {
		tigin.AbortWithError(c, tierrs.NewUnauthorized("unauthorized", nil))
		return
	}
	user := &account.User{Id: userIDInt, Email: userEmail}
	c.Set(tigin.CURRENT_USER, user)
	c.Next()
}

func MethodNotAllowedHandler(c *gin.Context) {
	c.JSON(http.StatusMethodNotAllowed, gin.H{
		"error":             "method_not_allowed",
		"error_description": "The method is not allowed for the requested URL.",
	})
}

func Metrics(c *gin.Context) {
	tBegin := time.Now()
	c.Next()

	duration := float64(time.Since(tBegin)) / float64(time.Millisecond)

	path := c.FullPath()

	httpStatus := c.Writer.Status()

	metrics.HTTPReqTotal.With(prometheus.Labels{
		"method": c.Request.Method,
		"path":   path,
		"status": strconv.Itoa(httpStatus),
	}).Inc()

	metrics.HTTPReqDuration.With(prometheus.Labels{
		"method": c.Request.Method,
		"path":   path,
	}).Observe(duration)
}
