package main

import (
	"cicv-data-closedloop/pjisuv_msgs"
	"fmt"
	"math"
	"sync"
)

func Topic() string {
	return "/tpperception"
}

// 禁止存在下划线_
func Label() string {
	return "UnknownBigTargetAhead"
}

type Object struct {
	ID               uint32
	StableFrame      int
	LastExistingTime float64
}

var objectsStability = make(map[uint32]Object)

// objTypeCheck 目标物类型检测
// × 金龙车:CAR_TYPE=0, TRUCK_TYPE=1, PEDESTRIAN_TYPE=2, CYCLIST_TYPE=3, UNKNOWN_TYPE=4, UNKNOWN_MOVABLE_TYPE=5, UNKNOWN_UNMOVABLE_TYPE=6
// √ 多功能车:UNKNOWN TYPE=O, PEDESTRIAN TYPE=1, CAR TYPE=2, TRUCK TYPE=3, Bicycle TYPE=4, Tricycle TYPE=5, Traffic Cone TYPE=6
func objTypeCheck(obj *pjisuv_msgs.PerceptionObject) bool {
	const targetType uint8 = 0

	return targetType == obj.Type
}

// objSizeCheck 目标物大小检测
func objSizeCheck(obj *pjisuv_msgs.PerceptionObject) bool {
	// 多功能车
	const targetMinLength = 3.6   // m
	const targetMinWidth = 1.605  // m
	const targetMinHeight = 1.995 // m

	// 金龙车
	//targetMinLength := 5.99
	//targetMinWidth := 2.065
	//targetMinHeight := 2.82

	// 至少满足两个条件
	counter := 0
	if obj.Length >= targetMinLength {
		counter++
	}
	if obj.Width >= targetMinWidth {
		counter++
	}
	if obj.Height >= targetMinHeight {
		counter++
	}

	return counter > 1
}

// objPosCheck 判断目标物位置关系
func objPosCheck(obj *pjisuv_msgs.PerceptionObject) bool {
	const laneWidth = 3.5 // m

	return obj.X > 0 && math.Abs(float64(obj.Y)) < laneWidth*1.5
}

// isEgoStationary 判断主车是否“静止”(速度低于阈值)
func isEgoStationary(shareVars *sync.Map) bool {
	const minSpeed = 1 // m/s

	VelocityXOfCicvLocation, _ := shareVars.Load("VelocityXOfCicvLocation") // float64
	VelocityYOfCicvLocation, _ := shareVars.Load("VelocityYOfCicvLocation")
	speed := math.Sqrt(math.Pow(VelocityXOfCicvLocation.(float64), 2) + math.Pow(VelocityYOfCicvLocation.(float64), 2))

	return speed > minSpeed
}

// Rule 检测前方未知大目标物
func Rule(shareVars *sync.Map, msg *pjisuv_msgs.PerceptionObjects) string {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println(fmt.Sprintf("Recovered from panic: [%s], [%#v]", Label(), r))
		}
	}()

	// 判断主车所在位置
	outsideWorkshopFlag, _ := shareVars.Load("OutsideWorkshopFlag")
	if !outsideWorkshopFlag.(bool) {
		return ""
	}

	// 判断主车行驶速度
	if isEgoStationary(shareVars) {
		return ""
	}

	//const Cgcs2000X = 456256.260152
	//const Cgcs2000Y = 4397809.886833
	const MinStableFrameCount = 5   // frame
	const MaxTimeBetweenFrame = 0.5 // second

	//fmt.Println("\n", time.Unix(int64(msg.Header.TimeStamp), int64(msg.Header.TimeStamp*1e9)%1e9).Format(time.StampNano))
	for _, obj := range msg.Objs {

		// 判断目标物是否满足筛选条件
		if objTypeCheck(&obj) && objPosCheck(&obj) && objSizeCheck(&obj) {
			//fmt.Println(fmt.Sprintf("id: [%d], type: [%d], x/yrel: [%f, %f], x/yabs: [%f, %f], speed: [%f], size: [%f/%f/%f]",
			//	obj.Id, obj.Type, obj.X, obj.Y, obj.Xabs-Cgcs2000X, obj.Yabs-Cgcs2000Y, obj.Speed, obj.Length, obj.Width, obj.Height))

			// 目标物初见存档
			if prevObjRecord, exists := objectsStability[obj.Id]; exists == false {
				objectsStability[obj.Id] = Object{
					ID:               obj.Id,
					StableFrame:      1,
					LastExistingTime: msg.Header.TimeStamp,
				}
				//fmt.Println("---------- create ----------")
			} else {
				currObjRecord := Object{
					ID:               obj.Id,
					StableFrame:      1,
					LastExistingTime: msg.Header.TimeStamp,
				}

				// 目标物确认/更新/重置
				if currObjRecord.LastExistingTime-prevObjRecord.LastExistingTime <= MaxTimeBetweenFrame { // 目标物消失不超过0.5s
					currObjRecord.StableFrame = prevObjRecord.StableFrame + 1
					if currObjRecord.StableFrame == MinStableFrameCount {
						delete(objectsStability, obj.Id)
						//fmt.Println("!!!!!!!!!! found !!!!!!!!!!")
						return Label()
					} else {
						//fmt.Println("---------- update ----------")
					}
				} else {
					//fmt.Println("---------- reset ----------")
				}
				objectsStability[obj.Id] = currObjRecord
			}
		}
	}

	return ""
}