package main

import (
	"context"
	"flag"
	"fmt"
	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	"github.com/tidbcloud/debug_portal/db"
	http_gateway "github.com/tidbcloud/debug_portal/grpc/http"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/debug_portal/pkg/centralgw"
	"go.uber.org/zap"
	"google.golang.org/grpc"

	"github.com/pingcap/log"
	"github.com/tidbcloud/debug_portal/config"
	"github.com/tidbcloud/debug_portal/model"
	"github.com/tidbcloud/debug_portal/pkg"
	"github.com/tidbcloud/debug_portal/session"

	grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
	pb "github.com/tidbcloud/debug_portal/idl/pbgen/debug_portal"
	// need to replace to shared repo
)

var (
	GitHash    = "None"
	configPath = ""
)

const (
	httpPort          = 8080
	gRPCPort          = 9191
	defaultConfigPath = "/etc/dbaas/config.yaml"
)

func init() {
	flag.StringVar(&configPath, "config-path", defaultConfigPath, "debug configuration file path")
	flag.Parse()
	/* just personal env test.
	cfg := config.MysqlConfig{
		Host:     "127.0.0.1",
		User:     "root",
		Port:     3306,
		Password: "12345678",
		Database: "dbaas",
	}

	_, err := db.InitializeWithoutMigrate(cfg)
	if err != nil {
		panic(err)
	}
	*/
}

func main() {
	var err error
	err = config.InitConfig(configPath)
	if err != nil {
		log.Fatal("Initialize configuration failed", zap.Error(err))
	}

	_, err = db.InitializeWithoutMigrate(config.Global().MysqlConfig)
	if err != nil {
		panic(err)
	}
	err = centralgw.Run(getDebugPortalServer, getDebugPortalGateway, httpPort, gRPCPort)
	panic(err)
}

// configureServer is an opinionated common configuration for a grpc Server.
func configureServer() *grpc.Server {
	/* TODO: run the closer
	   tracer, _ := tracing.InitJaeger(service)
	*/

	return grpc.NewServer(
		grpc.UnaryInterceptor(
			grpc_middleware.ChainUnaryServer(
				http_gateway.UnaryServerInterceptor(),
				grpc_recovery.UnaryServerInterceptor(),
			),
		),
		grpc.StreamInterceptor(
			grpc_middleware.ChainStreamServer(
				http_gateway.StreamServerInterceptor(),
				grpc_recovery.StreamServerInterceptor(),
			),
		),
	)
}

func getDebugPortalServer() (server *grpc.Server, err error) {
	server = configureServer()
	grafanaConfig := config.Global().GrafanaConfig
	grafanaClient := model.NewGrafranaClient(grafanaConfig.Server, grafanaConfig.APIKey, http.DefaultClient)
	debugModel := model.NewModel(log.L(), grafanaClient)
	centralService := pkg.New()
	debugSessionManager := session.NewSessionManager(&config.Global().SessionConfig)
	debugPortalService := pkg.NewService(centralService, debugModel, &config.Global().DebugPortalConfig, debugSessionManager)
	pb.RegisterCentralDebugPortalServiceServer(server, debugPortalService)
	return server, nil
}

func getDebugPortalGateway() (r *gin.Engine, err error) {
	mux := http_gateway.MakeGatewayMux()
	opts := []grpc.DialOption{grpc.WithInsecure()}
	grpcServerEndpoint := fmt.Sprintf("localhost:%d", gRPCPort)

	if err := pb.RegisterCentralDebugPortalServiceHandlerFromEndpoint(context.Background(), mux, grpcServerEndpoint, opts); err != nil {
		return nil, err
	}

	r = gin.Default()
	r.Use(func(c *gin.Context) {
		c.Writer.Header().Set("SameSite", "disabled")
	})

	r.Any("/debug-api/v1/*any", gin.WrapH(Handler(http_gateway.DebugAPICors.Handler(mux))))
	//r.GET("/debug-api/v1/orgs/:org_id/clusters", func(c *gin.Context) {
	//	c.JSON(200, gin.H{
	//		"message": "pong",
	//	})
	//})
	// r.StaticFile("/swagger/swagger.json", "/.swagger.json")
	return r, nil
}

func Handler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		rl := &http_gateway.ResponseLogger{W: w, Status: 200}
		h.ServeHTTP(rl, r)
	})
}
