package sdk

import (
	"context"
	mhayaGin "github.com/mhaya/components/gin"
	mhayaError "github.com/mhaya/error"
	mhayaString "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/data"
	"github.com/mhaya/game/game_cluster/internal/mdb"
	"github.com/mhaya/game/game_cluster/internal/token"
	mhayaLogger "github.com/mhaya/logger"
	"math/rand"
)

// sdk平台类型
const (
	DevMode  int = 1 // 开发模式，注册开发帐号登陆(开发时使用)
	QuickSDK int = 2 // quick sdk
)

var (
	invokeMaps = make(map[int]Invoke)
)

type (
	Invoke interface {
		SdkId() int                                                        // sdk id
		Reconnect(token *token.Token) (int32, *token.Token)                //重连
		Login(config *data.SdkConfigRow, params Params, callback Callback) // Login 登录验证接口
		PayCallback(config *data.SdkConfigRow, c *mhayaGin.Context)        // PayCallback 支付回调接口
	}

	Params   map[string]string
	Result   map[string]interface{}
	Callback func(code int32, result Result, error ...error)
)

func (p Params) GetInt(key string, defaultValue ...int) int {
	defVal := 0
	if len(defaultValue) > 0 {
		defVal = defaultValue[0]
	}

	val, found := p[key]
	if !found {
		return defVal
	}

	intVal, ok := mhayaString.ToInt(val)
	if ok {
		return intVal
	}

	return defVal
}

func (p Params) GetString(key string) (string, bool) {
	v, ok := p[key]
	return v, ok
}

func register(invoke Invoke) {
	invokeMaps[invoke.SdkId()] = invoke
}

func GetInvoke(sdkId int) (invoke Invoke, error error) {
	invoke, found := invokeMaps[sdkId]
	if found == false {
		return nil, mhayaError.Errorf("[sdkId = %d] not found.", sdkId)
	}

	return invoke, nil
}

func Init(app cfacade.IApplication) {
	register(quickSdk{app})
}

func SetNode(app cfacade.IApplication) (string, int32) {
	var nodeId string
	list := app.Discovery().ListByType("game")
	lNode := len(list)
	key := 0
	if lNode == 0 {
		return "", code.AccountBindFail
	} else if lNode > 1 {
		key = rand.Intn(lNode)
	}

	if lNode == 1 {
		return list[0].GetNodeId(), code.OK
	}

	nodeId = list[key].GetNodeId()
	if lNode > 0 {
		m, err := mdb.RDB.HGetAll(context.Background(), constant.ServerLoadHKey).Result()
		if err != nil {
			mhayaLogger.Warnf("[SetNode] Load too high. err=%v", err)
		}
		var maps = make(map[string]int, 10)
		for _, v := range list {
			if d, ok := m[v.GetNodeId()]; ok {
				p, ok := mhayaString.ToInt(d)
				if !ok {
					nodeId = list[key].GetNodeId()
				}
				maps[v.GetNodeId()] = p
			} else {
				maps[v.GetNodeId()] = 0
			}
		}
		wwr := NewWeightedRoundRobin(maps)
		info := wwr.Pick()
		if info == nil {
			mhayaLogger.Warnf("[SetNode] Load too high. data=%v", maps)
			return "", code.Error
		}
		nodeId = info.NodeId
	}
	return nodeId, code.OK
}
