package rpcCenter

import (
	"context"
	cstring "github.com/mhaya/extend/string"
	cfacade "github.com/mhaya/facade"
	"github.com/mhaya/game/game_cluster/internal/code"
	"github.com/mhaya/game/game_cluster/internal/constant"
	"github.com/mhaya/game/game_cluster/internal/mdb"
	"github.com/mhaya/game/game_cluster/internal/param"
	"github.com/mhaya/game/game_cluster/internal/pb"
	clog "github.com/mhaya/logger"
	"math"
	"math/rand"
)

// route = 节点类型.节点handler.remote函数

const (
	centerType = "center"
	gameType   = "database"
)

const (
	opsActor     = ".ops"
	accountActor = ".account"
)

const (
	ping            = "ping"
	registerAccount = "registerAccount"
)

const (
	sourcePath = ".system"
)

// Ping 访问center节点，确认center已启动
func Ping(app cfacade.IApplication) bool {
	nodeId := GetCenterNodeID(app)
	if nodeId == "" {
		return false
	}

	rsp := &pb.Bool{}
	targetPath := nodeId + opsActor
	errCode := app.ActorSystem().CallWait(sourcePath, targetPath, ping, nil, rsp)
	if code.IsFail(errCode) {
		return false
	}

	return rsp.Value
}

// RegisterAccount 注册帐号
func RegisterAccount(app cfacade.IApplication, openID, ip, plt, channel, sign string) *param.LoginResp {
	req := &param.LoginReq{
		OpenID:   openID,
		IP:       ip,
		Platform: plt,
		Channel:  channel,
		Sign:     sign,
	}

	targetPath := GetTargetPath(app, accountActor)
	rsp := &param.LoginResp{}
	errCode := app.ActorSystem().CallWait(sourcePath, targetPath, registerAccount, req, rsp)
	if code.IsFail(errCode) {
		clog.Warnf("[RegisterAccount] openID = %s, errCode = %v", openID, errCode)
		return nil
	}
	nodeId, ok := SetNode(app)
	if code.IsFail(ok) {
		clog.Warnf("[RegisterAccount] openID = %s,nodeID=%v, errCode = %v", openID, nodeId, errCode)
		return nil
	}
	rsp.TargetPath = cfacade.NewChildPath(nodeId, "player", rsp.UserName)
	return rsp
}

func GetCenterNodeID(app cfacade.IApplication) string {
	list := app.Discovery().ListByType(centerType)
	if len(list) > 0 {
		return list[0].GetNodeId()
	}
	return ""
}

func GetTargetPath(app cfacade.IApplication, actorID string) string {
	nodeId := GetCenterNodeID(app)
	return nodeId + actorID
}

func SetNode(app cfacade.IApplication) (string, int32) {
	var nodeId string
	list := app.Discovery().ListByType(gameType)
	lNode := len(list)
	key := 0
	if lNode == 0 {
		return "", code.AccountBindFail
	} else if lNode > 1 {
		key = rand.Intn(lNode)
	}
	nodeId = list[key].GetNodeId()
	if lNode > 0 {
		m, err := mdb.RDB.HGetAll(context.Background(), constant.ServerLoadHKey).Result()
		if err != nil {
			nodeId = list[key].GetNodeId()
		}
		if len(m) == 0 {
			nodeId = list[key].GetNodeId()
		} else {
			num := math.MaxInt
			for _, v := range list {
				id := v.GetNodeId()
				total, ok := cstring.ToInt(m[id])
				if ok {
					if total < num {
						num = total
						nodeId = v.GetNodeId()
					}
				} else {
					mdb.RDB.HSet(context.Background(), constant.ServerLoadHKey, id, 0)
				}
			}
		}
	}
	return nodeId, code.OK
}
