package main

import (
	"../log"
	"../mod"
	"../utils"
	"./pb"
	"encoding/json"
	"fmt"
	"github.com/coheneye/go-simplejson"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	"go.uber.org/zap"
	"net/http"
	"strconv"
	"time"
)

//  获取会员余额
func GetBalance(c *gin.Context) {
	// 校验 content-type 和 agentName
	if err := CheckContext(c); err != nil {
		log.Debug(">>>>>>>>Order CheckContext", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_ILLEGAL_OP,
		})
		return
	}

	body, _ := c.GetRawData()
	js, err := simplejson.NewJson(body)
	if err != nil {
		log.Debug(">>>>>>>>Order simplejson.NewJson", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_FMT_DATA,
		})
		return
	}

	// 校验 token
	token := js.Get("token").MustString()
	username := js.Get("member").Get("username").MustString()
	ec := pb.Ec_SUCCESS
	var balancef float64 = 0.00 //余额

	defer func() {
		log.Info("wallet GetBalance", zap.String("username", username), zap.Float64("balance", balancef), zap.Any("codeId", ec))
		c.JSON(http.StatusOK, gin.H{
			"codeId": ec,
			"token":  token,
			"member": gin.H{
				"username": username,
				"balance":  balancef,
			},
		})
	}()

	if err = CheckToken(token); err != nil {
		log.Debug(">>>>>>>>Order CheckToken", zap.Error(err))
		ec = pb.Ec(pb.Ec_value[err.Error()])
		return
	}

	guid, err := strconv.ParseUint(username, 10, 64)
	if err != nil {
		log.Debug(">>>>>>>>Order strconv.ParseUint", zap.Error(err))
		ec = pb.Ec_SYSTEM_EXCEPTION
		return
	}
	// 取得余额
	sbalance, err := mod.GetUserAttr(guid, "balance")
	if nil != err {
		log.Debug(">>>>>>>>Order GetUserAttr", zap.Error(err))
		ec = pb.Ec_MEMBER_NOT_FOUND
		return
	}
	//TODO : 优化
	balance, err := strconv.ParseInt(sbalance, 10, 64)
	if nil != err {
		log.Debug(">>>>>>>>Order strconv.ParseInt", zap.Error(err))
		ec = pb.Ec_UNKNOWN
		return
	}
	balancef = ConvertBalance(balance)
}

// 存取款接口  amount可以为0
func Transfer(c *gin.Context) {
	// 校验 content-type 和 agentName
	if err := CheckContext(c); err != nil {
		log.Debug(">>>>>>>>Transfer CheckContext", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_ILLEGAL_OP,
		})
		return
	}

	body, _ := c.GetRawData()
	js, err := simplejson.NewJson(body)
	if err != nil {
		log.Debug("simplejson.NewJson faild", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_FMT_DATA,
		})
		return
	}

	// 校验 token
	token := js.Get("token").MustString()
	username := js.Get("member").Get("username").MustString()
	ticketId := js.Get("ticketId").MustInt64()
	serial := js.Get("data").MustString()
	amount := js.Get("member").Get("amount").MustFloat64()
	var bbalance float64 = 0.00 //转帐前余额
	ec := pb.Ec_SUCCESS

	defer func() {
		jb := gin.H{
			"codeId": ec,
			"token":  token,
			"data":   serial,
			"member": gin.H{
				"username": username,
				"amount":   amount,
				"balance":  bbalance,
			},
		}

		if ec != pb.Ec_SUCCESS && ec != pb.Ec_TRANSFER_SEQ_NUMBER_OCCUPIED {
			// 保存失败订单
			bytes, err := json.Marshal(utils.H{
				"codeId":   ec,
				"username": username,
				"ticketId": ticketId,
				"serial":   serial,
				"amount":   amount,
				"time":     time.Now().Unix(),
			})
			log.Debug(">>>>>>>>Transfer faild saved", zap.Any("data", fmt.Sprintf("%s", bytes)))
			if err == nil {
				err = mod.UpdateTradeFailed(ticketId, serial, AgentName, string(bytes))
				if nil != err {
					log.Error("UpdateTradeFailed", zap.Any("data", fmt.Sprintf("%s", bytes)))
				}
			} else {
				log.Error("Marshal", zap.Any("data", fmt.Sprintf("%s", bytes)))
			}
		}

		log.Info(">>>>>>>>Transfer success", zap.Any("data", jb))
		c.JSON(http.StatusOK, jb)
	}()

	if err = CheckToken(token); err != nil {
		log.Debug(">>>>>>>>Transfer CheckToken", zap.Error(err))
		ec = pb.Ec(pb.Ec_value[err.Error()])
		return
	}

	guid_, err := strconv.ParseUint(username, 10, 64)
	if err != nil {
		log.Debug(">>>>>>>>Transfer strconv.ParseUint", zap.Error(err))
		ec = pb.Ec_SYSTEM_EXCEPTION
		return
	}
	guid, err := mod.GetUserAttr(guid_, "account")
	if nil != err {
		log.Debug(">>>>>>>>Transfer GetUserAttr", zap.Error(err))
		ec = pb.Ec_MEMBER_NOT_FOUND
		return
	}
	if guid == "" {
		log.Debug(">>>>>>>>Transfer guid ==  nil", zap.Error(err))
		ec = pb.Ec_MEMBER_NOT_FOUND
		return
	}

	// amount 为 0  返回失败
	//if amount == float64(0.00) {
	//	log.Debug(">>>>>>>>Transfer amount == float64(0.00)", zap.Error(err))
	//	ec = pb.Ec_PARAMS_
	//	return
	//}
	// 检查该笔交易是否已成功
	val, err := mod.GetTicketIdBySerial(serial, AgentName)
	if (nil != err && err != redis.Nil) || len(val) > 0 {
		log.Debug(">>>>>>>>Transfer Ec_TRANSFER_SEQ_NUMBER_OCCUPIED", zap.Error(err))
		ec = pb.Ec_TRANSFER_SEQ_NUMBER_OCCUPIED
		return
	}

	// 取得余额
	sbalance, err := mod.GetUserAttr(guid_, "balance")
	if nil != err {
		log.Debug(">>>>>>>>Transfer GetUserAttr", zap.Error(err))
		ec = pb.Ec_UNKNOWN
		return
	}
	balance, err := strconv.ParseInt(sbalance, 10, 64)
	if nil != err {
		log.Debug(">>>>>>>>Transfer strconv.ParseInt", zap.Error(err))
		ec = pb.Ec_UNKNOWN
		return
	}
	bbalance = ConvertBalance(balance)
	// 检查 amount 是否合法
	if amount < float64(0.00) && bbalance < -amount {
		log.Debug(">>>>>>>>Transfer Ec_BALANCE_INSUFFICIENT", zap.Error(err))
		ec = pb.Ec_BALANCE_INSUFFICIENT
		return
	}

	// 扣款
	bytes, err := json.Marshal(utils.H{
		"username": username,
		"ticketId": ticketId,
		"serial":   serial,
		"amount":   amount,
		"time":     time.Now().Unix(),
	})
	if err != nil {
		log.Debug(">>>>>>>>Transfer json.Marshal", zap.Error(err))
		ec = pb.Ec_UNKNOWN
		return
	}
	delta := ConvertAmount(amount)

	arr, err := UpdateSerialStatus(guid_, delta, ticketId, serial, bytes)
	if nil != err {
		log.Debug(">>>>>>>>Transfer UpdateSerialStatus", zap.Error(err))
		ec = pb.Ec_FAILED_TRANSFER
		//TODO: 加入失败列表
		return
	}
	newBalance := utils.If_to_int64(arr[0], 0)
	// 异步执行
	go func() {
		// Rpc
		err = RpcNotifyBalanceChange(guid_, delta, newBalance)
	}()
	// 返回成功.

	//newBalancef = ConvertBalance(newBalance)

	// log
	log.Info("UpdateSequenceStatus", zap.Int64("ticketId", ticketId),
		zap.String("serial", serial), zap.String("username", username),
		zap.String("agentName", AgentName), zap.Float64("amount", amount),
		zap.Int64("newBalance", newBalance))
	// ev
}

// 确认存取款结果接口
func CheckTransfer(c *gin.Context) {
	// 校验 content-type 和 agentName
	if err := CheckContext(c); err != nil {
		log.Debug(">>>>>>>>CheckTransfer CheckContext", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_ILLEGAL_OP,
		})
		return
	}

	body, _ := c.GetRawData()
	js, err := simplejson.NewJson(body)
	if err != nil {
		log.Debug(">>>>>>>>CheckTransfer simplejson.NewJson", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_FMT_DATA,
		})
		return
	}
	// 校验 token
	token := js.Get("token").MustString()
	serial := js.Get("data").MustString()
	ec := pb.Ec_SUCCESS

	defer func() {

		c.JSON(http.StatusOK, gin.H{
			"token":  token,
			"codeId": ec,
		})
	}()

	if err = CheckToken(token); err != nil {
		ec = pb.Ec(pb.Ec_value[err.Error()])
		return
	}

	sval, err := mod.GetTicketIdBySerial(serial, AgentName)
	if err != nil || len(sval) <= 0 {
		log.Debug(">>>>>>>>CheckTransfer GetTicketIdBySerial", zap.Error(err))
		ec = pb.Ec(pb.Ec_RESOURCE_NOT_FOUND)
		return
	}
}

// 请求回滚转账事务
func Inform(c *gin.Context) {
	// 校验 content-type 和 agentName
	if err := CheckContext(c); err != nil {
		log.Debug(">>>>>>>>Inform Inform", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_ILLEGAL_OP,
		})
		return
	}

	body, _ := c.GetRawData()
	log.Debug(">>>>>>>>Inform body", zap.Any("data", body))
	js, err := simplejson.NewJson(body)
	if err != nil {
		log.Debug(">>>>>>>>Inform simplejson.NewJson", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_ILLEGAL_OP,
		})
		return
	}

	// 校验 token
	token := js.Get("token").MustString()
	username := js.Get("member").Get("username").MustString()
	ticketId := js.Get("ticketId").MustInt64()
	serial := js.Get("data").MustString()
	amount := js.Get("member").Get("amount").MustFloat64()
	var newBalancef float64 = 0.00
	ec := pb.Ec_SUCCESS

	defer func() {
		jb := gin.H{
			"codeId":   ec,
			"token":    token,
			"ticketId": ticketId,
			"data":     serial,
			"member": gin.H{
				"username": username,
				"amount":   amount,
				"balance":  newBalancef,
			},
		}

		if ec != pb.Ec_SUCCESS {
			ec = pb.Ec_FAILED_OP
		}
		c.JSON(http.StatusOK, jb)
	}()

	if err = CheckToken(token); err != nil {
		ec = pb.Ec(pb.Ec_value[err.Error()])
		log.Debug(">>>>>>>>Inform CheckToken", zap.Error(err))
		return
	}

	guid, err := strconv.ParseUint(username, 10, 64)
	if err != nil {
		log.Debug(">>>>>>>>Inform ParseUint", zap.Error(err))
		ec = pb.Ec_UNKNOWN
		return
	}
	//  guid 是否存在
	account, err := mod.GetUserAttr(guid, "account")
	if err != nil {
		log.Debug(">>>>>>>>Inform GetUserAttr", zap.Error(err))
		ec = pb.Ec_MEMBER_NOT_FOUND
		return
	}
	if account == "" {
		log.Debug(">>>>>>>>Inform account == nil", zap.Error(err))
		ec = pb.Ec_MEMBER_NOT_FOUND
		return
	}

	// 取得余额
	sbalance, err := mod.GetUserAttr(guid, "balance")
	if nil != err {
		ec = pb.Ec_UNKNOWN
		log.Debug(">>>>>>>>Inform account == nil", zap.Error(err))
		//ec = pb.Ec_FAILED_OP
		return
	}

	newBalance, err := strconv.ParseInt(sbalance, 10, 64)
	if err != nil {
		log.Debug(">>>>>>>>Inform account == nil", zap.Error(err))
		ec = pb.Ec_UNKNOWN
		return
	}

	newBalancef = ConvertBalance(newBalance)
	delta := ConvertAmount(amount)
	faild, err := mod.GetTradeFailed(ticketId, serial, AgentName)
	if err != nil && len(faild) <= 0 {
		log.Debug(">>>>>>>>Inform GetTradeFailed err", zap.Error(err))
		return
	}
	var order Orders
	json.Unmarshal([]byte(faild), &order)

	if amount > 0.00 {
		if order.Amount < 0 {
			log.Debug(">>>>>>>>Inform order.Amount < 0", zap.Error(err))
			return
		}
		val, err := mod.GetSerialStatus(ticketId, serial, AgentName)
		if err == nil && len(val) > 6 {
			return
		} else {
			// 扣款
			bytes, err := json.Marshal(utils.H{
				"username": username,
				"ticketId": ticketId,
				"serial":   serial,
				"amount":   amount,
				"time":     time.Now().Unix(),
			})
			if err != nil {
				log.Debug(">>>>>>>>Inform json.Marshal", zap.Error(err))
				ec = pb.Ec_UNKNOWN
				return
			}

			arr, err := UpdateSerialStatus(guid, delta, ticketId, serial, string(bytes))
			if err != nil {
				log.Debug(">>>>>>>>Inform UpdateSerialStatus", zap.Error(err))
				ec = pb.Ec_FAILED_OP
				return
			}
			newBalance := utils.If_to_int64(arr[0], 0)
			newBalancef = ConvertBalance(newBalance)
			err = mod.RemTradeFailed(ticketId, serial, AgentName) //清除失败加钱操作
			if nil != err {

				log.Debug("/account/inform/"+AgentName+" mod.RemTradeFailed", zap.Int64("ticketId", ticketId),
					zap.String("serial", serial), zap.String("AgentName", AgentName))
				//ec = pb.Ec_FAILED_OP
				//return
			} // else{return}
			//return
		}
	} else { // 如果amount < 0,查询数据库有对应记录则删除对应的扣钱操作,否则直接返回操作成功。
		if order.Amount >= 0 {
			return
		}
		val, err := mod.GetTradeFailed(ticketId, serial, AgentName)
		if err == nil && len(val) > 6 { // there is
			err = mod.RemTradeFailed(ticketId, serial, AgentName)
			if nil != err {
				ec = pb.Ec_FAILED_OP
				return
			}
		}
	}
}

// 请求对账接口
func Order(c *gin.Context) {
	// 校验 content-type 和 agentName
	if err := CheckContext(c); err != nil {
		log.Debug(">>>>>>>>Order CheckContext", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_ILLEGAL_OP,
		})
		return
	}

	body, _ := c.GetRawData()
	js, err := simplejson.NewJson(body)
	if err != nil {
		log.Debug(">>>>>>>>Order simplejson.NewJson", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_FMT_DATA,
		})
		return
	}
	// 校验 token
	token := js.Get("token").MustString()
	ticketId := js.Get("ticketId").MustInt64()
	ec := pb.Ec_SUCCESS
	var list []*pb.Order

	defer func() {
		c.JSON(http.StatusOK, gin.H{
			"token":    token,
			"codeId":   ec,
			"ticketId": ticketId,
			"list":     list,
		})
	}()

	if err = CheckToken(token); err != nil {
		ec = pb.Ec(pb.Ec_value[err.Error()])
		log.Debug(">>>>>>>>Order CheckToken", zap.Error(err))
		return
	}

	mss, err := mod.GetAllSerialStatus(ticketId, AgentName)
	if err != nil {
		log.Debug(">>>>>>>>Order GetAllSerialStatus", zap.Error(err))
		ec = pb.Ec_UNKNOWN
		return
	}
	for _, jst := range mss {
		js, err := simplejson.NewJson([]byte(jst))
		if err != nil {
			log.Debug("NewJson", zap.Int64("ticketId", ticketId),
				zap.Error(err))
			continue
		}
		transfer := &pb.Order{
			Username: js.Get("username").MustString(),
			TicketId: js.Get("ticketId").MustInt64(),
			Serial:   js.Get("serial").MustString(),
			Amount:   js.Get("amount").MustFloat64(),
		}
		list = append(list, transfer)
	}
	// log
	// ev
}

// 查询未派彩和未回滚记录
func Unsettle(c *gin.Context) {
	// 校验 content-type 和 agentName
	if err := CheckContext(c); err != nil {
		log.Debug(">>>>>>>>Order CheckContext", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_ILLEGAL_OP,
		})
		return
	}

	body, _ := c.GetRawData()
	js, err := simplejson.NewJson(body)
	if err != nil {
		log.Debug(">>>>>>>>Order simplejson.NewJson", zap.Error(err))
		c.JSON(http.StatusOK, gin.H{
			"codeId": pb.Ec_FMT_DATA,
		})
		return
	}
	// 校验 token
	token := js.Get("token").MustString()
	ec := pb.Ec_SUCCESS
	var list []*pb.Order

	defer func() {
		c.JSON(http.StatusOK, gin.H{
			"token":  token,
			"codeId": ec,
			"list":   list,
		})
	}()

	if err = CheckToken(token); err != nil {
		log.Debug(">>>>>>>>Order CheckToken", zap.Error(err))
		ec = pb.Ec(pb.Ec_value[err.Error()])
		return
	}

	keys, err := mod.GetAllFaildKeys(AgentName)
	if err != nil {
		log.Debug(">>>>>>>>Order GetAllFaildKeys", zap.Error(err))
		ec = pb.Ec_UNKNOWN
		return
	}

	for _, key := range keys {
		mss, err := mod.GetAllFaildStatus(key)
		if err != nil {
			log.Debug(">>>>>>>>Order GetAllFaildStatus", zap.Error(err))
			ec = pb.Ec_UNKNOWN
			return
		}
		for _, jst := range mss {
			js, err := simplejson.NewJson([]byte(jst))
			if err != nil {
				log.Debug("NewJson", zap.String("ticketId", key),
					zap.Error(err))
				continue
			}

			day, err := time.ParseDuration("-10m")
			if err != nil {
				log.Debug("ParseDuration -10m", zap.Error(err))
			}

			if js.Get("time").MustInt64() <= time.Now().Add(day).Unix() { //返回10分钟之前的
				transfer := &pb.Order{
					Username: js.Get("username").MustString(),
					TicketId: js.Get("ticketId").MustInt64(),
					Serial:   js.Get("serial").MustString(),
					Amount:   js.Get("amount").MustFloat64(),
				}
				list = append(list, transfer)
			}
		}
	}
}
