package controller

import (
	"blazing/common/socket/errorcode"

	"blazing/cool"

	"blazing/logic/service/player"
	"os"
	"strings"
	"time"

	"bytes"
	"context"
	"fmt"
	"reflect"

	"github.com/gogf/gf/v2/os/gcmd"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/lunixbochs/struc"
)

var Maincontroller = NewController() //注入service
// 分发cmd逻辑实现Controller
type Controller struct {
	Port      uint16
	RPCClient struct {
		Kick func(uint32) error

		RegisterLogic func(uint16, uint16) error
	}
}

type LogicClient struct {
}

func (h *LogicClient) KickPerson(a int) error {

	fmt.Println("检测到踢人请求", a)
	player.KickPlayer(uint32(a))
	return nil
}
func (h *LogicClient) QuitSelf(a int) error {
	//TODO 这里待退出
	fmt.Println("检测到退出请求")

	go func() {

		for {

			//entity.ConutPlayer()
			fmt.Println("当前在线人数", player.ConutPlayer())

			if player.ConutPlayer() <= 0 {
				//执行退出逻辑
				os.Exit(1)
			}
			<-time.After((50000))
		}
	}()
	//service.KickPlayer(uint32(a))
	return nil
}
func NewController() *Controller {
	return &Controller{}
}

func ParseCmd[T any](a T, data []byte) T {
	// := info.NewLoginSidInfo()
	struc.Unpack(bytes.NewBuffer(data), &a)
	return a
	//fmt.Println(pinfo)
	//login.OnData_1001(pinfo, player)
	//fmt.Println(data)
}

func init() { //默认初始化扫描
	// 解析命令行参数
	cool.Config.PortBL = gcmd.GetOpt("port", "1").Uint16()
	// 获取对象的反射值和类型
	value := reflect.ValueOf(Maincontroller)

	// 获取类型
	typ := value.Type()

	for i := 0; i < typ.NumMethod(); i++ {
		method := typ.Method(i)

		methodValue := value.MethodByName(method.Name)
		//fmt.Println("找到注册方法", method.Name)
		methodValue.Type().NumIn()

		for _, func_cmd := range getcmd(methodValue.Type().In(0)) {
			if func_cmd == 0 { //说明不是注册方法
				glog.Warning(context.Background(), "方法参数必须是结构体", method.Name, "跳过注册")
				continue
			}

			if cool.Config.PortBL == 0 && func_cmd > 1000 { //判断login服务器
				continue

			}

			if cool.Config.PortBL != 0 && func_cmd < 1000 { //判断login服务器
				continue

			}
			glog.Debug(context.Background(), "注册方法", func_cmd, method.Name)
			//	fmt.Println(methodValue.Interface().(func(gnet.Conn, player.TomeeHeader)))
			_, ok := cool.CmdCache.LoadOrStore(func_cmd, methodValue) //TODO 待实现对不同用户初始化方法以取消全局cmdcache

			if ok { //方法已存在init
				glog.Error(context.Background(), "方法已存在init,不会初始化后面的方法", func_cmd)
			}
		}

	}
}

func getcmd(t reflect.Type) []uint32 {
	// 处理指针类型
	if t.Kind() == reflect.Ptr {
		t = t.Elem() // 获取指针指向的类型
	}

	// 确保是结构体
	if t.Kind() != reflect.Struct {

		return []uint32{0}
	}

	// 遍历结构体字段
	//	fmt.Printf("结构体 %s 的字段信息：\n", t.Name())
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		//fmt.Printf("- 字段名: %s\n", field.Name)
		//fmt.Printf("  类型: %v\n", field.Type)
		if field.Type == reflect.TypeOf(player.TomeeHeader{}) {
			//	fmt.Println(reflect.ValueOf(field))

			return gconv.SliceUint32(strings.Split(field.Tag.Get("cmd"), "|"))

		}

		if field.Type.Kind() == reflect.Struct ||
			(field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct) {

			nestedType := field.Type
			if nestedType.Kind() == reflect.Ptr {
				nestedType = nestedType.Elem()
			}
			getcmd(nestedType)
		}
		//	fmt.Println()
	}
	return []uint32{0}
}

// 遍历结构体方法并执行RECV_cmd
func Recv(c *player.Conn, data player.TomeeHeader) {

	cmdlister, ok := cool.CmdCache.Load(data.CMD)
	if !ok {

		glog.Error(context.Background(), data.CMD, "cmd未注册")
		return //TODO 待实现cmd未注册
	}

	//	fmt.Println(cmdlister)
	glog.Debug(context.Background(), "接收数据", data.UserID, data.CMD)
	params := []reflect.Value{}

	//funct := cmdlister.Type().NumIn()

	// 如果需要可设置的变量（用于修改值），创建指针并解引用
	ptrValue := reflect.New(cmdlister.Type().In(0).Elem())

	tt1 := ptrValue.Elem().Addr().Interface()
	//	fmt.Println(tt1)
	err := struc.Unpack(bytes.NewBuffer(data.Data), tt1)
	if err != nil {
		fmt.Println(err)
	}
	//fmt.Println(tt1)
	ptrValue1 := ptrValue.Elem().Addr()
	// 设置 Name 字段
	nameField := ptrValue.Elem().Field(0) //首个为header
	if nameField.IsValid() && nameField.CanSet() {
		nameField.Set(reflect.ValueOf(data))
	}
	if cmdlister.Type().In(1) == reflect.TypeOf(&player.Player{}) {
		t := player.GetPlayer(c, data.UserID)
		//	fmt.Println(data.CMD, "接收 变量的地址 ", &t.Info, t.Info.UserID)
		err := t.WaitForLoginWithCtx(context.Background())
		if err != nil {
			fmt.Println("登录失败")
		}

		params = append(params, ptrValue1, reflect.ValueOf(t))
	} else {

		params = append(params, ptrValue1, reflect.ValueOf(c))
	}

	ret := cmdlister.Call(params)

	if len(ret) <= 0 { //如果判断没有参数,那就说明这个包没有返回参数
		return
	}

	aa, ok := ret[1].Interface().(errorcode.ErrorCode) //判断错误
	data.Result = uint32(aa)
	if aa == -1 {
		return

	}

	if ok && aa != 0 { //这里实现回复错误包

		cool.Loger.Error(context.Background(), aa.Code())

		c.SendPack(data.Pack(nil))
		return

	}

	data.Version = "7"
	//glog.Debug(context.Background(), data.CMD, "回复数据")
	c.SendPack(data.Pack(ret[0].Interface()))

}
