package cmd

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

	"github.com/pingcap/errors"
	"github.com/pingcap/log"
	"github.com/spf13/cobra"
	"github.com/tidbcloud/ticdc-service/internal/server"
	"github.com/tidbcloud/ticdc-service/pkg/config"
	"github.com/tidbcloud/tiinf/monitor/titracing"
	"go.uber.org/zap"
	"k8s.io/client-go/tools/clientcmd"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

var httpServerCmd = &cobra.Command{
	Use:   "http",
	Short: "run http server to serve api requests",
	RunE: func(cmd *cobra.Command, args []string) error {
		return startAPIServer()
	},
}

func init() {
	rootCmd.AddCommand(httpServerCmd)
}

func startAPIServer() error {
	cfg, err := config.LoadConfig(cfgFile)
	if err != nil {
		return errors.Trace(err)
	}
	// init logger, use pingcap/log now
	logger, props, err := log.InitLogger(&log.Config{Level: cfg.LogLevel})
	if err != nil {
		return errors.Trace(err)
	}
	log.ReplaceGlobals(logger, props)
	log.Info("Starting ticdc-service server...")
	defer log.Sync() // nolint: errcheck

	k8sClient, err := newK8sClient(cfg.Kubeconfig)
	if err != nil {
		log.Fatal("Failed to create k8s client", zap.Error(err))
		return errors.Trace(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(server.ServiceName); err != nil {
		log.Error("init tiinf jaeger provider failed", zap.Error(err))
		return errors.Trace(err)
	}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		log.S().Infof("ticdc-service server start")
		log.Info("setupAndRunGRPCServer")
		server.SetupAndRunGRPCServer(ctx, cfg, k8sClient)
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		log.Info("setupAndRunGRPCGateway")
		server.SetupAndRunGRPCGateway(ctx, cfg.Addr, cfg.InternalGRPCAddr)
	}()

	wg.Wait()
	log.Info("ticdc-service server stopped")
	return nil
}

func newK8sClient(kubeconfigPath string) (client.Client, error) {
	restCfg, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
	if err != nil {
		return nil, errors.Trace(err)
	}
	c, err := client.New(restCfg, client.Options{
		Scheme: scheme,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return c, nil
}
