package api

import (
	"github.com/gin-gonic/gin"
	swaggerfiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"

	"github.com/tidbcloud/auth-server/commons/config"
	"github.com/tidbcloud/auth-server/commons/grpc"
	_ "github.com/tidbcloud/auth-server/docs/oauth2"
	oauth2_controller "github.com/tidbcloud/auth-server/internal/controller/oauth2"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"github.com/tidbcloud/tiinf/transport/http/tigin"
)

type RouterManager struct {
	GinEng *gin.Engine

	Oauth2Controller oauth2_controller.Oauth2Controller
}

// @title		AuthServer OAuth2
// @version		1.0
// @description	AuthServer OAuth2 API
// @host		127.0.0.1:10010
// @BasePath	/
func Routers(m *RouterManager) {
	m.GinEng.Any(
		"/healthz", func(c *gin.Context) {
			c.Status(200)
		},
	)

	routeError(m.GinEng)

	m.GinEng.Use(CheckRequestBodySize)
	// should only handle inner-api's cors request
	m.GinEng.Use(Cors("/api/"))
	m.GinEng.Use(Metrics)

	m.GinEng.HandleMethodNotAllowed = true
	m.GinEng.NoMethod(MethodNotAllowedHandler)

	m.GinEng.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))

	// since api-gateway does not support rewrite path,
	// now we directly use /v1 instead of /oauth2/v1 as the prefix,
	// expected public uri will be: https://oauth.tidbcloud.com/v1/device_authorization
	// domain  https://oauth.tidbcloud.com
	oauth2PublicGroup := m.GinEng.Group("/v1")
	{
		oauth2PublicGroup.POST("/device_authorization", m.Oauth2Controller.DeviceAuthorizationEndpoint)
		oauth2PublicGroup.POST("/token", m.Oauth2Controller.TokenEndpoint)
		oauth2PublicGroup.POST("/revoke", m.Oauth2Controller.RevokeEndpoint)
		oauth2PublicGroup.GET("/userinfo", m.Oauth2Controller.GetUserInfoEndpoint)
		//  this api is inner api for tidb cloud
		oauth2PublicGroup.GET("/authInfo", m.Oauth2Controller.GetAccessTokenInfoEndpoint)

	}

	// inner router group for tidb cloud console
	//domains: https://us-west-2.prod.aws.tidbcloud.com
	innerRouterGroup := m.GinEng.Group("/api/v1")
	installAuthPlugin(innerRouterGroup)

	oauth2InnerGroup := innerRouterGroup.Group("/oauth")
	{
		oauth2InnerGroup.POST("/device/check", m.Oauth2Controller.InnerDeviceCodeCheckEndpoint)
		oauth2InnerGroup.POST("/device/confirmation", m.Oauth2Controller.InnerDeviceCodeConfirmationEndpoint)
		oauth2InnerGroup.POST("/authorize/check", m.Oauth2Controller.InnerAuthorizationCodeCheckEndpoint)
		oauth2InnerGroup.POST("/authorize/confirmation", m.Oauth2Controller.InnerAuthorizationCodeConfirmationEndpoint)
		//oauth2InnerGroup.GET("/ops/token", m.Oauth2Controller.InnerQueryTokenEndpoint)
		oauth2InnerGroup.GET("/console/token", m.Oauth2Controller.InnerGetUserLastTokenEndpoint)
		oauth2InnerGroup.POST("/console/token", m.Oauth2Controller.ConsoleRevokeEndpoint)
		oauth2InnerGroup.GET("/console/application/user-authorized", m.Oauth2Controller.InnerQueryUserAuthorizedApplications)

		//  this api is inner api for test
		oauth2InnerGroup.POST("/console/application", m.Oauth2Controller.InnerCreateApplications)

	}
}

func routeError(router *gin.Engine) {
	router.Use(APIErrorJSONReporter())
}

func installAuthPlugin(router *gin.RouterGroup) {
	if config.IsLocalEnv() {
		tilog.PlainInfo("run local mode, check test header")
		router.Use(CheckAuthByTestHeader)
		return
	}

	accountClient := grpc.GetAccountProviderSvcClient()
	// Auth CheckUser
	router.Use(tigin.CheckAuthByAuth0(accountClient))
}
