package config

import (
	"cicv-data-closedloop/aarch64/pji/common/config"
	"cicv-data-closedloop/common/config/c_log"
	"cicv-data-closedloop/common/util"
	"cicv-data-closedloop/pji_msgs"
	"github.com/bluenviron/goroslib/v2/pkg/msgs/diagnostic_msgs"
	"github.com/bluenviron/goroslib/v2/pkg/msgs/nav_msgs"
	"github.com/bluenviron/goroslib/v2/pkg/msgs/sensor_msgs"
	"github.com/bluenviron/goroslib/v2/pkg/msgs/std_msgs"
	"plugin"
	"strconv"
)

var (
	LabelMapTriggerId = make(map[string]string)

	// 1
	TopicOfDiagnostics = "/diagnostics"
	RuleOfDiagnostics  []func(data *diagnostic_msgs.DiagnosticArray) string
	// 2
	TopicOfImu = "/imu"
	RuleOfImu  []func(data *sensor_msgs.Imu) string
	// 3
	TopicOfLocateInfo = "/locate_info"
	RuleOfLocateInfo  []func(data *pji_msgs.LocateInfo) string
	// 4
	TopicOfObstacleDetection = "/obstacle_detection"
	RuleOfObstacleDetection  []func(data *std_msgs.UInt8) string
	// 5
	TopicOfOdom = "/odom"
	RuleOfOdom  []func(data *nav_msgs.Odometry) string
	// 6
	TopicOfSysInfo = "/sys_info"
	RuleOfSysInfo  []func(data *pji_msgs.SysInfo) string
)

func InitTriggerConfig() {
	loadSuccess := 0
	// 下载所有触发器的文件
	for _, trigger := range config.PlatformConfig.TaskTriggers {
		// 下载
		triggerLocalPath := config.CloudConfig.TriggersDir + trigger.TriggerScriptPath
		_ = util.CreateParentDir(triggerLocalPath)
		c_log.GlobalLogger.Info("下载触发器插件从", trigger.TriggerScriptPath, "到", triggerLocalPath)
		config.OssMutex.Lock()
		err := config.OssBucket.GetObjectToFile(trigger.TriggerScriptPath, triggerLocalPath)
		config.OssMutex.Unlock()
		if err != nil {
			c_log.GlobalLogger.Errorf("下载oss上的触发器插件失败【%v】->【%v】:%v", trigger.TriggerScriptPath, triggerLocalPath, err)
			continue
		}
		// 载入插件到数组
		open, err := plugin.Open(triggerLocalPath)
		if err != nil {
			c_log.GlobalLogger.Error("加载本地插件", triggerLocalPath, "失败。", err)
		}
		topic0, err := open.Lookup("Topic")
		if err != nil {
			c_log.GlobalLogger.Error("加载本地插件", triggerLocalPath, "中的Topic方法失败。", err)
			continue
		}
		topic1, ok := topic0.(func() string)
		if ok != true {
			c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func() string):", err)
			continue
		}
		topic2 := topic1()
		rule, err := open.Lookup("Rule")
		if err != nil {
			c_log.GlobalLogger.Error("加载本地插件", triggerLocalPath, "中的Rule方法失败。", err)
			continue
		}
		// 判断topic
		// todo 如果是未知的topic，可以添加一个循环，更新平台配置，同理金龙车和多功能车
		if TopicOfDiagnostics == topic2 { // 1
			f, ok := rule.(func(*diagnostic_msgs.DiagnosticArray) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *diagnostic_msgs.DiagnosticArray) string):", err)
				continue
			}
			RuleOfDiagnostics = append(RuleOfDiagnostics, f)
		} else if TopicOfImu == topic2 { // 2
			f, ok := rule.(func(data *sensor_msgs.Imu) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.Imu) string):", err)
				continue
			}
			RuleOfImu = append(RuleOfImu, f)
		} else if TopicOfLocateInfo == topic2 { // 3
			f, ok := rule.(func(data *pji_msgs.LocateInfo) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pji_msgs.LocateInfo) string):", err)
				continue
			}
			RuleOfLocateInfo = append(RuleOfLocateInfo, f)
		} else if TopicOfObstacleDetection == topic2 { // 4
			f, ok := rule.(func(data *std_msgs.UInt8) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *std_msgs.UInt8) string):", err)
				continue
			}
			RuleOfObstacleDetection = append(RuleOfObstacleDetection, f)
		} else if TopicOfOdom == topic2 { // 5
			f, ok := rule.(func(data *nav_msgs.Odometry) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *nav_msgs.Odometry) string):", err)
				continue
			}
			RuleOfOdom = append(RuleOfOdom, f)
		} else if TopicOfSysInfo == topic2 { // 6
			f, ok := rule.(func(data *pji_msgs.SysInfo) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pji_msgs.SysInfo) string):", err)
				continue
			}
			RuleOfSysInfo = append(RuleOfSysInfo, f)
		} else {
			c_log.GlobalLogger.Error("未知的topic：", topic2)
			continue
		}

		label, err := open.Lookup("Label")
		if err != nil {
			c_log.GlobalLogger.Error("加载本地插件", triggerLocalPath, "中的TriggerName方法失败。", err)
			continue
		}
		labelFunc, ok := label.(func() string)
		if ok != true {
			c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Label方法必须是(func() string):", err)
			continue
		}
		labelString := labelFunc()
		LabelMapTriggerId[labelString] = strconv.Itoa(trigger.TriggerId)
		loadSuccess++
		c_log.GlobalLogger.Info("主节点加载触发器插件：【ros topic】=", topic2, "，【触发器label】=", labelString, "【触发器ID】=", trigger.TriggerId)
	}
	c_log.GlobalLogger.Infof("一共有%v个触发器，加载成功了%v个，【label和id映射关系】=%v", len(config.PlatformConfig.TaskTriggers), loadSuccess, LabelMapTriggerId)
}
