package tests

import (
	"fmt"
	"github.com/pingcap/dbaas/billing2/middleware"
	"net/http"
	"testing"

	"github.com/pingcap/dbaas/billing2/api"
	"github.com/pingcap/dbaas/billing2/version"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/handler/metricshandler"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/stretchr/testify/suite"
)

type MetricsTestSuite struct {
	tests.BillingTestSuite
	router *gin.Engine
}
type VersionResp struct {
	Hash string `json:"hash"`
}

func (suite *MetricsTestSuite) SetupTest() {
	suite.BillingTestSuite.SetupTest()
	suite.router = gin.New()
	suite.router.Use(ginutils.ErrorMiddleWare)
}

func TestMetricsSuite(t *testing.T) {
	suite.Run(t, new(MetricsTestSuite))
}

func (suite *MetricsTestSuite) TestMetricsWithLables() {
	metricshandler.RegisterMetricsRouteWithSub(suite.router, "gin1")

	assert := suite.Assert()
	metricshandler.MeasureInput.Inc()
	tests.PerformGetRequest(suite.router, "/units")
	w := tests.PerformGetRequest(suite.router, "/metrics")
	assert.Equal(http.StatusOK, w.Code)
	fmt.Println(w.Body.String())
	assert.Contains(w.Body.String(), `dbaas_billing_test_counter 1`)

	metricshandler.MeasureLabeledInput.WithLabelValues("l1", "l2").Inc()

	w = tests.PerformGetRequest(suite.router, "/metrics")
	assert.Equal(http.StatusOK, w.Code)
	fmt.Println(w.Body.String())

	assert.Contains(w.Body.String(), `dbaas_billing_test_labeled_counter{label1="l1",label2="l2"} 1`)
}

func (suite *MetricsTestSuite) TestNomralMetricsAPI() {
	// order: RegisterMetricsRoute -- r.Group
	assert := suite.Assert()
	r := suite.router
	metricshandler.RegisterMetricsRouteWithSub(suite.router, "gin2")

	r.GET("/version", func(c *gin.Context) { c.JSON(http.StatusOK, &VersionResp{Hash: version.GitHash}) })
	billingGroup := suite.router.Group("/api/v1/billing")
	ws := ginutils.MyRoute{Route: billingGroup}
	api.InitializeUnitRouter(ws)

	tests.PerformGetRequest(r, "/api/v1/billing/units")
	w := tests.PerformGetRequest(r, "/metrics")
	assert.Equal(http.StatusOK, w.Code)
	fmt.Println(w.Body.String())
	assert.Contains(w.Body.String(), `gin2_request_duration_seconds_bucket{code=`)

}
func (suite *MetricsTestSuite) TestErrorMetricsAPI() {
	//order: r.Group -- RegisterMetricsRoute
	assert := suite.Assert()
	r := suite.router
	r.GET("/version", func(c *gin.Context) { c.JSON(http.StatusOK, &VersionResp{Hash: version.GitHash}) })
	billingGroup := r.Group("/api/v1/billing")
	ws := ginutils.MyRoute{Route: billingGroup}
	api.InitializeUnitRouter(ws)

	metricshandler.RegisterMetricsRouteWithSub(suite.router, "gin3")

	tests.PerformGetRequest(r, "/api/v1/billing/units")
	w := tests.PerformGetRequest(r, "/metrics")
	assert.Equal(http.StatusOK, w.Code)
	fmt.Println(w.Body.String())
	assert.NotContains(w.Body.String(), `gin3_request_duration_seconds_bucket{code=`)

}

func (suite *MetricsTestSuite) TestNomralMetricsRegisterAndMiddlewareOrder() {
	assert := suite.Assert()
	r := suite.router

	metricshandler.RegisterMetricsRouteWithSub(suite.router, "gin5")
	r.Use(
		ginutils.ErrorMiddleWare,
		middleware.UserMiddleware,
	)
	r.GET("/version", func(c *gin.Context) { c.JSON(http.StatusOK, &VersionResp{Hash: version.GitHash}) })
	billingGroup := r.Group("/api/v1/billing")
	ws := ginutils.MyRoute{Route: billingGroup}

	api.InitializeUnitRouter(ws)
	t := tests.PerformGetRequest(r, "/api/v1/billing/units/:unit_key")
	assert.Equal(http.StatusNotFound, t.Code)
	w := tests.PerformGetRequest(r, "/metrics")
	assert.Equal(http.StatusOK, w.Code)

	fmt.Println(w.Body.String())
	assert.NotContains(w.Body.String(), `gin5_request_duration_seconds_bucket{code=404`)

}

func (suite *MetricsTestSuite) TestErrorMetricsRegisterAndMiddlewareOrder() {
	assert := suite.Assert()
	r := suite.router
	r.Use(
		ginutils.ErrorMiddleWare,
		middleware.UserMiddleware,
	)
	metricshandler.RegisterMetricsRouteWithSub(suite.router, "gin4")
	r.GET("/version", func(c *gin.Context) { c.JSON(http.StatusOK, &VersionResp{Hash: version.GitHash}) })
	billingGroup := r.Group("/api/v1/billing")
	ws := ginutils.MyRoute{Route: billingGroup}

	api.InitializeUnitRouter(ws)
	t := tests.PerformGetRequest(r, "/api/v1/billing/units/:unit_key")
	assert.Equal(http.StatusNotFound, t.Code)
	w := tests.PerformGetRequest(r, "/metrics")
	assert.Equal(http.StatusOK, w.Code)

	fmt.Println(w.Body.String())
	assert.NotContains(w.Body.String(), `gin4_request_duration_seconds_bucket{code=200`)

}
