package gameapi

import (
	"../log"
	"../mod"
	pb "../protos"
	"encoding/json"
	"github.com/coheneye/go-simplejson"
	"github.com/shopspring/decimal"
	"go.uber.org/zap"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

//进入游戏
//
func ZZYL_Enter_game(guid string, gameParam []string, cash int64, isReconnect bool, res *pb.S_EnterGame) {

	if len(gameParam) != 1 {
		res.Ec = SYS_GAME_PARAM_ERROR
		return
	}

	cash_ := convertBalanceToZzyl(cash) //1:100
	kindId := gameParam[0]
	log.Info("< ZZYL_Enter_game", zap.String("guid", guid), zap.String("gameId", kindId), zap.Float64(" converted money", cash_))

	if cash == 0 && !isReconnect && (kindId == LONGHUDOU || kindId == HONGHEIDAZHAN) { //龙虎斗 红黑 没钱不能进 不是重连
		res.Ec = SYS_ENTER_GAME_NOT_ALLOW
		return
	}

	param := ResponseParams{"", -1, 0.00, -1, "", 0.00}
	back := ResponseHeader{"", "", param}
	if ZZYL__request(ZZYL_LoadContent(ZZYL_GetLoginUri(guid, GenIpaddr(), "CNY")), &back) {
		if isReconnect {
			log.Info("ZZYL 重连 success", zap.String("guid", guid), zap.Float64("money", cash_))
			res.Url = back.D.Url + "&gameId=" + kindId
			res.GameParam = gameParam
			res.Ec = SUCCESS
		} else {
			orderid := guid + Zzyl_agent + GetFormatDate() //流水号不重复
			if ZZYL__request(ZZYL_LoadContent(ZZYL_GetAddMoneyUri(guid, "CNY", cash_, orderid)), &back) {
				log.Info("ZZYL 上分 success", zap.String("guid", guid), zap.Float64("money", cash_))
				res.Url = back.D.Url + "&gameId=" + kindId
				res.GameParam = gameParam
				res.Ec = SUCCESS
			} else {
				log.Info("ZZYL_Leave_game GetAddMoneyUri faild", zap.String("guid", guid), zap.Any("code", back.D.Code))
				res.Ec = SYS_DEPOSIT_FAILED
			}
		}
	} else {
		log.Debug("ZZYL_Leave_game GetLoginUri faild", zap.String("guid", guid), zap.Any("code", back.D.Code))
		res.Ec = SYS_LOGIN_FAILED
	}
}

//下分后 获取该玩家游戏任务统计
func ZZYL_GetUserStatistics(guid uint64) {
	var taskList TaskStatistics
	if ZZYL__request_statistics(ZZYL_LoadContent(getUserTaskStatistics(strconv.FormatUint(guid, 10))), &taskList) {
		UpdateReward(guid, taskList.validDate, taskList.tasks)
		log.Info("ZZYL 统计 success", zap.Uint64("guid", guid), zap.Any("taskList", taskList))
	} else {
		log.Error("ZZYL_GetUserStatistics failed", zap.Uint64("guid", guid))
	}
}

//退出游戏
func ZZYL_Leave_game(guid string, p_b *pb.S_Ntf_UserBalance, p_r *pb.S_LeaveGame) {

	wd_money,ok := ZZYL_withdraw(guid)
	if ok {
		p_r.Ec = SUCCESS
		p_b.Balance = wd_money
	}else {
		p_r.Ec = SYS_WITHDRAW_FAILED
	}
}

//查询余额
func ZZYL_query_balance(guid string)(bool, int64){
	param := ResponseParams{"", -1, 0.00, -1, "", 0.00}
	back := ResponseHeader{"", "", param}
	if ZZYL__request(ZZYL_LoadContent(ZZYL_GetQueryBalanceUri(guid, "127.0.0.1")), &back){
		return true , ConvertBalanceToPlatform(back.D.Money)
	}else{
		return false , 0
	}
}

func ZZYL_withdraw(guid string) (balance int64,b bool){

	param := ResponseParams{"", -1, 0.00, -1, "", 0.00}
	back := ResponseHeader{"", "", param}

	orderid := Zzyl_agent + GetFormatDate() + guid
	//!!!!!!这里需要注意   下分接口中的money字段只要大于0就可以,H5那边不用这个字段作参考,因为玩家在游戏的过程中去查询玩家余额是不准确的
	if ZZYL__request(ZZYL_LoadContent(ZZYL_GetDeductMoneyUri(guid, "CNY", 1, orderid)), &back) { //下分操作9
		if back.D.Amount >= 0 {
			backMoney := ConvertBalanceToPlatform(back.D.Amount)
			log.Info("ZZYL_withdraw 取款 success ", zap.String("guid", guid), zap.Int64("balance", backMoney))
			return backMoney,true
		} else {
			log.Error("ZZYL_withdraw 取款 余额 < 0", zap.Float64("amount", back.D.Amount))
			return 0,false
		}
	} else {
		log.Debug("ZZYL_withdraw 取款 faild", zap.String("guid", guid), zap.Any("code", back.D.Code))
		return 0,false
	}
}

//请求
func ZZYL__request(url string, back *ResponseHeader) bool {

	log.Debug("ZZYL 请求", zap.String("url", Zzyl_addr + url))
	resp, err := http.Get(Zzyl_addr + url)
	if err != nil {
		log.Debug("gameapi zzyl Do_request Get err", zap.Error(err))
		return false
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Debug("gameapi zzyl Do_request ReadAll err", zap.Error(err))
		return false
	}

	if err := json.Unmarshal(body[:len(body)], &back); err != nil {
		log.Debug("gameapi api_zzyl Do_request json.Unmarshal", zap.Error(err))
		return false
	}
	log.Debug("ZZYL 响应", zap.Any("data", back))
	if back.D.Code == 0 {
		return true
	} else {
		return false
	}
}

//获取游戏任务统计请求
func ZZYL__request_statistics(url string, task *TaskStatistics) bool {

	resp, err := http.Get(Zzyl_addr + url)
	if err != nil {
		log.Debug("ZZYL__request_statistics Do_request Get err", zap.Error(err))
		return false
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Debug("ZZYL__request_statistics ReadAll err", zap.Error(err))
		return false
	}

	js, _ := simplejson.NewJson([]byte(body))
	code := js.Get("d").Get("code").MustInt()

	if code == 0 {
		list, _ := js.Get("d").Get("data").Map()
		taskMap := make(map[string]int)
		for k, v := range list[time.Now().Format("060102")].(map[string]interface{}) {
			num, _ := v.(json.Number).Int64()
			taskMap[k] = int(num)
		}
		task.tasks = taskMap
		task.validDate = time.Now().Format("2006-01-02")
		log.Debug("ZZYL__request_statistics return back", zap.Any("data", *task))
		return true
	} else {
		return false
	}
}

//加载请求类容
func ZZYL_LoadContent(origStr string) string {
	log.Debug("ZZYL 请求参数", zap.String("data", origStr))
	var req requestheader
	req.agent = Zzyl_agent
	req.timestamp = strconv.FormatInt(time.Now().Unix(), 10)
	v := url.Values{}
	v.Add("param", AesEncrypt(origStr, DesKey))
	body := v.Encode()
	req.param = strings.Split(body, "=")[1]
	req.key = Md5Encrypt(req.agent + req.timestamp + Md5Key)
	return req.string()
}

//获取用户游戏任务统计
func getUserTaskStatistics(guid string) string {
	var p requestParams
	p.s = query_task_statistic
	p.account = guid
	return p.getQueryUserTaskStatisticsString()
}

//登陆
func ZZYL_GetLoginUri(account string, ip string, currency string) string {
	var p requestParams
	p.s = login_opt
	p.account = account
	p.ip = ip
	p.currency = currency
	return p.getLoginString()
}

//查询余额 请求类容
func ZZYL_GetQueryBalanceUri(account string, ip string) string {

	var p requestParams
	p.s = query_balance_opt
	p.account = account
	p.ip = ip
	return p.getQueryBalanceString()
}

//加钱
func ZZYL_GetAddMoneyUri(account string, currency string, money float64, orderid string) string {
	var p requestParams
	p.s = add_money_opt
	p.account = account
	p.currency = currency
	p.money = money
	p.orderid = orderid //代理编号+yyyyMMddHHmmssSSS+account
	return p.getAddMoneyString()
}

//扣钱
func ZZYL_GetDeductMoneyUri(account string, currency string, money float64, orderid string) string {
	var p requestParams
	p.s = deduct_money_opt
	p.account = account
	p.money = money
	p.currency = currency
	p.orderid = orderid
	return p.getDeductMoneyString()
}

//查询加扣钱记录
func ZZYL_GetMoneyOrderUri(orderid string) string {
	var p requestParams
	p.s = query_order_opt
	p.orderid = orderid
	return p.getQueryOrderString()
}

//查询玩家是否在线
func ZZYL_GetUserOnlineUri(account string) string {
	var p requestParams
	p.s = query_user_online
	p.account = account
	return p.getQueryUserOnlineString()
}

//踢出玩家
func ZZYL_GetKickUserUri(account string) string {
	var p requestParams
	p.s = kick_out_user
	p.account = account
	return p.getKickOutUserString()
}

//平台金币换算成至尊娱乐
func convertBalanceToZzyl(balance int64) float64 {
	return float64(balance) / 100
}

//至尊娱乐换算成平台
func ConvertBalanceToPlatform(balance float64) int64 {
	return decimal.NewFromFloat(balance).Mul(decimal.NewFromFloat(100)).IntPart()
}

//强制关端  下分、发送离开游戏事件
func ZZYL_Cronjob(guid uint64, gameId int64) bool {

	param := ResponseParams{"", -1, 0.00, -1, "", 0.00}
	back := ResponseHeader{"", "", param}
	//1.下分
	if ZZYL_DeductMoney(strconv.FormatUint(guid, 10), &back) {

		balance := ConvertBalanceToPlatform(back.D.Amount)
		//2.给用户加金币
		log.Debug("redis update balance", zap.Int64("back.D.Amount", balance))
		new_balance, err := mod.AddUserBalance(guid, balance)
		log.Debug("redis update balance", zap.Int64("new_balance", new_balance))
		if err != nil {
			log.Error("ZZYL_Cronjob falild", zap.Error(err), zap.Uint64("guid", guid), zap.Int64("balance", balance))
		}
		if new_balance >= 0 {
			//3, 断开游戏连接20分钟以后就不走断线重连,下分成功直接进大厅
			if err := mod.UpdateUserAttr(guid, "regameinfo", ""); err != nil {
				log.Error("ZZYL_Cronjob clean regameinfo err,please check", zap.Uint64("guid", guid))
			}
		}

		//4.修改玩家游戏位置状态
		//UpdateUserStateOut("ZZYL", guid, gameId)

		//5.通知后台更新玩家金币变更
		Nats_Ntf_Balance(guid, gameId, strconv.FormatInt(new_balance, 10), false)
		//6.查询牌局记录统计
		ZZYL_GetUserStatistics(guid)
		log.Debug("ZZYL_Cronjob ZZYL_DeductMoney  success", zap.Uint64("guid", guid))
		return true
	} else {
		log.Error("ZZYL_Cronjob ZZYL_DeductMoney failed,please look user regameinfo", zap.Uint64("guid", guid), zap.Any("data", back))
		return false
	}
}

//至尊娱乐下分
func ZZYL_DeductMoney(guid string, back *ResponseHeader) bool {

	orderid := Zzyl_agent + GetFormatDate() + guid
	//!!!!!!这里需要注意   下分接口中的money字段只要大于0就可以,H5那边不用这个字段作参考,因为玩家在游戏的过程中去查询玩家余额是不准确的
	if ZZYL__request(ZZYL_LoadContent(ZZYL_GetDeductMoneyUri(guid, "CNY", 1, orderid)), back) { //下分操作9
		if back.D.Amount >= 0 {
			log.Debug("ZZYL_DeductMoney success", zap.Any("guid", guid))
			return true
		} else {
			log.Error("ZZYL_DeductMoney balance num < 0", zap.Float64("amount", back.D.Amount))
			return false
		}
	} else {
		log.Error("ZZYL_DeductMoney failed", zap.Any("data", back))
		return false
	}
}
