package gameapi

import (
	"../log"
	"../mod"
	pb "../protos"
	"github.com/go-redis/redis"
	"go.uber.org/zap"
	"strconv"
	"strings"
)

//TODO 暂时没用 后续优化
//type ApiConfig struct {
//	Key       string
//	Host      string
//	AgentName string
//}

//TODO 暂时没用 后续优化
//type Api interface {
//	Init()
//	Register()
//	Login()
//	AddMoney()
//	QueryMoney()
//	ReduceMoney()
//	Destroy()
//}

const (
	ZZYL   		= 1
	HONGBO 		= 2
	DBDZ   		= 3
	DWQP   		= 4
	IG_LOTTERY  = 5 //IG彩票
	IG_DZ       = 6 //IG电子
	CQ9_BY		= 7 //CQ9捕鱼
	CQ9_DZ		= 8 //CQ9电子
	IG_LMG		= 9 //IG视讯
	//CQ9_QP		= 10 //棋牌
	DBDZ_QP     = 11 //JDB棋牌
	VG			= 12 //VG
	FG			= 13 //FG

	//游戏延时一定时间 才能下分  单位秒
	VG_DELAY_WITHDRAW_TIME 		=  2
	CQ9_QP_DELAY_WITHDRAW_TIME  =  3
	CQ9_BY_DELAY_WITHDRAW_TIME  =  3
	DBDZ_QP_DELAY_WITHDRAW_1TIME =  9
	DBDZ_QP_DELAY_WITHDRAW_2TIME =  12
	DBDZ_QP_DELAY_WITHDRAW_3TIME =  14
)

//通过游戏id判断是哪个游戏接入商
func GetChannelByGameId(gameId int64) int {

	if gameId > 2000 && gameId <= 2011 {
		return ZZYL
	}

	if gameId > 500400 && gameId <= 500499 {
		return HONGBO
	}

	//if gameId > 2005000 && gameId <= 2005999 {
	//	return CQ9_QP
	//}

	if gameId > 2200000 && gameId <= 2200999 {
		return DBDZ_QP
	}

	if gameId > 2300000 && gameId <= 2300999 {
		return VG
	}

	if gameId > 2400000 && gameId <= 2400999 {
		return FG
	}

	if gameId > 4001000 && gameId <= 4001999 {
		return DBDZ
	}

	if gameId > 4005000 && gameId <= 4009999 {
		return IG_DZ
	}

	if gameId > 4004400 && gameId <= 4004499 {
		return CQ9_BY
	}

	if gameId > 4004000 && gameId <= 4004399 {
		return CQ9_DZ
	}

	if gameId > 4010000 && gameId <= 4010999 {
		return FG
	}

	if gameId > 5003000 && gameId <= 5003999 {
		return IG_LMG
	}

	if gameId > 6001000 && gameId <= 6001999 {
		return DBDZ
	}

	if gameId > 6002000 && gameId <= 6002999 {
		return IG_LOTTERY
	}

	return -1
}

func Dispatcher_EnterGame(guid uint64, gameId int64, gameParam []string, res *pb.S_EnterGame) {

	log.Debug(">>>Dispatcher_EnterGame", zap.Any("gameParam", gameParam))

	cash, ok := getUserBalance(guid) //获取用户余额
	if !ok {
		res.Ec = -1
		return
	}

	re_gameId, isReconnect := isUserReconnect(guid)
	if isReconnect {
		gameId = re_gameId //进入重连gameId
	}
	if !checkEnterGameLimit(gameId, gameParam, guid, isReconnect, cash) { //检查进入游戏限制
		res.Ec = -1
		return
	}

	Nats_Ntf_Balance(guid, gameId, strconv.FormatInt(cash, 10), true) //通知php,玩家进入游戏前的游戏币数量

	makerId := GetChannelByGameId(gameId) //获取接入游戏厂商Id
	if makerId == -1 {
		log.Error("Dispatcher_EnterGame GetChannelByGameId doesnt exist", zap.Int64("gameId", gameId))
		res.Ec = -1
		return
	}

	switch makerId {

	case ZZYL: //至尊娱乐 手动上下分
		ZZYL_Enter_game(strconv.FormatUint(guid, 10), gameParam, cash, isReconnect, res)
		after_enter_game("ZZYL", cash, res, guid, gameId, gameParam)

	case IG_LOTTERY, IG_LMG, IG_DZ: // 手动上下分
		IG_Enter_Game(strconv.FormatUint(guid, 10), gameParam, cash, isReconnect, res, makerId)
		after_enter_game("IG"+ strconv.Itoa(makerId), cash, res, guid, gameId, gameParam)

	case CQ9_BY, CQ9_DZ:// 手动上下分, CQ9_QP不上:
		CQ9_Enter_game(strconv.FormatUint(guid, 10), gameParam, cash, isReconnect, res)
		after_enter_game("CQ9", cash, res, guid, gameId, gameParam)

	case HONGBO: //红博 共享钱包
		Hongbo_Enter_game(strconv.FormatUint(guid, 10), gameParam, res)
		UpdateUserStateIn("HONGBO", guid, gameId)

	case DBDZ: //夺宝电子
		DBDZ_Enter_game(strconv.FormatUint(guid, 10), gameParam, res)
		UpdateUserStateIn("DBDZ", guid, gameId)

	case DBDZ_QP://夺宝电子棋牌
		DBDZ_QP_Enter_game(strconv.FormatUint(guid, 10), gameParam, cash, isReconnect, res)
		after_enter_game("DBDZ_QP", cash, res, guid, gameId, gameParam)

	case VG:// 手动上下分
		VG_Enter_game(strconv.FormatUint(guid, 10), gameParam, cash, isReconnect, res)
		after_enter_game("VG", cash, res, guid, gameId, gameParam)

	case FG:// 手动上下分
		FG_Enter_game(strconv.FormatUint(guid, 10), gameParam, cash, isReconnect, res)
		after_enter_game("FG", cash, res, guid, gameId, gameParam)

	//case DWQP://DW棋牌 手动上下分
	//	DWQP_Enter_game(strconv.FormatUint(guid, 10), gameParam, money, isReconnect, res)
	//	after_enter_game("DWQP",money, res, guid, gameId, gameParam)
	default:
		res.Ec = -1
	}
}

func Dispatcher_LeaveGame(guid uint64, gameId int64, gameParam []int32, balance *pb.S_Ntf_UserBalance, res *pb.S_LeaveGame) {

	makerId := GetChannelByGameId(gameId) //获取接入游戏厂商Id
	guid_str := strconv.FormatUint(guid, 10)
	
	switch makerId {

	case ZZYL: //至尊娱乐 手动上下分
		ZZYL_Leave_game(guid_str, balance, res)
		After_leave_game("ZZYL", res, guid, balance, gameId)

	case IG_LOTTERY, IG_LMG, IG_DZ: // 手动上下分
		IG_Leave_Game(guid_str, balance, res)
		After_leave_game("IG"+strconv.Itoa(makerId), res, guid, balance, gameId)

	case CQ9_DZ: // 手动上下分
		CQ9_Leave_game(guid_str, balance, res)
		After_leave_game("CQ9", res, guid, balance, gameId)

	case HONGBO: //红博 共享钱包
		Hongbo_Leave_game(guid_str, balance, res)
		UpdateUserStateOut("HONGBO", guid, gameId)

	case DBDZ: //夺宝电子
		DBDZ_Leave_game(guid_str, balance, res)
		UpdateUserStateOut("DBDZ", guid, gameId)

	//case DBDZ_QP://夺宝电子棋牌
	//	DBDZ_QP_Leave_game(guid_str, balance, res)
	//	After_leave_game("DBDZ_QP", res, guid, balance, gameId)

	//case VG:// 手动上下分
	//	VG_Leave_game(guid_str, balance, res)
	//	After_leave_game("VG", res, guid, balance, gameId)
		
	case FG:// 手动上下分
		FG_Leave_game(guid_str, balance, res)
		After_leave_game("FG", res, guid, balance, gameId)

	//case DWQP://DW棋牌 手动上下分
	//	DWQP_Leave_game(strconv.FormatUint(guid, 10), balance, res)
	//	after_leave_game("DWQP",res, guid, balance, gameId)

	default:
		res.Ec = -1
	}

	if res.Ec == 0 { //通知nats 入库玩家余额
		Nats_Ntf_Balance(guid, gameId, strconv.FormatInt(balance.Balance, 10), false)
	}
}

//func UpdateWithDrawTask(guid string, id int64) bool{
//	if err := mod.UpdateWithDraw(guid, []byte(strconv.FormatInt(id,10)));err != nil{
//		log.Debug("UpdateWithDrawTask UpdateWithDraw err",zap.Error(err))
//		return false
//	}
//	return true
//}
//
//func GetWithDrawTaskId(guid string) (id string,b bool){
//	str, err := mod.GetWithDraw(guid)
//	if err != nil{
//		log.Debug("GetWithDrawTask GetWithDraw err",zap.Error(err))
//		return "",false
//	}
//
//	if len(str) > 0{
//		return str,false
//	}else{
//		return "",false
//	}
//}
//
//func DeleteWithDrawTask(guid string) bool{
//	if err := mod.RemWithDraw(guid);err != nil{
//		log.Debug("DeleteWithDrawTask RemWithDraw err",zap.Error(err))
//		return false
//	}
//	return true
//}

//仅限上下分模式 进入游戏后
//1、记录玩家位置状态 在大厅 在某款游戏中
//2、暂时记录重连信息 如果正常退出会清空,反之 客户端利用该信息 断线重连
func after_enter_game(gn string, oldBalance int64, res *pb.S_EnterGame, guid uint64, gameId int64, gameParam []string) {

	if res.Ec == 0 {
		log.Info(gn+" redis update balance", zap.Uint64("guid", guid), zap.Int64("oldbalance", oldBalance), zap.String("url", res.Url))
		new_balance, err := mod.AddUserBalance(guid, -oldBalance)
		log.Info(gn+" redis update balance", zap.Uint64("guid", guid), zap.Int64("newbalance", new_balance))

		if err != nil {
			res.Ec = -1
			log.Error(gn+" redis update balance to 0 falild", zap.String("err", err.Error()),
				zap.Uint64("guid", guid), zap.Int64("delta", -oldBalance))
			return
		}

		if oldBalance >= 0 {
			gameConf, has := FindGameConfBygameId(gameId) //查找游戏配置
			if !has {
				res.Ec = -1
				log.Debug("after_enter_game FindGameConfBygameId null,please check conf of gamelist",zap.Int64("gameId",gameId), zap.Any("gameParam", gameParam))
				return
			}
			regameinfo := strconv.FormatInt(gameId, 10)
			for i := 0; i < len(gameParam); i++ {
				regameinfo += "#" + gameParam[i]
			}
			regameinfo += "#" + strconv.Itoa(int(gameConf.GetOrientation()))
			if err := mod.UpdateUserAttr(guid, "regameinfo", regameinfo); err != nil {
				res.Ec = -1
				log.Error(gn+" redis save regameinfo err", zap.Uint64("guid", guid), zap.String("regameinfo", regameinfo))
				return
			}
			log.Info(gn+" redis update balance to 0 success", zap.Uint64("guid", guid), zap.Int64("oldBalance", oldBalance), zap.Int64("newbalance", new_balance))
		}

		UpdateUserStateIn(gn, guid, gameId)
	}
}

func After_leave_game(gn string, res *pb.S_LeaveGame, guid uint64, balance *pb.S_Ntf_UserBalance, gameId int64) {

	if res.Ec == 0 {
		//1.修改玩家位置 从游戏退出到大厅
		UpdateUserStateOut(gn, guid, gameId)
		//2.开始结算
		if !OnSettlement(gn, guid, balance){
			res.Ec = -1
			return
		}
		//3.清除断线重连信息
		CleanReconnectInfo(gn, guid)

	}else{
		log.Error(gn+"OnSettlement has some problem", zap.Uint64("guid", guid), zap.Int64("balance", balance.Balance))
	}
}

//清除玩家断线重连信息
func CleanReconnectInfo(gn string, guid uint64){
	if err := mod.UpdateUserAttr(guid, "regameinfo", ""); err != nil {
		log.Debug(gn+" cleanGamePosition err", zap.Uint64("guid", guid))
	}
	log.Debug(gn+" cleanGamePosition success", zap.Uint64("guid", guid))
}

//游戏结算
func OnSettlement(gn string, guid uint64, bal *pb.S_Ntf_UserBalance) bool{

		if bal.Balance < 0 {
			log.Error("OnSettlement bal.Balance < 0",zap.Int64("Balance", bal.Balance))
			return false
		}

		log.Debug("OnSettlement update balance", zap.Int64("withdraw balance", bal.Balance))
		new_balance, err := mod.AddUserBalance(guid, bal.Balance)
		if err != nil {
			log.Error(gn+" OnSettlement update newBalance err", zap.Error(err),zap.Uint64("guid", guid), zap.Int64("balance", bal.Balance))
			return false
		}
		log.Debug("OnSettlement update balance", zap.Int64("end newbalance", new_balance))
		bal.Balance = new_balance
		return true
}

//清除玩家游戏位置
func RemoveUserLogicByGuid(guid uint64) {

	gId, err := mod.GetUserLogic(guid)
	if err != nil && err != redis.Nil {
		log.Debug("RemoveUserLogicByGuid err", zap.Error(err), zap.Uint64("guid", guid))
		return
	}
	if err := mod.RemoveUserLogic(guid, gId); err != nil {
		log.Error("RemoveUserLogicByGuid err", zap.Error(err),
			zap.Uint64("guid", guid), zap.Int64("gameId", gId))
	}
}

//更新玩家游戏状态 退出 在某个品牌某个游戏中 进入大厅
func UpdateUserStateOut(gn string, guid uint64, gameId int64) {
	if err := mod.RemoveUserLogic(guid, gameId); err != nil {
		log.Error(gn+"after_leave_game RemoveUserLogic err", zap.Error(err), zap.Int64("gameId", gameId))
	}
}

//更新玩家游戏状态  在大厅 在某个品牌某个游戏中
func UpdateUserStateIn(gn string, guid uint64, gameId int64) {

	if err := mod.SaveUserLogic(guid, gameId); err != nil {
		log.Error(gn+"after_enter_game SaveUserLogic err", zap.Error(err), zap.Int64("gameId", gameId))
	}
	RecoderUserGameHistory(guid, gameId)
}

// 记录玩家最近玩的10款游戏
func RecoderUserGameHistory(guid uint64, gameId int64){

	guid_str := strconv.FormatUint(guid,10)
	gh, err := mod.GetGameHistory(guid_str)
	if err != nil && err != redis.Nil {
		log.Debug("RecoderUserGameHistory err",zap.String("guid",guid_str),zap.Int64("gameId",gameId))
		return
	}
	gId := strconv.FormatInt(gameId,10)
	gh_arr := strings.Split(gh,",")
	for i := 0; i < len(gh_arr); i++ {
		if gh_arr[i] == gId {
			gh_arr = append(gh_arr[:i], gh_arr[i+1:]...)
			break
		}
	}
	gh_arr = append(gh_arr, gId)
	if len(gh_arr) > 10{
		gh_arr = append(gh_arr[:0], gh_arr[1:]...)
	}
	gh = ""
	for i := 0; i < len(gh_arr); i++{
		gh += gh_arr[i]
		if i != len(gh_arr) - 1{
			gh += ","
		}
	}
	log.Debug("最近记录",zap.String("guid", guid_str), zap.String("newGameHistory", gh))
	if err := mod.UpdateGameHistory(guid_str, []byte(gh));err != nil{
		log.Debug("RecoderUserGameHistory UpdateGameHistory err",zap.String("guid",guid_str),zap.Int64("gameId",gameId),
			zap.String("oldGameHistory", gh))
	}
}

//获取玩家余额
func getUserBalance(guid uint64) (cash int64, b bool) {

	money, err := mod.GetUserAttr(guid, "balance") //获取玩家余额
	if err != nil {
		log.Error("Dispatcher_EnterGame getUserBalance err", zap.Uint64("guid", guid), zap.String("err", err.Error()))
		return 0, false
	}

	i_money, err := strconv.ParseInt(money, 10, 64)
	if err != nil {
		log.Error("Dispatcher_EnterGame getUserBalance ParseInt", zap.Uint64("guid", guid), zap.String("err", err.Error()), zap.String("money", money))
		return 0, false
	}
	return i_money, true
}

//该玩家是否是断线重连
func isUserReconnect(guid uint64) (gameId int64,b bool) {

	regame, err := mod.GetUserAttr(guid, "regameinfo")
	if err != nil && err != redis.Nil {
		log.Error("Dispatcher_EnterGame isReconnect err", zap.Uint64("guid", guid), zap.String("err", err.Error()))
		return 0,false
	}

	if len(regame) <= 0 {
		return 0,false
	} else {
		gameId_,err := strconv.ParseInt(strings.Split(regame,"#")[0],10,64)
		if err != nil{
			log.Debug("isUserReconnect ParseInt err",zap.Error(err),zap.Uint64("guid",guid))
			return 0,false
		}
		log.Debug("重连成功",zap.Uint64("guid",guid),zap.Int64("gameid", gameId_))
		return gameId_,true
	}

}

//检查入场限制
func checkEnterGameLimit(gameId int64, gameParam []string, guid uint64, isReconnect bool, cash int64) bool {

	gameConf, has := FindGameConfBygameId(gameId) //查找游戏配置
	if !has {
		log.Debug("Dispatcher_EnterGame checkEnterGameLimit null,please check conf of gamelist",zap.Int64("gameId",gameId),
			zap.Any("gameParam", gameParam))
		return false
	}
	limitMoney := gameConf.GetMinLimit()
	if cash < limitMoney && !isReconnect { //不是断线重连 低于入场限制不能进游戏
		log.Debug("Dispatcher_EnterGame user is not reconnect and  not enouth money enter game",
			zap.Int64("cash", cash), zap.Int64("limitMoney", limitMoney))
		return false
	}
	return true
}
