package main

import (
	"context"
	"flag"
	"os"
	"os/signal"
	"sync"
	"syscall"

	"github.com/pingcap/log"
	"github.com/samber/lo"
	"github.com/tidbcloud/tiinf/monitor/titracing"
	"go.uber.org/zap"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"

	"github.com/tidbcloud/cluster-controller/server/pkg/config"
)

const (
	serviceName = "cluster-server"
)

func main() {
	// init config
	err := config.InitConfig(os.Args[1:])
	switch err {
	case nil:
	case flag.ErrHelp:
		os.Exit(0)
	default:
		panic(err)
	}
	cfg := config.GetConfig()

	// init logger, use pingcap/log now
	logger, props, err := log.InitLogger(&log.Config{Level: cfg.LogLevel})
	if err != nil {
		panic(err)
	}
	log.ReplaceGlobals(logger, props)
	log.Info("Starting cluster-control server...")
	defer log.Sync() // nolint: errcheck

	k8sManager, err := newK8sControllerManager(cfg.Provider, cfg.Kubeconfig)
	if err != nil {
		log.Fatal("Failed to create k8s controller manager", zap.Error(err))
	}

	// Create context that listens for the interrupt signal from the OS.
	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	// init tracing even if the tracing is currently not usable in regional, because we need to init Propagator
	// to extra some info from HTTP header.
	if _, err = titracing.InitJaeger(serviceName); err != nil {
		log.Error("init tiinf jaeger provider failed", zap.Error(err))
	}
	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		defer wg.Done()
		if err := k8sManager.Start(ctx); err != nil {
			log.Fatal("Failed to start k8s controller manager", zap.Error(err))
		}
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		if !k8sManager.GetCache().WaitForCacheSync(ctx) {
			log.Fatal("Failed to sync cache")
		}
		clusterList := cloudv1.ClusterList{}
		workflowList := cloudv1.WorkflowList{}
		configChangeList := cloudv1.ConfigChangeList{}
		lo.Must0(k8sManager.GetCache().List(ctx, &clusterList))
		lo.Must0(k8sManager.GetCache().List(ctx, &workflowList))
		lo.Must0(k8sManager.GetCache().List(ctx, &configChangeList))
		log.S().Infof("cluster-control server start, cluster counts: %d, workflow counts: %d, configChange counts: %d", len(clusterList.Items), len(workflowList.Items), len(configChangeList.Items))
		log.Info("setupAndRunGRPCServer")
		setupAndRunGRPCServer(ctx, cfg, k8sManager)
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		if !k8sManager.GetCache().WaitForCacheSync(ctx) {
			log.Fatal("Failed to sync cache")
		}
		log.Info("setupAndRunGRPCGateway")
		setupAndRunGRPCGateway(ctx, cfg.Addr, cfg.InternalGRPCAddr)
	}()

	wg.Wait()
	log.Info("cluster-control server stopped")
}
