// ************************************
// @package: handleMgr
// @description: 反射类
// @author:
// @revision history:
// @create date: 2022-02-23 16:33:27
// ************************************

package handleMgr

import (
	"fmt"
	"goutil/logUtil"
	"reflect"
	"strings"
)

const (
	// 定义用于分隔模块名称和方法名称的分隔符
	con_DelimeterOfObjAndMethod = "_"
)

var (
	// 定义存放所有方法映射的变量
	methodMap = make(map[string]*ReflectMethod, 4)

	// 函数返回值类型
	responseType reflect.Type = reflect.TypeOf(new(ResponseObject))
)

// getStructName
// @description: 获取结构体类型的名称
// parameter:
//		@structType:结构体类型
// return:
//		@string:结构体类型的名称
func getStructName(structType reflect.Type) string {
	reflectTypeStr := structType.String()
	reflectTypeArr := strings.Split(reflectTypeStr, ".")

	return reflectTypeArr[len(reflectTypeArr)-1]
}

// getFullMethodName
// @description: 获取完整的方法名称
// parameter:
//		@structName:结构体名称
//		@methodName:方法名称
// return:
//		@string:完整的方法名称
func getFullMethodName(structName, methodName string) string {
	return structName + con_DelimeterOfObjAndMethod + methodName
}

// resolveMethodInOutParams
// @description: 解析方法的输入输出参数
// parameter:
//		@method:方法对应的反射值
// return:
//		@inTypes:输入参数类型集合
//		@outTypes:输出参数类型集合
func resolveMethodInOutParams(method reflect.Value) (inTypes []reflect.Type, outTypes []reflect.Type) {
	methodType := method.Type()
	for i := 0; i < methodType.NumIn(); i++ {
		inTypes = append(inTypes, methodType.In(i))
	}

	for i := 0; i < methodType.NumOut(); i++ {
		outTypes = append(outTypes, methodType.Out(i))
	}

	return
}

// RegisterFunction
// @description: 对象注册
// parameter:
//		@structObject:对象
// return:
func RegisterFunction(structObject interface{}) {
	// 获取structObject对应的反射 Type 和 Value
	reflectValue := reflect.ValueOf(structObject)
	reflectType := reflect.TypeOf(structObject)

	// 提取对象类型名称
	structName := getStructName(reflectType)

	// 获取structObject中返回值为responseObject的方法
	for i := 0; i < reflectType.NumMethod(); i++ {
		// 获得方法名称
		methodName := reflectType.Method(i).Name

		// 获得方法及其输入参数的类型列表
		method := reflectValue.MethodByName(methodName)
		inTypes, outTypes := resolveMethodInOutParams(method)

		// 判断输出参数数量是否正确
		if len(outTypes) != 1 {
			continue
		}

		// 判断返回值是否为responseObject
		if outTypes[0] != responseType {
			continue
		}

		// 添加到列表中
		methodMap[getFullMethodName(structName, methodName)] = NewReflectMethod(method, inTypes, outTypes)
	}
}

// CallFunction
// @description: 调用方法
// parameter:
//		@requestObject:请求对象
// return:
//		@responseObj:返还对象
func CallFunction(requestObject *RequestObject) (responseObj *ResponseObject) {
	responseObj = GetInitResponseObj()

	var reflectMethod *ReflectMethod
	var ok bool

	// 根据传入的ModuleName和MethodName找到对应的方法对象
	key := getFullMethodName(requestObject.ModuleName, requestObject.MethodName)
	if reflectMethod, ok = methodMap[key]; !ok {
		message := fmt.Sprintf("找不到指定的方法：%s", key)
		logUtil.ErrorLog(message)
		responseObj.SetResultStatus(-2, message)
		return
	}

	// 判断参数数量是否相同
	inTypesLength := len(reflectMethod.InTypes)
	paramLength := len(requestObject.Parameters)
	if paramLength != inTypesLength {
		message := fmt.Sprintf("传入的参数数量不符，本地方法%s的参数数量：%d，传入的参数数量为：%d", key, inTypesLength, paramLength)
		logUtil.ErrorLog(message)
		responseObj.SetResultStatus(-3, message)
		return
	}

	// 构造参数
	in := make([]reflect.Value, inTypesLength)
	for i := 0; i < inTypesLength; i++ {
		inTypeItem := reflectMethod.InTypes[i]
		paramItem := requestObject.Parameters[i]

		// 已支持类型：Client,Player(非基本类型)
		// 已支持类型：Bool,Int,Int8,Int16,Int32,Int64,Uint,Uint8,Uint16,Uint32,Uint64,Float32,Float64,String
		// 已支持类型：以及上面所列出类型的Slice类型
		// 未支持类型：Uintptr,Complex64,Complex128,Array,Chan,Func,Interface,Map,Ptr,Struct,UnsafePointer
		// 由于byte与int8同义，rune与int32同义，所以并不需要单独处理
		// 枚举参数的类型，并进行类型转换
		switch inTypeItem.Kind() {
		case reflect.Bool:
			if paramBool, ok := paramItem.(bool); ok {
				in[i] = reflect.ValueOf(paramBool)
			}
		case reflect.Int:
			if paramFloat64, ok := paramItem.(int); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Int8:
			if paramFloat64, ok := paramItem.(int8); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Int16:
			if paramFloat64, ok := paramItem.(int16); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Int32:
			if paramFloat64, ok := paramItem.(int32); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Int64:
			if paramFloat64, ok := paramItem.(int64); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Uint:
			if paramFloat64, ok := paramItem.(uint); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Uint8:
			if paramFloat64, ok := paramItem.(uint8); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Uint16:
			if paramFloat64, ok := paramItem.(uint16); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Uint32:
			if paramFloat64, ok := paramItem.(uint32); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Uint64:
			if paramFloat64, ok := paramItem.(uint64); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Float32:
			if paramFloat64, ok := paramItem.(float32); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.Float64:
			if paramFloat64, ok := paramItem.(float64); ok {
				in[i] = reflect.ValueOf(paramFloat64)
			}
		case reflect.String:
			if paramString, ok := paramItem.(string); ok {
				in[i] = reflect.ValueOf(paramString)
			}
		case reflect.Slice:
			// 如果是Slice类型，则需要对其中的项再次进行类型判断及类型转换
			if paramInterface, ok := paramItem.([]interface{}); ok {
				switch inTypeItem.String() {
				case "[]bool":
					paramsInner := make([]bool, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramBool, ok := paramInterface[i].(bool); ok {
							paramsInner[i] = paramBool
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]int":
					paramsInner := make([]int, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(int); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]int8":
					paramsInner := make([]int8, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(int8); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]int16":
					paramsInner := make([]int16, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(int16); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]int32":
					paramsInner := make([]int32, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(int32); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]int64":
					paramsInner := make([]int64, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(int64); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]uint":
					paramsInner := make([]uint, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(uint); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
					// case "[]uint8": 特殊处理
				case "[]uint16":
					paramsInner := make([]uint16, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(uint16); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]uint32":
					paramsInner := make([]uint32, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(uint32); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]uint64":
					paramsInner := make([]uint64, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(uint64); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]float32":
					paramsInner := make([]float32, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(float32); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]float64":
					paramsInner := make([]float64, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramFloat64, ok := paramInterface[i].(float64); ok {
							paramsInner[i] = paramFloat64
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				case "[]string":
					paramsInner := make([]string, len(paramInterface))
					for i := 0; i < len(paramInterface); i++ {
						if paramString, ok := paramInterface[i].(string); ok {
							paramsInner[i] = paramString
						}
					}
					in[i] = reflect.ValueOf(paramsInner)
				}
			} else if inTypeItem.String() == "[]uint8" { // 由于[]uint8在传输过程中会被转化成字符串，所以单独处理;
				if paramString, ok := paramItem.(string); ok {
					paramUint8 := ([]uint8)(paramString)
					in[i] = reflect.ValueOf(paramUint8)
				}
			}
		}
	}

	// 判断是否有无效的参数（传入的参数类型和方法定义的类型不匹配导致没有赋值）
	for _, item := range in {
		if reflect.Value.IsValid(item) == false {
			message := fmt.Sprintf("type:%v,value:%v.方法%s传入的参数%v无效", reflect.TypeOf(item), reflect.ValueOf(item), key, requestObject.Parameters)
			logUtil.ErrorLog(message)
			responseObj.SetResultStatus(-1, message)
			return
		}
	}

	out := reflectMethod.Method.Call(in)

	// 并输出结果到客户端（由于只有一个返回值，所以取out[0]）
	if responseObj, ok = (&out[0]).Interface().(*ResponseObject); !ok {
		message := fmt.Sprintf("返回值类型推断为ResponseObject 出错, tyep is :%v", reflect.TypeOf(out[0]))
		logUtil.ErrorLog(message)
		responseObj.SetResultStatus(-1, message)
		return
	}
	return
}
