package main

import (
	"flag"
	"fmt"

	"github.com/getsentry/sentry-go"
	"github.com/pingcap/dbaas/admin/api"
	"github.com/pingcap/dbaas/admin/models"
	"github.com/pingcap/dbaas/central/config"
	infraapi "github.com/pingcap/dbaas/central/infra-api"
	"github.com/pingcap/errors"
	"github.com/pingcap/log"
	"github.com/tidbcloud/pkgv2/auth/auth0"
	"github.com/tidbcloud/pkgv2/zapext/zapsentry"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

const (
	defaultConfigPath = "/etc/dbaas/config.yaml"
)

var (
	configPath = flag.String("config-path", defaultConfigPath, "dbaas configuration file path")
)

func setupLogger(opts ...zap.Option) error {
	cfg := &log.Config{
		Level: config.Global().ServerConfig.LogLevel,
	}
	gl, props, err := log.InitLogger(cfg, append(opts, zap.AddStacktrace(zapcore.ErrorLevel))...)
	if err != nil {
		return errors.Trace(err)
	}
	log.ReplaceGlobals(gl, props)

	return nil
}

func setupSentry() error {
	cfg := config.Global().ServerConfig.SentryConf
	opts := sentry.ClientOptions{
		Dsn:         cfg.DSN,
		Environment: cfg.Environment,
	}
	if err := sentry.Init(opts); err != nil {
		log.Error("setupSentry failed", zap.String("dsn", cfg.DSN), zap.String("env", cfg.Environment))
		return err
	}
	return nil
}

func main() {
	flag.Parse()

	// init config
	if err := config.InitConfig(*configPath); err != nil {
		log.Fatal("Initialize configuration failed", zap.Error(err))
	}
	portalAuth0 := auth0.Conf{
		Audience:                 config.Global().Auth0Config.ManagementPortalAuth0Audience,
		Secret:                   []byte(config.Global().Auth0Config.ManagementPortalAuth0Secret),
		Domain:                   config.Global().Auth0Config.ManagementPortalAuth0Domain,
		ClientCredentialAudience: config.Global().Auth0Config.ManagementPortalAuth0ClientAudience,
	}

	// init shoot cache & database
	models.InitMySQL(false)
	if err := api.InitTokenValidator(portalAuth0); err != nil {
		log.Fatal("failed to init token validator", zap.Error(err))
	}
	// gardener cluster k8s client
	var cfg *rest.Config
	var err error
	kubeConfig := config.Global().GardenerConfig.KubeConfigPath
	if kubeConfig == "" {
		cfg, err = rest.InClusterConfig()
	} else {
		cfg, err = clientcmd.BuildConfigFromFlags("", kubeConfig)
	}
	if err != nil {
		log.Fatal("initialize the kubernetes config failed", zap.Error(err))
	}
	// Initialize the k8s/gardener clients.
	baseKubeCli, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		log.Fatal("initialize the base kubeclient failed", zap.Error(err))
	}
	infraAPI := infraapi.InitInfraAPI(baseKubeCli)
	if err := models.InitAdminModel(infraAPI); err != nil {
		log.Fatal("failed to init admin model", zap.Error(err))
	}

	if err := setupSentry(); err != nil {
		panic("setupSentry failed")
	}
	var level zapcore.Level
	if err := level.UnmarshalText([]byte(config.Global().ServerConfig.SentryConf.LogLevel)); err != nil {
		panic("invalid sentry.LogLevel")
	}
	sentryOpt := zap.WrapCore(func(core zapcore.Core) zapcore.Core {
		return zapcore.NewTee(core, zapsentry.NewCore(level, sentry.CurrentHub().Client()))
	})
	if err := setupLogger(sentryOpt); err != nil {
		panic("initialize logger failed")
	}
	// flush all buffering log
	defer func() {
		if err := log.L().Sync(); err != nil {
			fmt.Println(err.Error())
		}
	}()

	// listen and serve on 0.0.0.0:8080 by default
	r := api.InitRouter()
	log.Fatal("failed to start admin server", zap.Error(r.Run(config.Global().ServerConfig.AdminListenAddr)))
}
