package config

import (
	"cicv-data-closedloop/aarch64/pjisuv/common/config"
	"cicv-data-closedloop/common/config/c_log"
	"cicv-data-closedloop/common/util"
	"cicv-data-closedloop/pjisuv_msgs"
	entity "cicv-data-closedloop/pjisuv_param"
	"github.com/bluenviron/goroslib/v2/pkg/msgs/geometry_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/tf2_msgs"
	"github.com/bluenviron/goroslib/v2/pkg/msgs/visualization_msgs"
	"plugin"
)

func InitTriggerConfig() {
	triggerLocalPathsMapTriggerId := make(map[string]string)
	c_log.GlobalLogger.Info("主节点加载触发器插件 - 开始。")
	// 1 获取数采任务的触发器列表
	cloudTriggers := &config.PlatformConfig.TaskTriggers
	// 2 获取本地触发器列表（触发器目录的一级子目录为【触发器ID_触发器Label】）
	localTriggerIds := util.GetFirstLevelSubdirectories(config.CloudConfig.TriggersDir)
	// 3 对比触发器列表，本地没有的则下载
	for _, trigger := range *cloudTriggers {
		id := util.ToString(trigger.TriggerId)
		hasIdDir, _ := util.ContainsElement(localTriggerIds, id)
		triggerLocalDir := config.CloudConfig.TriggersDir + id + "/"
		hasLabelSo, soPaths := util.CheckSoFilesInDirectory(triggerLocalDir)
		var triggerLocalPath string
		if hasIdDir && hasLabelSo { // 已存在的触发器不需要再次下载
			triggerLocalPath = soPaths[0]
			c_log.GlobalLogger.Info("触发器插件 ", triggerLocalPath, " 存在。")
			triggerLocalPathsMapTriggerId[triggerLocalPath] = id
			continue
		}
		label := util.GetFileNameWithoutExtension(config.CloudConfig.TriggersDir + trigger.TriggerScriptPath)
		triggerLocalPath = config.CloudConfig.TriggersDir + id + "/" + label + ".so"
		c_log.GlobalLogger.Info("下载触发器插件从 ", trigger.TriggerScriptPath, " 到 ", triggerLocalPath)
		config.OssMutex.Lock()
		_ = util.CreateParentDir(triggerLocalPath)
		err := config.OssBucket.GetObjectToFile(trigger.TriggerScriptPath, triggerLocalPath)
		config.OssMutex.Unlock()
		if err != nil {
			c_log.GlobalLogger.Error("下载 OSS 上的触发器插件失败：", err)
			continue
		}
		triggerLocalPathsMapTriggerId[triggerLocalPath] = id
	}

	success := 0
	// 加载所有触发器的文件
	for triggerLocalPath, triggerId := range triggerLocalPathsMapTriggerId {
		// 载入插件到数组
		open, err := plugin.Open(triggerLocalPath)
		if err != nil {
			c_log.GlobalLogger.Error("加载本地插件", triggerLocalPath, "失败。", err)
			continue
		}
		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
		}

		if TopicOfCicvExtend == topic2 { // 自定义扩展
			f, ok := rule.(func(param entity.PjisuvParam) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(param entity.ExtendParam):", err)
				continue
			}
			RuleOfCicvExtend = append(RuleOfCicvExtend, f)
		} else if TopicOfAmrPose == topic2 { //1
			f, ok := rule.(func(data *visualization_msgs.MarkerArray) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *visualization_msgs.MarkerArray) string):", err)
				continue
			}
			RuleOfAmrPose = append(RuleOfAmrPose, f)
		} else if TopicOfBoundingBoxesFast == topic2 { //2
			f, ok := rule.(func(data *pjisuv_msgs.BoundingBoxArray) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.BoundingBoxArray) string):", err)
				continue
			}
			RuleOfBoundingBoxesFast = append(RuleOfBoundingBoxesFast, f)
		} else if TopicOfCameraFault == topic2 { //3
			f, ok := rule.(func(data *pjisuv_msgs.FaultVec) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.FaultVec) string):", err)
				continue
			}
			RuleOfCameraFault = append(RuleOfCameraFault, f)
		} else if TopicOfCanData == topic2 { //4
			f, ok := rule.(func(data *pjisuv_msgs.Frame) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.Frame) string):", err)
				continue
			}
			RuleOfCanData = append(RuleOfCanData, f)
		} else if TopicOfCh128x1LslidarPointCloud == topic2 { //5
			f, ok := rule.(func(data *sensor_msgs.PointCloud2) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.PointCloud2) string):", err)
				continue
			}
			RuleOfCh128x1LslidarPointCloud = append(RuleOfCh128x1LslidarPointCloud, f)
		} else if TopicOfCh64wLLslidarPointCloud == topic2 { //6
			f, ok := rule.(func(data *sensor_msgs.PointCloud2) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.PointCloud2) string):", err)
				continue
			}
			RuleOfCh64wLLslidarPointCloud = append(RuleOfCh64wLLslidarPointCloud, f)
		} else if TopicOfCh64wLScan == topic2 { //7
			f, ok := rule.(func(data *sensor_msgs.LaserScan) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.LaserScan) string):", err)
				continue
			}
			RuleOfCh64wLScan = append(RuleOfCh64wLScan, f)
		} else if TopicOfCh64wRLslidarPointCloud == topic2 { //8
			f, ok := rule.(func(data *sensor_msgs.PointCloud2) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.PointCloud2) string):", err)
				continue
			}
			RuleOfCh64wRLslidarPointCloud = append(RuleOfCh64wRLslidarPointCloud, f)
		} else if TopicOfCh64wRScan == topic2 { //9
			f, ok := rule.(func(data *sensor_msgs.LaserScan) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.LaserScan) string):", err)
				continue
			}
			RuleOfCh64wRScan = append(RuleOfCh64wRScan, f)
		} else if TopicOfCicvLidarclusterMovingObjects == topic2 { //10
			f, ok := rule.(func(data *pjisuv_msgs.PerceptionCicvMovingObjects) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.PerceptionCicvMovingObjects) string):", err)
				continue
			}
			RuleOfCicvLidarclusterMovingObjects = append(RuleOfCicvLidarclusterMovingObjects, f)
		} else if TopicOfCicvAmrTrajectory == topic2 { //11
			f, ok := rule.(func(data *pjisuv_msgs.Trajectory, param entity.PjisuvParam) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.Trajectory,param entity.PjisuvParam) string):", err)
				continue
			}
			RuleOfCicvAmrTrajectory = append(RuleOfCicvAmrTrajectory, f)
		} else if TopicOfCicvLocation == topic2 { //12
			f, ok := rule.(func(data *pjisuv_msgs.PerceptionLocalization) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.PerceptionLocalization) string):", err)
				continue
			}
			RuleOfCicvLocation = append(RuleOfCicvLocation, f)
		} else if TopicOfCloudClusters == topic2 { //13
			f, ok := rule.(func(data *pjisuv_msgs.AutowareCloudClusterArray) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.AutowareCloudClusterArray) string):", err)
				continue
			}
			RuleOfCloudClusters = append(RuleOfCloudClusters, f)
		} else if TopicOfHeartbeatInfo == topic2 { //14
			f, ok := rule.(func(data *pjisuv_msgs.HeartBeatInfo) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.HeartBeatInfo) string):", err)
				continue
			}
			RuleOfHeartbeatInfo = append(RuleOfHeartbeatInfo, f)
		} else if TopicOfLidarPretreatmentCost == topic2 { //15
			f, ok := rule.(func(data *geometry_msgs.Vector3Stamped) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *geometry_msgs.Vector3Stamped) string):", err)
				continue
			}
			RuleOfLidarPretreatmentCost = append(RuleOfLidarPretreatmentCost, f)
		} else if TopicOfLidarPretreatmentOdometry == topic2 { //16
			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
			}
			RuleOfLidarPretreatmentOdometry = append(RuleOfLidarPretreatmentOdometry, f)
		} else if TopicOfLidarRoi == topic2 { //17
			f, ok := rule.(func(data *geometry_msgs.PolygonStamped) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *geometry_msgs.PolygonStamped) string):", err)
				continue
			}
			RuleOfLidarRoi = append(RuleOfLidarRoi, f)
		} else if TopicOfLine1 == topic2 { //18
			f, ok := rule.(func(data *nav_msgs.Path) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *nav_msgs.Path) string):", err)
				continue
			}
			RuleOfLine1 = append(RuleOfLine1, f)
		} else if TopicOfLine2 == topic2 { //19
			f, ok := rule.(func(data *nav_msgs.Path) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *nav_msgs.Path) string):", err)
				continue
			}
			RuleOfLine2 = append(RuleOfLine2, f)
		} else if TopicOfMapPolygon == topic2 { //20
			f, ok := rule.(func(data *pjisuv_msgs.PolygonStamped) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.PolygonStamped) string):", err)
				continue
			}
			RuleOfMapPolygon = append(RuleOfMapPolygon, f)
		} else if TopicOfObstacleDisplay == topic2 { //21
			f, ok := rule.(func(data *visualization_msgs.MarkerArray) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *visualization_msgs.MarkerArray) string):", err)
				continue
			}
			RuleOfObstacleDisplay = append(RuleOfObstacleDisplay, f)
		} else if TopicOfPjControlPub == topic2 { //22
			f, ok := rule.(func(data *pjisuv_msgs.CommonVehicleCmd) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.CommonVehicleCmd) string):", err)
				continue
			}
			RuleOfPjControlPub = append(RuleOfPjControlPub, f)
		} else if TopicOfPointsCluster == topic2 { //23
			f, ok := rule.(func(data *sensor_msgs.PointCloud2) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.PointCloud2) string):", err)
				continue
			}
			RuleOfPointsCluster = append(RuleOfPointsCluster, f)
		} else if TopicOfPointsConcat == topic2 { //24
			f, ok := rule.(func(data *sensor_msgs.PointCloud2) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.PointCloud2) string):", err)
				continue
			}
			RuleOfPointsConcat = append(RuleOfPointsConcat, f)
		} else if TopicOfReferenceDisplay == topic2 { //25
			f, ok := rule.(func(data *nav_msgs.Path) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *nav_msgs.Path) string):", err)
				continue
			}
			RuleOfReferenceDisplay = append(RuleOfReferenceDisplay, f)
		} else if TopicOfReferenceTrajectory == topic2 { //26
			f, ok := rule.(func(data *pjisuv_msgs.Trajectory) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.Trajectory) string):", err)
				continue
			}
			RuleOfReferenceTrajectory = append(RuleOfReferenceTrajectory, f)
		} else if TopicOfRoiPoints == topic2 { //27
			f, ok := rule.(func(data *sensor_msgs.PointCloud2) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.PointCloud2) string):", err)
				continue
			}
			RuleOfRoiPoints = append(RuleOfRoiPoints, f)
		} else if TopicOfRoiPolygon == topic2 { //28
			f, ok := rule.(func(data *nav_msgs.Path) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *nav_msgs.Path) string):", err)
				continue
			}
			RuleOfRoiPolygon = append(RuleOfRoiPolygon, f)
		} else if TopicOfTf == topic2 { //29
			f, ok := rule.(func(data *tf2_msgs.TFMessage) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *tf2_msgs.TFMessage) string):", err)
				continue
			}
			RuleOfTf = append(RuleOfTf, f)
		} else if TopicOfTpperception == topic2 { //30
			f, ok := rule.(func(data *pjisuv_msgs.PerceptionObjects, param entity.PjisuvParam) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.PerceptionObjects, param entity.ExtendParam) string):", err)
				continue
			}
			RuleOfTpperception = append(RuleOfTpperception, f)
		} else if TopicOfTpperceptionVis == topic2 { //31
			f, ok := rule.(func(data *visualization_msgs.MarkerArray) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *visualization_msgs.MarkerArray) string):", err)
				continue
			}
			RuleOfTpperceptionVis = append(RuleOfTpperceptionVis, f)
		} else if TopicOfTprouteplan == topic2 { //32
			f, ok := rule.(func(data *pjisuv_msgs.RoutePlan) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.RoutePlan) string):", err)
				continue
			}
			RuleOfTprouteplan = append(RuleOfTprouteplan, f)
		} else if TopicOfTrajectoryDisplay == topic2 { //33
			f, ok := rule.(func(data *nav_msgs.Path) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *nav_msgs.Path) string):", err)
				continue
			}
			RuleOfTrajectoryDisplay = append(RuleOfTrajectoryDisplay, f)
		} else if TopicOfUngroundCloudpoints == topic2 { //34
			f, ok := rule.(func(data *sensor_msgs.PointCloud2) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.PointCloud2) string):", err)
				continue
			}
			RuleOfUngroundCloudpoints = append(RuleOfUngroundCloudpoints, f)
		} else if TopicOfCameraImage == topic2 { //35
			f, ok := rule.(func(data *sensor_msgs.Image) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *sensor_msgs.Image) string):", err)
				continue
			}
			RuleOfCameraImage = append(RuleOfCameraImage, f)
		} else if TopicOfDataRead == topic2 { //36
			f, ok := rule.(func(data *pjisuv_msgs.Retrieval) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.Retrieval) string):", err)
				continue
			}
			RuleOfDataRead = append(RuleOfDataRead, f)
		} else if TopicOfPjVehicleFdbPub == topic2 { //39
			f, ok := rule.(func(data *pjisuv_msgs.VehicleFdb, param *entity.PjisuvParam) string)
			if ok != true {
				c_log.GlobalLogger.Error("插件", triggerLocalPath, "中的Topic方法必须是(func(data *pjisuv_msgs.VehicleFdb) string):", err)
				continue
			}
			RuleOfPjVehicleFdbPub = append(RuleOfPjVehicleFdbPub, f)
		} else {
			c_log.GlobalLogger.Error("未知的topic：", topic2)
			continue
		}

		label, err := open.Lookup("Label")
		if err != nil {
			c_log.GlobalLogger.Error("加载本地插件 ", triggerLocalPath, " 中的 Label 方法失败。", err)
			continue
		}
		labelFunc := label.(func() string)
		labelString := labelFunc()
		LabelMapTriggerId.Store(labelString, triggerId)
		success++
	}
	c_log.GlobalLogger.Info("一共应加载", len(config.PlatformConfig.TaskTriggers), "个触发器，实际加载 ", success, " 个触发器。")
}
