package service

import (
	"cicv-data-closedloop/aarch64/pji/common/config"
	"cicv-data-closedloop/common/config/c_log"
	"cicv-data-closedloop/common/util"
	"github.com/bluenviron/goroslib/v2"
	"os"
	"os/exec"
	"time"
)

// BagRecord 打包rosbag
func BagRecord(nodeName string) {
	var err error
	c_log.GlobalLogger.Info("rosbag record goroutine - 启动")
	for {
		c_log.GlobalLogger.Info("校验必需的 rosnode 是否全部启动。")
		canRecord := false
		for !canRecord {
			time.Sleep(time.Duration(2) * time.Second)
			canRecord = isCanRecord(config.RosNode)
		}
		c_log.GlobalLogger.Info("rosnode 启动完成，正在启动 rosbag record 命令。")

		var command []string
		command = append(command, "record")
		command = append(command, "--split")
		command = append(command, "--duration=1")
		for _, host := range config.CloudConfig.Hosts {
			if host.Name == nodeName {
				for _, topic := range host.Topics {
					command = append(command, topic)
				}
			}
		}

		// 2 ------- 调用 rosbag 打包命令，该命令自动阻塞 -------
		// 不在此处压缩，因为 rosbag filter 时会报错。在上传到oss之前压缩即可。
		// 包名格式：2023-11-15-17-35-20_0.bag
		_ = util.CreateParentDir(config.CloudConfig.BagDataDir)
		var recordProcessPid int
		var recordSubProcessPid int
		var cmd *exec.Cmd
		systemEnv := os.Environ()
		c_log.GlobalLogger.Info("系统环境变量为：", systemEnv)
	parent:
		for {
			c_log.GlobalLogger.Info("record 环境变量为：", config.RosbagEnvs)
			cmd, err = util.ExecuteWithEnvAndDirAsync(config.RosbagEnvs, config.CloudConfig.BagDataDir, config.RosbagPath, command...)
			if err != nil {
				c_log.GlobalLogger.Error("执行record命令", command, "出错：", err)
				continue
			}
			recordProcessPid = cmd.Process.Pid
		sub:
			for {
				time.Sleep(time.Duration(2) * time.Second)
				process, err := os.FindProcess(recordProcessPid)
				if process == nil {
					continue parent
				}
				recordSubProcessPid, err = util.GetSubProcessPid(recordProcessPid)
				if err != nil {
					c_log.GlobalLogger.Info("正在等待获取进程 ", recordProcessPid, " 的子进程的pid。")
					continue sub
				}
				if recordSubProcessPid != 0 {
					c_log.GlobalLogger.Info("获取进程 ", recordProcessPid, " 的子进程的pid：", recordSubProcessPid)
					break parent
				}
			}
		}
		// 等待自杀信号
		c_log.GlobalLogger.Info("启动record命令成功。等待自杀信号。")
		select {
		case signal := <-ChannelKillRosRecord:
			if signal == 1 {
				if err := util.KillProcessByPid(recordSubProcessPid); err != nil {
					c_log.GlobalLogger.Errorf("程序阻塞，杀死record命令子进程出错，【pid】=%v,【err】=%v。", recordSubProcessPid, err)
					select {} // 此处阻塞防止record命令一直录包占满存储
				}
				if err = cmd.Process.Kill(); err != nil {
					c_log.GlobalLogger.Error("程序阻塞，杀死record命令进程", recordProcessPid, "出错：", err)
					select {} // 此处阻塞防止record命令一直录包占满存储
				}
				AddKillTimes("1")
				return
			}
		}

		// TODO 暂时不放开该逻辑。如果监控rosnode来判断是否杀死record，太麻烦，生成窗口的线程也需要关闭
		//{
		//	commonCfg.GlobalLogger.Info("正在监控rosnode是否全部关闭。")
		//	for canRecord {
		//		time.Sleep(time.Duration(1) * time.Second)
		//		canRecord = isCanRecord(commonCfg.RosNode)
		//	}
		//	commonCfg.GlobalLogger.Info("rosnode已全部关闭，正在结束record进程。")
		//
		//	err = cmd.Process.Kill()
		//	if err != nil {
		//		commonCfg.GlobalLogger.Error("杀死record进程错误：", err)
		//		continue
		//	}
		//}
	}
}

func isCanRecord(n *goroslib.Node) bool {
	time.Sleep(time.Duration(1) * time.Second)
	// 获取
	nodes, err := n.MasterGetNodes()
	if err != nil {
		c_log.GlobalLogger.Error("获取rosnode出错：", err)
		return false
	}
	// 创建一个示例的map
	myMap := nodes
	// 创建一个切片，包含要检查的元素
	mySlice := config.CloudConfig.Ros.Nodes

	// 判断map的键是否包含切片中的所有元素
	for _, element := range mySlice {
		if _, ok := myMap[element]; !ok {
			c_log.GlobalLogger.Info("rosnode：", element, " 未启动，需等待启动后才可启动record。")
			return false
		}
	}
	return true
}
