package app

import (
	"fmt"
	"os"

	"github.com/pingcap/log"
	"github.com/spf13/cobra"
	"github.com/tidbcloud/serverless-service/internal/config"
	"github.com/tidbcloud/serverless-service/pkg/version"
	"go.uber.org/zap"
)

const defaultConfigPath = "/etc/serverless-service/config.yaml"

var (
	cfgFile string

	rootCmd = &cobra.Command{
		Use:               "serverless-service",
		Version:           version.Info(),
		CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
	}

	serveCmd = &cobra.Command{
		Use:   "http",
		Short: "serve as a http server",
		Run: func(cmd *cobra.Command, args []string) {
			config.SetWorkMode(config.WorkModeHttpServer)
			s := NewServer()
			if err := s.Setup(); err != nil {
				log.Fatal("failed to setup", zap.Error(err))
			}
			serveErr := s.ServeHTTP()
			if serveErr != nil {
				log.Fatal("failed to serve HTTP server", zap.Error(serveErr))
			}
			log.Info("HTTP server exits now")
		},
	}
	grpcServerCmd = &cobra.Command{
		Use:   "grpc",
		Short: "serve as a grpc server",
		Run: func(cmd *cobra.Command, args []string) {
			config.SetWorkMode(config.WorkModeGrpcServer)
			s := NewServer()
			if err := s.Setup(); err != nil {
				log.Fatal("failed to setup", zap.Error(err))
			}
			serveErr := s.ServeGRPC()
			if serveErr != nil {
				log.Fatal("failed to serve GRPC server", zap.Error(serveErr))
			}
			log.Info("GRPC server exits now")
		},
	}

	workerCmd = &cobra.Command{
		Use:   "worker",
		Short: "run background workers",
		Run: func(cmd *cobra.Command, args []string) {
			config.SetWorkMode(config.WorkModeWorker)
			s := NewServer()
			if err := s.Setup(); err != nil {
				log.Fatal("failed to setup", zap.Error(err))
			}
			s.RunWorkers()
			log.Info("workers run in background now")

			runMetricsServer()
			log.Info("workers exits now")
		},
	}

	brWorkerCmd = &cobra.Command{
		Use:   "brworker",
		Short: "run backup&restore workers",
		Run: func(cmd *cobra.Command, args []string) {
			config.SetWorkMode(config.WorkModeBRWorker)
			s := NewServer()
			if err := s.Setup(); err != nil {
				log.Fatal("failed to setup", zap.Error(err))
			}
			s.RunBRWorkers()
			log.Info("br workers run in background now")

			runMetricsServer()
			log.Info("br workers exits now")
		},
	}

	workflowCmd = &cobra.Command{
		Use:   "workflow",
		Short: "run the FastFlow workflow executor (CDC newarch DAGs)",
		Run: func(cmd *cobra.Command, args []string) {
			config.SetWorkMode(config.WorkModeWorkflow)
			s := NewServer()
			if err := s.Setup(); err != nil {
				log.Fatal("failed to setup", zap.Error(err))
			}
			s.RunWorkflow()
			log.Info("workflow executor started")

			runMetricsServer()
			log.Info("workflow exits now")
		},
	}
)

func initGlobalConfig() {
	cobra.CheckErr(config.InitConfig(cfgFile, true))
}

func init() {
	cobra.OnInitialize(initGlobalConfig)
	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", defaultConfigPath, "config file")
	rootCmd.AddCommand(serveCmd)
	rootCmd.AddCommand(grpcServerCmd)
	rootCmd.AddCommand(workerCmd)
	rootCmd.AddCommand(brWorkerCmd)
	rootCmd.AddCommand(workflowCmd)
}

func Execute() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
