package app

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
	"go.uber.org/dig"

	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/apiserver"
	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/apiserver/middlewares"
	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/logger"
	"github.com/tidbcloud/aisupport/services/jsm-syncer/config"
)

const (
	APIRoutePath apiserver.RoutePath = "/api/v1/jsm-syncer"
)

type HandlerResult struct {
	dig.Out

	Handler apiserver.Handler `group:"apiHandlers"`
}

type APIServerParam struct {
	dig.In

	Config   *config.RootConfig
	Handlers []apiserver.Handler `group:"apiHandlers"`
}

func NewAPIServer(param APIServerParam) (*apiserver.APIServer, error) {
	logger := logger.Logger.WithName("APIServer")

	return apiserver.NewAPIServer(apiserver.APIServerParam{
		Address: param.Config.APIServer.Address,
		RoutePaths: []apiserver.RoutePath{
			APIRoutePath,
		},
		Logger:   logger,
		Handlers: param.Handlers,
		PreInitRoute: func(root gin.IRouter) error {
			logMW := middlewares.LogMetricMiddlewareBuilder{
				Request: middlewares.RequestLoggerOptions{
					Logger: logger,
					FilterFunc: func(c *gin.Context) bool {
						if c.Request.Method == http.MethodOptions {
							return true
						}
						return c.FullPath() == "/healthz" || c.FullPath() == "/metrics"
					},
				},
			}

			root.Use(
				otelgin.Middleware("jsm-syncer"),
				logMW.Build(),
				middlewares.RecoveryMiddleware(logger),
				middlewares.CorsMiddleware(),
			)
			root.GET("/healthz", gin.WrapF(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) }))
			root.GET("/metrics", gin.WrapH(promhttp.Handler()))
			return nil
		},
	})
}
