package main

import (
	"../utils"
	"github.com/coheneye/go-simplejson"
	"net/http"
	"strconv"

	"../log"
	"../mod"
	"../nt"
	pb "../protos"
	"../rpc"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

func do_default(c *gin.Context, req *MgrRequest) {
	c.JSON(http.StatusOK, gin.H{
		"cmd": req.Cmd,
		"result": gin.H{
			"ec": pb.ErrCode_CMD_UNSUPPORT,
		},
	})

	Ev.OnDefCmdUnsupported(req.Cmd)
}

func do_change_channel(c *gin.Context, args *rpc.RpcArgs, body string) {
	if nil != nt.Zk.SetNodeData(nt.ZkP.Channels, []byte(body)) {
		c.JSON(http.StatusOK, gin.H{
			"cmd": args.Cmd,
			"result": gin.H{
				"ec": pb.ErrCode_FAILED,
			},
		})
		return
	}
	do_change(c, args)
}

// 更新游戏配置
func do_change_game(c *gin.Context, args *rpc.RpcArgs, body string) {
	if nil != nt.Zk.SetNodeData(nt.ZkP.Games, []byte(body)) {
		c.JSON(http.StatusOK, gin.H{
			"cmd": args.Cmd,
			"result": gin.H{
				"ec": pb.ErrCode_FAILED,
			},
		})
		return
	}
	do_change(c, args)
}

// 更新渠道配置
func do_change(c *gin.Context, args *rpc.RpcArgs) {
	var res rpc.RpcResult

	//TODO 优化，做工作池管理起来
	go func() {
		_ = rpc.BroadCastToLobbies(args, &res)
	}()

	c.JSON(http.StatusOK, gin.H{
		"cmd": args.Cmd,
		"result": gin.H{
			"ec": pb.ErrCode_PENDING,
		},
	})

	Ev.OnMgrChangeGameConfig(args.Cmd)
}

// 更新客户端配置
func do_change_client_config(c *gin.Context, args *rpc.RpcArgs, body string) {
	err := nt.Zk.SetNodeData(nt.ZkP.ClientAddrs, []byte(body))
	if nil != err {
		c.JSON(http.StatusOK, gin.H{
			"cmd": args.Cmd,
			"result": gin.H{
				"ec": pb.ErrCode_FAILED,
			},
		})
		return
	}

	var res rpc.RpcResult

	// 通知到所有服务器
	//TODO 优化，做工作池管理起来
	go func() {
		_ = rpc.BroadCastToLobbies(args, &res)
	}()

	c.JSON(http.StatusOK, gin.H{
		"cmd": args.Cmd,
		"result": gin.H{
			"ec": pb.ErrCode_PENDING,
		},
	})

	Ev.OnMgrChangeClientConfig(args.Cmd, body)
}

// 跑马灯
func do_marquees(c *gin.Context, args *rpc.RpcArgs, body string) {
	p := simplejson.NewFrom(args.Params)
	id := p.Get("id").MustInt64()
	tp := p.Get("type").MustInt64()
	ec := pb.ErrCode_PENDING

	defer func() {
		c.JSON(http.StatusOK, gin.H{
			"cmd": args.Cmd,
			"result": gin.H{
				"ec": ec,
			},
		})
	}()

	var err error = nil
	// save
	if 1 == tp {
		err = mod.SaveMarquees(id, tp, body)
	} else if 2 == tp {
		err = mod.SaveNotices(id, tp, body)
	} else {
		ec = pb.ErrCode_BAD_REQUEST
		return
	}
	if nil != err {
		log.Error("do_marquees", zap.Error(err))
		ec = pb.ErrCode_UNKNOWN
		return
	}

	var res rpc.RpcResult
	//TODO 优化，做工作池管理起来
	go func() {
		_ = rpc.BroadCastToLobbies(args, &res)
	}()

	Ev.OnMgrPublishMarquee(args.Cmd, body)
}

// 修改玩家金币
func do_change_money(c *gin.Context, args *rpc.RpcArgs, body string) {
	p := simplejson.NewFrom(args.Params)
	guid := p.Get("guid").MustUint64()
	money := p.Get("money").MustInt64()
	ec := pb.ErrCode_OK

	defer func() {
		c.JSON(http.StatusOK, gin.H{
			"cmd": args.Cmd,
			"result": gin.H{
				"ec": ec,
			},
		})
	}()

	sold_money, err := mod.GetUserAttr(guid, "balance")
	if err != nil {
		log.Error("GetUserAttr", zap.Error(err))
		ec = pb.ErrCode_UNKNOWN
		return
	}

	old_money, err := strconv.ParseInt(sold_money, 10, 64)
	if nil != err {
		log.Error("ParseInt", zap.Error(err), zap.String("src", sold_money))
		ec = pb.ErrCode_UNKNOWN
		return
	}
	// 钱不够扣
	if money < 0 && old_money < -money {
		log.Warn("money insufficient", zap.Int64("old_money", old_money),
			zap.Int64("delta", money), zap.Uint64("guid", guid))
		ec = pb.ErrCode_BALANCE_INSUFFICIENT
		return
	}

	addr, err := rpc.GetUserAgentRpcUrl(guid)
	var newBalance int64 = 0
	if err != nil { // 玩家不在线，直接修改
		newBalance, err = mod.AddUserBalance(guid, money)
		if nil != err {
			log.Error("AddUserBalance", zap.Error(err))
			ec = pb.ErrCode_FAILED
			return
		} else {
			Ev.OnMgrChangeBalance(guid, money, newBalance)
		}
	} else { // 找到玩家所在 agent 修改，通知
		var res rpc.RpcResult
		err = rpc.RpcRequest(addr, args, &res)
		if nil != err {
			log.Warn("RpcRequest", zap.String("addr", addr), zap.String("cmd", args.Cmd), zap.Error(err))
			ec = pb.ErrCode_TARGET_NOT_FOUND
			return
		}
	}

	log.Info("change_money", zap.Uint64("guid", guid), zap.Int64("delta", money),
		zap.Int64("balance", newBalance))
}

// 修改玩家银行余额
func do_change_bank_money(c *gin.Context, args *rpc.RpcArgs, body string) {
	p := simplejson.NewFrom(args.Params)
	guid := p.Get("guid").MustUint64()
	money := p.Get("money").MustInt64()
	ec := pb.ErrCode_OK

	defer func() {
		c.JSON(http.StatusOK, gin.H{
			"cmd": args.Cmd,
			"result": gin.H{
				"ec": ec,
			},
		})
	}()

	sbank, err := mod.GetUserAttr(guid, "bank")
	if nil != err {
		log.Error("GetUserBank", zap.Error(err))
		ec = pb.ErrCode_UNKNOWN
		return
	}
	old_bank, err := strconv.ParseInt(sbank, 10, 64)
	if nil != err {
		log.Error("ParseInt", zap.Error(err), zap.String("src", sbank))
		ec = pb.ErrCode_UNKNOWN
		return
	}
	if money < 0 && old_bank < -money {
		log.Warn("bank insufficient", zap.Int64("old_bank", old_bank),
			zap.Int64("delta", money))
		ec = pb.ErrCode_BANK_INSUFFICIENT
		return
	}
	addr, err := rpc.GetUserAgentRpcUrl(guid)
	if err != nil { // 玩家不在线，直接修改
		newval, err := mod.AddUserBank(guid, money)
		if nil != err {
			log.Error("AddUserBank", zap.Uint64("guid", guid), zap.Int64("delta", money),
				zap.Error(err))
			ec = pb.ErrCode_UNKNOWN
		} else {
			Ev.OnMgrChangeBank(guid, money, newval)
			log.Info("change_bank", zap.String("cmd", args.Cmd), zap.Uint64("guid", guid), zap.Int64("delta", money))
		}
	} else { // 找到玩家所在 agent 修改，通知
		var res rpc.RpcResult
		err = rpc.RpcRequest(addr, args, &res)
		if nil != err {
			log.Warn("RpcRequest", zap.String("addr", addr), zap.String("cmd", args.Cmd), zap.Error(err))
			ec = pb.ErrCode_TARGET_NOT_FOUND
		}
		val, ok := res.Result.(map[string]interface{})
		if !ok {
			log.Error("Interface", zap.String("addr", addr), zap.String("cmd", args.Cmd), zap.Error(err))
			ec = pb.ErrCode_UNKNOWN
			return
		}
		ec = pb.ErrCode(utils.If_to_int32(val["ec"], 0))
	}
	log.Debug("do_change_bank", zap.String("addr", addr), zap.String("cmd", args.Cmd), zap.Int64("bank", money),
		zap.Int32("ec", int32(ec)))
}

// 禁止/解禁玩家
func do_disable(c *gin.Context, args *rpc.RpcArgs, body string) {
	p := simplejson.NewFrom(args.Params)
	guid := p.Get("guid").MustUint64()
	status := p.Get("status").MustInt64()
	var ec pb.ErrCode

	defer func() {
		c.JSON(http.StatusOK, gin.H{
			"cmd": args.Cmd,
			"result": gin.H{
				"ec": ec,
			},
		})
	}()
	// check parameters
	if status != 0 && status != 1 {
		ec = pb.ErrCode_BAD_REQUEST
		return
	}

	addr, err := rpc.GetUserAgentRpcUrl(guid)
	if err != nil { // 玩家不在线，直接修改
		err = mod.UpdateUserinfoToRedis(guid, map[string]interface{}{
			"status": status,
		})
		if nil != err {
			ec = pb.ErrCode_FAILED
			return
		} else {
			Ev.OnMgrDisableUser(guid, status)
		}
	} else { // 找到玩家所在 agent 修改，通知
		var res rpc.RpcResult
		err = rpc.RpcRequest(addr, args, &res)
		if nil != err {
			log.Warn("RpcRequest", zap.String("addr", addr), zap.String("cmd", args.Cmd), zap.Error(err))
			ec = pb.ErrCode_TARGET_NOT_FOUND
			return
		}
	}
	log.Info("do_disable", zap.String("addr", addr), zap.String("cmd", args.Cmd), zap.Int64("status", status),
		zap.Int32("ec", int32(ec)))
}

// 获得在线玩家
func do_online_list(c *gin.Context, args *rpc.RpcArgs, body string) {
	user_agent, user_logic := mod.GetAllUserPlace()
	userpos := make(map[uint64]uint64)

	for k, v := range user_agent {
		kk, err := strconv.ParseUint(k, 10, 64)
		vv, err2 := strconv.ParseUint(v, 10, 64)
		if err == nil && err2 == nil {
			userpos[kk] = vv
		}
	}
	for k, v := range user_logic {
		kk, err := strconv.ParseUint(k, 10, 64)
		vv, err2 := strconv.ParseUint(v, 10, 64)
		if err == nil && err2 == nil {
			userpos[kk] = vv
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"cmd": args.Cmd,
		"result": gin.H{
			"ec":   0,
			"list": userpos,
		},
	})
}

// 发送私人通知
func do_private_notice(c *gin.Context, args *rpc.RpcArgs, body string) {
	p := simplejson.NewFrom(args.Params)
	guid := p.Get("guid").MustUint64()
	ec := pb.ErrCode_OK

	defer func() {
		c.JSON(http.StatusOK, gin.H{
			"cmd": args.Cmd,
			"result": gin.H{
				"ec": ec,
			},
		})
	}()

	if !nt.DynConf.ValidGuid(guid) {
		log.Error("ValidGuid", zap.Uint64("guid", guid))
		ec = pb.ErrCode_BAD_REQUEST
		return
	}

	id := p.Get("id").MustInt64()

	jsp, err := p.MarshalJSON()
	if err != nil {
		log.Error("MarshalJSON", zap.Uint64("guid", guid), zap.Error(err))
		ec = pb.ErrCode_UNKNOWN
		return
	}

	err = mod.AddPrivateMail(guid, id, string(jsp))
	if nil != err {
		ec = pb.ErrCode_UNKNOWN
		log.Error("AddPrivateMail", zap.Error(err), zap.Uint64("guid", guid))
		return
	}

	addr, err := rpc.GetUserAgentRpcUrl(guid)
	if nil != err {
		ec = pb.ErrCode_OK // 玩家不在线而已
		log.Debug("GetUserAgent", zap.Error(err), zap.Uint64("guid", guid))
		return
	}
	var res rpc.RpcResult
	err = rpc.RpcRequest(addr, args, &res)
	if nil != err {
		log.Error("RpcRequest", zap.String("addr", addr), zap.String("cmd", args.Cmd), zap.Error(err))
		ec = pb.ErrCode_OK
	}

	Ev.OnMgrPublishPrivateMail(args.Cmd, string(jsp))
}