package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"gitlink.org.cn/cloudream/common/pkgs/logger"
	"gitlink.org.cn/cloudream/common/pkgs/mq"
	stgglb "gitlink.org.cn/cloudream/jcs-pub/common/globals"
	coormq "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/mq/coordinator"
	hubrpc "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc/hub"
	"gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/config"
	"gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/db"
	mymq "gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/mq"
	"gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/repl"
	"gitlink.org.cn/cloudream/jcs-pub/coordinator/internal/ticktock"
)

func init() {
	var configPath string
	cmd := &cobra.Command{
		Use:   "serve",
		Short: "Start coordinator server",
		Long:  `Start coordinator server`,
		Run: func(cmd *cobra.Command, args []string) {
			serve(configPath)
		},
	}
	cmd.Flags().StringVarP(&configPath, "config", "c", "", "Path to config file")
	RootCmd.AddCommand(cmd)
}

func serve(configPath string) {
	err := config.Init(configPath)
	if err != nil {
		fmt.Printf("init config failed, err: %s", err.Error())
		os.Exit(1)
	}

	err = logger.Init(&config.Cfg().Logger)
	if err != nil {
		fmt.Printf("init logger failed, err: %s", err.Error())
		os.Exit(1)
	}

	stgglb.InitMQPool(config.Cfg().RabbitMQ)
	stgglb.InitHubRPCPool(hubrpc.PoolConfig{})

	db2, err := db.NewDB(&config.Cfg().DB)
	if err != nil {
		logger.Fatalf("new db2 failed, err: %s", err.Error())
	}

	// 初始化系统事件发布器
	// evtPub, err := sysevent.NewPublisher(sysevent.ConfigFromMQConfig(config.Cfg().RabbitMQ), &cortypes.SourceCoordinator{})
	// if err != nil {
	// 	logger.Errorf("new sysevent publisher: %v", err)
	// 	os.Exit(1)
	// }
	// go servePublisher(evtPub)

	coorSvr, err := coormq.NewServer(mymq.NewService(db2), config.Cfg().RabbitMQ)
	if err != nil {
		logger.Fatalf("new coordinator server failed, err: %s", err.Error())
	}

	coorSvr.OnError(func(err error) {
		logger.Warnf("coordinator server err: %s", err.Error())
	})

	// 启动服务
	go serveCoorServer(coorSvr, config.Cfg().RabbitMQ)

	// 定时任务
	tktk := ticktock.New(config.Cfg().TickTock, db2)
	tktk.Start()
	defer tktk.Stop()

	// 交互式命令行
	rep := repl.New(db2, tktk)
	replCh := rep.Start()

	/// 开始监听各个模块的事件
	replEvt := replCh.Receive()
loop:
	for {
		select {
		case e := <-replEvt.Chan():
			if e.Err != nil {
				logger.Errorf("receive repl event: %v", err)
				break loop
			}

			switch e.Value.(type) {
			case repl.ExitEvent:
				logger.Info("exit by repl")
				break loop
			}
			replEvt = replCh.Receive()
		}
	}
}

// func servePublisher(evtPub *sysevent.Publisher) {
// 	logger.Info("start serving sysevent publisher")

// 	ch := evtPub.Start()

// loop:
// 	for {
// 		val, err := ch.Receive().Wait(context.Background())
// 		if err != nil {
// 			logger.Errorf("sysevent publisher stopped with error: %s", err.Error())
// 			break
// 		}

// 		switch val := val.(type) {
// 		case sysevent.PublishError:
// 			logger.Errorf("publishing event: %v", val)

// 		case sysevent.PublisherExited:
// 			if val.Err != nil {
// 				logger.Errorf("publisher exited with error: %v", val.Err)
// 			} else {
// 				logger.Info("publisher exited")
// 			}
// 			break loop

// 		case sysevent.OtherError:
// 			logger.Errorf("sysevent: %v", val)
// 		}
// 	}
// 	logger.Info("sysevent publisher stopped")

// 	// TODO 仅简单结束了程序
// 	os.Exit(1)
// }

func serveCoorServer(server *coormq.Server, cfg mq.Config) {
	logger.Info("start serving command server")

	ch := server.Start(cfg)
	if ch == nil {
		logger.Errorf("RabbitMQ logEvent is nil")
		os.Exit(1)
	}

loop:
	for {
		val, err := ch.Receive()
		if err != nil {
			logger.Errorf("command server stopped with error: %s", err.Error())
			break
		}

		switch val := val.(type) {
		case error:
			logger.Errorf("rabbitmq connect with error: %v", val)
		case mq.ServerExit:
			if val.Error != nil {
				logger.Errorf("rabbitmq server exit with error: %v", val.Error)
			} else {
				logger.Info("rabbitmq server exit")
			}
			break loop
		}
	}
	logger.Info("command server stopped")

	// TODO 仅简单结束了程序
	os.Exit(1)
}
