package main

import (
	"flag"
	"log"
	"strings"

	"github.com/tidbcloud/aws-shared-provider/pkg/tidbworker"
	"github.com/tidbcloud/aws-shared-provider/pkg/tidbworker/server"
	"k8s.io/client-go/tools/clientcmd"
	ctrl "sigs.k8s.io/controller-runtime"
)

var (
	namespace                        string
	pdAddr                           string
	dsn                              string
	enableLeaderElection             bool
	enableGcV1                       bool
	gcV1JobLimit                     int
	enableGcV2                       bool
	gcV2JobLimit                     int
	enableBgTask                     bool
	enableTTLTask                    bool
	ttlJobLimit                      int
	batchWorkerCount                 int
	batchJobLimit                    int
	ddlWorkerCount                   int
	ddlJobLimit                      int
	importIntoWorkerCount            int
	importIntoJobLimit               int
	enableRemoteQuery                bool
	enableAutoAnalyze                bool
	autoAnalyzeLimit                 int
	enableWorkerAutoScale            bool
	disableBatchWorkerAutoScale      bool
	disableDDLWorkerAutoScale        bool
	disableImportIntoWorkerAutoScale bool
	maxSharedWorkerCount             int
	maxSharedWorkerCountPerKeyspace  int
	bgTaskNodeGroup                  string
	enableSharedWorkerForAutoAnalyze bool
	key                              string
	cert                             string
	cacert                           string
	workerCertSecret                 string
	apiServerAddr                    string
	metricBindAddr                   string

	// Resource Manager Configs
	enableResourceManager     bool
	testRMKeyspaces           string
	enableTTLResourceManager  bool
	enableGCResourceManager   bool
	enableGCV2ResourceManager bool
)

func init() {
	flag.StringVar(&namespace, "namespace", "tidb-worker", "the namespace to create tidb worker")
	flag.StringVar(&pdAddr, "pd-addr", "serverless-cluster-pd.tidb-serverless.svc:2379", "the PD addresses")
	flag.StringVar(&dsn, "dsn", "", "the DSN of the MySQL cluster")
	flag.BoolVar(&enableLeaderElection, "enable-leader-election", true, "enable leader election")
	flag.BoolVar(&enableGcV1, "enable-gc-v1", true, "if consume GC v1 tasks")
	flag.IntVar(&gcV1JobLimit, "gc-v1-job-limit", 5, "the max number of concurrent running GC v1 jobs, 0 means no limit")
	flag.BoolVar(&enableGcV2, "enable-gc-v2", true, "if consume GC v2 tasks")
	flag.IntVar(&gcV2JobLimit, "gc-v2-job-limit", 5, "the max number of concurrent running GC v2 jobs, 0 means no limit")
	flag.BoolVar(&enableBgTask, "enable-bg-task", true, "if consume background tasks")
	flag.IntVar(&batchWorkerCount, "batch-worker-count", 2, "the number of batch workers")
	flag.IntVar(&batchJobLimit, "batch-job-limit", 20, "the max number of concurrent running batch jobs, 0 means no limit")
	flag.IntVar(&ddlWorkerCount, "ddl-worker-count", 1, "the number of ddl workers")
	flag.IntVar(&ddlJobLimit, "ddl-job-limit", 20, "the max number of concurrent running ddl jobs, 0 means no limit")
	flag.IntVar(&importIntoWorkerCount, "import-into-worker-count", 1, "the number of import into workers")
	flag.IntVar(&importIntoJobLimit, "import-into-job-limit", 20, "the max number of concurrent running import into jobs, 0 means no limit") //nolint:lll // ignore
	flag.BoolVar(&enableTTLTask, "enable-ttl-task", true, "if consume ttl tasks")
	flag.IntVar(&ttlJobLimit, "ttl-job-limit", 5, "the max number of concurrent running ttl jobs, 0 means no limit")
	flag.BoolVar(&enableRemoteQuery, "enable-remote-query", true, "if enable remote query")
	flag.BoolVar(&enableAutoAnalyze, "enable-auto-analyze", true, "if enable auto analyze")
	flag.IntVar(&autoAnalyzeLimit, "auto-analyze-limit", 5, "max concurrent running auto analyze jobs, 0 means no limit")
	flag.BoolVar(&enableWorkerAutoScale, "enable-worker-autoscale", false, "if enable worker auto scale")
	flag.BoolVar(&disableBatchWorkerAutoScale, "disable-batch-worker-autoscale", false, "if disable batch worker auto scale") //nolint:lll // ignore
	flag.BoolVar(&disableDDLWorkerAutoScale, "disable-ddl-worker-autoscale", false, "if disable ddl worker auto scale")
	flag.BoolVar(&disableImportIntoWorkerAutoScale, "disable-importinto-worker-autoscale", false, "if disable import into worker auto scale") //nolint:lll // ignore
	flag.IntVar(&maxSharedWorkerCount, "max-shared-worker-count", 16, "the max number of shared workers")
	flag.IntVar(
		&maxSharedWorkerCountPerKeyspace,
		"max-shared-worker-count-per-keyspace",
		0,
		"the max number of shared workers per keyspace, 0 means use max-shared-worker-count")
	flag.StringVar(&bgTaskNodeGroup, "bgtask-node-group", "", "the node group for background task workers")
	flag.BoolVar(&enableSharedWorkerForAutoAnalyze, "enable-shared-worker-for-auto-analyze", false, "if enable shared worker for auto analyze") //nolint:lll // ignore
	flag.StringVar(&key, "key", "", "path of file that contains X509 key in PEM format")
	flag.StringVar(&cert, "cert", "", "path of file that contains X509 certificate in PEM format")
	flag.StringVar(&cacert, "cacert", "", "path of file that contains list of trusted CAs")
	flag.StringVar(&workerCertSecret, "worker-cert-secret", "", "the secret used by worker jobs")
	flag.StringVar(&apiServerAddr, "api-server-addr", ":9080", "the address of api server")
	flag.StringVar(&metricBindAddr, "metric-bind-addr", ":9191", "the address to bind metrics")
	flag.BoolVar(&enableResourceManager, "enable-resource-manager", false, "if enable resource manager and worker pool")
	flag.StringVar(&testRMKeyspaces, "test-rm-keyspaces", "", "test resource manager keyspaces")
	flag.BoolVar(&enableTTLResourceManager, "enable-ttl-resource-manager", false, "if ttl task enable resource manager")
	flag.BoolVar(&enableGCResourceManager, "enable-gc-resource-manager", false, "if gc task enable resource manager")
	flag.BoolVar(&enableGCV2ResourceManager, "enable-gcv2-resource-manager", false, "if gcv2 task enable resource manager")
}

func main() {
	flag.Parse()

	kubeConfigPath := flag.Lookup("kubeconfig").Value.String()
	kubeConfig, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath)
	if err != nil {
		log.Fatal("failed to load kubeconfig", err)
	}
	svr, err := server.New(&tidbworker.Config{
		KubeConfig:                       kubeConfig,
		Namespace:                        namespace,
		EnableLeaderElection:             enableLeaderElection,
		PDAddr:                           strings.Split(pdAddr, ","),
		DSN:                              dsn,
		EnableGcV1:                       enableGcV1,
		GcV1JobLimit:                     gcV1JobLimit,
		EnableGcV2:                       enableGcV2,
		GcV2JobLimit:                     gcV2JobLimit,
		EnableBgTask:                     enableBgTask,
		BatchWorkerCount:                 batchWorkerCount,
		BatchJobLimit:                    batchJobLimit,
		DDLWorkerCount:                   ddlWorkerCount,
		DDLJobLimit:                      ddlJobLimit,
		ImportIntoWorkerCount:            importIntoWorkerCount,
		ImportIntoJobLimit:               importIntoJobLimit,
		EnableTTLTask:                    enableTTLTask,
		TTLJobLimit:                      ttlJobLimit,
		EnableRemoteQuery:                enableRemoteQuery,
		EnableAutoAnalyze:                enableAutoAnalyze,
		AutoAnalyzeLimit:                 autoAnalyzeLimit,
		EnableWorkerAutoScale:            enableWorkerAutoScale,
		DisableBatchWorkerAutoScale:      disableBatchWorkerAutoScale,
		DisableDDLWorkerAutoScale:        disableDDLWorkerAutoScale,
		DisableImportIntoWorkerAutoScale: disableImportIntoWorkerAutoScale,
		MaxSharedWorkerCount:             maxSharedWorkerCount,
		MaxSharedWorkerCountPerKeyspace:  maxSharedWorkerCountPerKeyspace,
		BgTaskNodeGroup:                  bgTaskNodeGroup,
		EnableSharedWorkerForAutoAnalyze: enableSharedWorkerForAutoAnalyze,
		Security: tidbworker.Security{
			Key:  key,
			Cert: cert,
			CA:   cacert,
		},
		WorkerCertSecret:          workerCertSecret,
		MetricBindAddr:            metricBindAddr,
		EnableResourceManager:     enableResourceManager,
		TestRMKeyspaces:           testRMKeyspaces,
		EnableTTLResourceManager:  enableTTLResourceManager,
		EnableGCResourceManager:   enableGCResourceManager,
		EnableGCV2ResourceManager: enableGCV2ResourceManager,
	})
	if err != nil {
		log.Fatal("failed to create tidb worker", err)
	}

	if err := svr.Start(ctrl.SetupSignalHandler(), apiServerAddr); err != nil {
		log.Fatal("failed to start tidb worker", err)
	}
}
