package main

import (
	"context"
	"os"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/log"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/collectors"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/tidbcloud/tiflash-manager/pkg/config"
	"github.com/tidbcloud/tiflash-manager/pkg/core"
	"github.com/tidbcloud/tiflash-manager/pkg/handler"
	"github.com/tidbcloud/tiflash-manager/pkg/handler/middleware"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	log.SetLevel(fromEnv("LOG_LEVEL"))
	log.Info("Starting tiflash-autoscale manager server")

	conf := config.Parsed()
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	pools := core.NewPools(conf)
	reconciler := core.NewPoolReconciler(conf)
	tenantsPool := core.NewTenantsPool(conf, pools, reconciler)

	managerServer := handler.NewServer(ctx, conf, pools, tenantsPool)

	pools.Setup(ctx)
	tenantsPool.Setup(ctx)

	// prometheus registry and collectors
	// to collect Go runtime metrics and process metrics
	registry := prometheus.NewRegistry()
	registry.MustRegister(
		collectors.NewGoCollector(),
		collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
	)

	r := gin.Default()
	r.Use(middleware.PrometheusMiddleware())

	r.GET("/metrics", gin.WrapH(promhttp.Handler()))

	r.GET("/v1/cluster", func(c *gin.Context) {
		managerServer.GetCluster(c.Writer, c.Request)
	})
	r.GET("/v1/clusters", func(c *gin.Context) {
		managerServer.DumpClusters(c.Writer, c.Request)
	})
	r.GET("/resume-and-get-topology", func(c *gin.Context) {
		managerServer.GetTopology(c.Writer, c.Request)
	})
	r.GET("/healthz", func(c *gin.Context) {
		managerServer.Healthz(c.Writer, c.Request)
	})

	log.Info("Setting up server", zap.Uint("port", conf.HttpPort))
	if err := r.Run(":" + strconv.FormatInt(int64(conf.HttpPort), 10)); err != nil {
		log.Fatal("Can not start server: ", zap.String("error", err.Error()))
	}
}

func fromEnv(s string) zapcore.Level {
	value, ok := os.LookupEnv(s)
	if !ok {
		return zapcore.InfoLevel
	}

	switch value {
	case "debug":
		return zap.DebugLevel
	case "info":
		return zap.InfoLevel
	case "warn":
		return zap.WarnLevel
	case "error":
		return zap.ErrorLevel
	case "dpanic":
		return zap.DPanicLevel
	case "panic":
		return zap.PanicLevel
	case "fatal":
		return zap.FatalLevel
	default:
		log.Warn("Unknown log level, using default info level", zap.String("level", value))
		return zap.InfoLevel
	}
}
