package chesstitians

import (
	"fmt"
	"math"
	"sort"
	"strings"
	"time"

	"mongo.games.com/goserver/core/logger"

	"mongo.games.com/game/common"
	rule "mongo.games.com/game/gamerule/chess"
	"mongo.games.com/game/gamesrv/base"
	"mongo.games.com/game/model"
	"mongo.games.com/game/proto"
	"mongo.games.com/game/protocol/chesstitians"
	"mongo.games.com/game/protocol/server"
	"mongo.games.com/game/srvdata"
)

// SceneEx 房间上的额外数据
type SceneEx struct {
	*base.Scene                                // 场景
	players     map[int32]*PlayerEx            // 玩家信息
	seats       [rule.MaxNumOfPlayer]*PlayerEx // 玩家
	opPos       int                            // 当前等待出牌的玩家位置
	winSnId     int32                          // 赢家id
	masterSnId  int32                          // 房主
	isAllRob    bool                           // 是否是纯AI场
	chess       rule.Logic                     // 棋盘对象
	lastMove    []int32                        // 上一步的行动
	variant     int                            // 棋类变种 对应fairy-stockfish
	stepSnId    int32                          // 计步玩家SnId
	stepNum     int                            // 计步回合数
	stepLimit   int                            // 计步最大回合数
	stepKing    int                            // 孤王计步回合数
	drawSnId    int32                          // 求和的玩家SnId
	nextSnId    int32                          // 再来一局玩家SnId
}

func getChessVariant(gameId int) int {
	var variant int
	switch gameId {
	case common.GameId_Chesstitians:
		variant = rule.ChessVarChess
	case common.GameId_ChesstitiansMakruk:
		variant = rule.ChessVarMakruk
	case common.GameId_ChesstitiansCambodian, common.GameId_ChesstitiansCambodianRobot:
		variant = rule.ChessVarCambodian
	}
	return variant
}

func NewSceneEx(s *base.Scene) *SceneEx {
	variant := getChessVariant(s.GameId)
	chess := rule.NewChess(variant)
	chess.Init()
	sceneEx := &SceneEx{
		Scene:   s,
		chess:   chess,
		players: make(map[int32]*PlayerEx),
		variant: variant,
	}
	return sceneEx
}

func (e *SceneEx) init() bool {
	// 初始配置
	e.SetPlayerNum(rule.MaxNumOfPlayer)
	return true
}

func (e *SceneEx) Clear() {
	// 重置
	e.chess.Init()
	e.opPos = rule.InvalidPos
	e.isAllRob = false
	e.winSnId = 0
	e.nextSnId = 0
	for _, player := range e.players {
		if player != nil {
			player.UnmarkFlag(base.PlayerState_WaitNext)
		}
	}
	e.lastMove = e.lastMove[:0]
	e.stepSnId = 0
	e.stepNum = 0
	e.stepLimit = 0
	e.drawSnId = 0
}

func (e *SceneEx) CanStart() bool {
	if e.GetGaming() {
		return false
	}

	if e.GetPlayerCnt() == rule.MaxNumOfPlayer {
		return true
	}
	return false
}

func (e *SceneEx) GetPlayerCnt() int {
	var cnt int
	for i := 0; i < e.GetPlayerNum(); i++ {
		playerEx := e.seats[i]
		if playerEx == nil {
			continue
		}
		cnt++
	}
	return cnt
}

func (e *SceneEx) GetGamingPlayerCnt() int {
	var cnt int
	for i := 0; i < e.GetPlayerNum(); i++ {
		playerEx := e.seats[i]
		if playerEx == nil {
			continue
		}
		if playerEx.IsGameing() {
			cnt++
		}
	}
	return cnt
}

func (e *SceneEx) GetRobotCnt() int {
	var cnt int
	for i := 0; i < e.GetPlayerNum(); i++ {
		playerEx := e.seats[i]
		if playerEx == nil {
			continue
		}
		if playerEx.IsRob {
			cnt++
		}
	}
	return cnt
}

func (e *SceneEx) GetGamingRobotCnt() int {
	var cnt int
	for i := 0; i < e.GetPlayerNum(); i++ {
		playerEx := e.seats[i]
		if playerEx == nil {
			continue
		}
		if playerEx.IsRob && playerEx.IsGameing() {
			cnt++
		}
	}
	return cnt
}

func (e *SceneEx) GetSeatPlayerCnt() int {
	var cnt int
	for i := 0; i < e.GetPlayerNum(); i++ {
		playerEx := e.seats[i]
		if playerEx == nil {
			continue
		}
		cnt++
	}
	return cnt
}

func (e *SceneEx) delPlayer(p *base.Player) {
	if p, exist := e.players[p.SnId]; exist {
		e.seats[p.GetPos()] = nil
		delete(e.players, p.SnId)
	}
}

func (e *SceneEx) OnPlayerLeave(p *base.Player, reason int) {
	e.delPlayer(p)
	e.BroadcastPlayerLeave(p, reason)
}

func (e *SceneEx) SceneDestroy(force bool) {
	//销毁房间
	e.Scene.Destroy(force)
}

func (e *SceneEx) BroadcastPlayerLeave(p *base.Player, reason int) {
	scLeavePack := &chesstitians.SCChesstitiansPlayerLeave{
		Pos: proto.Int(p.GetPos()),
	}
	proto.SetDefaults(scLeavePack)
	logger.Logger.Trace("SCChesstitiansPlayerLeave: ", p.SnId, " scLeavePack: ", scLeavePack)
	e.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansPlayerLeave), scLeavePack, p.GetSid())
}

func (e *SceneEx) BroadcastAudienceNum(p *base.Player) {
	pack := &chesstitians.SCChesstitiansUpdateAudienceNum{
		AudienceNum: proto.Int(e.GetAudiencesNum()),
	}
	proto.SetDefaults(pack)
	e.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansUpdateAudienceNum), pack, p.GetSid())
}

// BroadcastUpdateMasterSnId 广播房主更换
func (e *SceneEx) BroadcastUpdateMasterSnId(changeState bool) {
	pack := &chesstitians.SCChesstitiansUpdateMasterSnid{
		MasterSnid: proto.Int32(e.masterSnId),
	}
	proto.SetDefaults(pack)
	e.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansUpdateMasterSnid), pack, 0)
	//logger.Logger.Trace("BroadcastUpdateMasterSnId ", pack)

	//重置开始倒计时
	if changeState && e.CanStart() {
		e.Scene.ChangeSceneState(rule.SceneStateWaitStart)
	}
}

func (e *SceneEx) playerOpPack(snId int32, opcode int, opRetCode chesstitians.OpResultCode, params []int64) *chesstitians.SCChesstitiansPlayerOp {
	pack := &chesstitians.SCChesstitiansPlayerOp{
		OpCode:    proto.Int(opcode),
		OpParam:   params,
		SnId:      proto.Int32(snId),
		OpRetCode: opRetCode,
		Check:     e.chess.GetCheck(),
		Checkmate: e.chess.GetCheckmate(),
		StepSnId:  e.stepSnId,
		StepNum:   int64(proto.Int(e.stepNum)),
		StepLimit: int64(e.stepLimit),
	}
	p := e.GetPlayer(snId)
	if p != nil {
		if ex, ok := p.ExtraData.(*PlayerEx); ok {
			pack.TotalTime = append(pack.TotalTime, ex.GetTotalTime())
			for _, v := range e.seats {
				if v != nil && v.Pos != ex.Pos {
					pack.TotalTime = append(pack.TotalTime, v.GetTotalTime())
					break
				}
			}
		}
	}

	proto.SetDefaults(pack)
	return pack
}

// OnPlayerSCOp 发送玩家操作情况
func (e *SceneEx) OnPlayerSCOp(p *base.Player, opcode int, opRetCode chesstitians.OpResultCode, params []int64) {
	pack := e.playerOpPack(p.SnId, opcode, opRetCode, params)
	p.SendToClient(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansPlayerOp), pack)
	logger.Logger.Tracef("OnPlayerSCOp %s", pack)
}

// BroadcastPlayerSCOp 广播发送玩家操作情况
func (e *SceneEx) BroadcastPlayerSCOp(snid int32, opcode int, opRetCode chesstitians.OpResultCode, params []int64) {
	pack := e.playerOpPack(snid, opcode, opRetCode, params)
	e.Broadcast(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansPlayerOp), pack, 0)
	logger.Logger.Tracef("BroadcastPlayerSCOp %s", pack)
}

// FindOnePos 逆时针找一个空位
func (e *SceneEx) FindOnePos() int {
	for i := 0; i < e.GetPlayerNum(); i++ {
		if e.seats[i] == nil {
			return i
		}
	}
	return rule.InvalidPos
}

func (e *SceneEx) SystemCoinOut() int64 {
	systemGain := int64(0)
	for i := 0; i < e.GetPlayerNum(); i++ {
		playerData := e.seats[i]

		if playerData != nil && playerData.IsGameing() && playerData.IsRob {
			systemGain += playerData.winCoin
		}
	}
	return systemGain
}

func (e *SceneEx) AllPlayerEnterGame() {
	for i := 0; i < e.GetPlayerNum(); i++ {
		if e.seats[i] == nil {
			continue
		}

		if e.seats[i].IsMarkFlag(base.PlayerState_GameBreak) == false {
			e.seats[i].UnmarkFlag(base.PlayerState_WaitNext)
			e.seats[i].SyncFlag()
		}
	}
}

func (e *SceneEx) SetCurOpPos(pos int) {
	e.opPos = pos
	e.seats[pos].lastTime = time.Now()
}

func (e *SceneEx) GetCurOpPos() int {
	return e.opPos
}

func (e *SceneEx) AddChessGrade(p *PlayerEx, num int64) {
	if p == nil {
		return
	}

	// 人机对战没有积分
	if e.GetGameId() != common.GameId_ChesstitiansCambodianRobot {
		p.AddChessGrade(num)
	}
}

func (e *SceneEx) AddCoin(p *PlayerEx, num int64, gainWay int32, syncFlag int, oper, remark string) {
	if p == nil {
		return
	}

	// 人机对战没有金币结算
	if e.GetGameId() != common.GameId_ChesstitiansCambodianRobot {
		p.AddCoin(num, gainWay, syncFlag, oper, remark)
	}
}

func (e *SceneEx) GetSeatByCKey(cKey string) *PlayerEx {
	_cKey := strings.ToLower(cKey)
	for _, seat := range e.seats {
		if _cKey == "w" && !seat.isBlack || _cKey == "b" && seat.isBlack {
			return seat
		}
	}
	return nil
}

// ChessInit 棋盘初始化
func (e *SceneEx) ChessInit() {
	e.chess.Init()
	e.lastMove = []int32{}
	// 空结构
	// 随机
	firstIdx := e.RandInt(2)
	fmt.Println("@@firstIdx", firstIdx)
	for idx, seat := range e.seats {
		if seat != nil {
			if idx == firstIdx {
				// 默认seats中的第一个是白棋，先走
				seat.isBlack = false
			} else {
				seat.isBlack = true
			}
			seat.oldGrade = seat.ChessGrade
			pack := &chesstitians.SCChesstitiansCard{}
			// 通过cards[0] 传递isBlack
			if seat.isBlack {
				pack.Cards = append(pack.Cards, int32(1))
			} else {
				pack.Cards = append(pack.Cards, int32(0))
			}
			// 生成棋数据
			pack.Chess = e.chess.GetChess()
			pack.Act = e.chess.GetAct()
			pack.Castling = e.chess.GetCastling()
			pack.CambodianMove = e.chess.GetCambodianMove()
			pack.Enpassant = int32(e.chess.GetEnPassant())
			pack.ChessRound = int32(e.chess.GetRound())
			pack.Check = e.chess.GetCheck()
			pack.Checkmate = e.chess.GetCheckmate()
			proto.SetDefaults(pack)
			seat.SendToClient(int(chesstitians.ChesstitiansPacketID_PACKET_SCChesstitiansCard), pack)
		}
	}
}

// PlayChess 判断客户端发来的行棋操作，返回是否合法
func (e *SceneEx) PlayChess(fromTo []int64) bool {
	fromIdx, toIdx := int(fromTo[0]), int(fromTo[1])
	// 判断该谁走
	// 检查棋子本身能不能走
	if !e.chess.CanMove(fromIdx, toIdx) {
		logger.Logger.Errorf("非法行棋(棋子本身的路线错误) %v %v %v", fromIdx, toIdx, e.chess.GetPiece(fromIdx))
		return false
	}
	// 王被吃
	toPiece := e.chess.GetPiece(toIdx)
	if toPiece == rule.WK { // 白王被吃，标记黑方获胜
		for _, seat := range e.seats {
			if seat != nil {
				if seat.isBlack {
					e.winSnId = seat.GetSnId()
				}
			}
		}
	} else if toPiece == rule.BK { // 黑王被吃，标记白方获胜
		for _, seat := range e.seats {
			if !seat.isBlack {
				e.winSnId = seat.GetSnId()
			}
		}
	}

	c := e.chess.GetPiece(fromIdx)
	e.chess.Move(fromIdx, toIdx)
	e.lastMove = []int32{int32(fromIdx), int32(toIdx)}

	// 将死
	if rule.IsWhite(c) && e.chess.IsCheckmate(true) { // 白方胜
		e.winSnId = e.GetSeatByCKey("w").GetSnId()
	} else if !rule.IsWhite(c) && e.chess.IsCheckmate(false) { // 黑方胜
		e.winSnId = e.GetSeatByCKey("b").GetSnId()
	}

	// 无子可动平局
	if rule.IsWhite(c) && e.chess.IsStop(false) {
		e.ChangeSceneState(rule.SceneStateBilled)
	} else if rule.IsBlack(c) && e.chess.IsStop(true) {
		e.ChangeSceneState(rule.SceneStateBilled)
	}
	return true
}

// NextOpPos 轮换到下一个操作的玩家
func (e *SceneEx) NextOpPos() {
	lastPlayer := e.seats[e.opPos]
	if !lastPlayer.lastTime.IsZero() {
		lastPlayer.totalTime += int64(time.Now().Sub(lastPlayer.lastTime).Seconds())
	}

	e.opPos = (e.opPos + 1) % rule.MaxNumOfPlayer
	e.chess.NextAct()
	e.chess.PrintChess()
	s := e.chess.GenFen()
	println(s)

	// 计步
	if e.IsStep() {
		curPlayer := e.seats[e.opPos]
		if curPlayer.SnId == e.stepSnId {
			e.stepNum++
		}
		if e.IsKingStep() {
			e.stepKing++
			if e.stepKing == 2 {
				e.stepNum++
				e.stepKing = 0
			}
		}

		if e.stepNum > e.stepLimit {
			// 计步结束，平局
			e.ChangeSceneState(rule.SceneStateBilled)
			return
		}
	}

	// 检查孤王计步
	// 任何一方只剩一个王时，开始计步；取消残局计步；确定回合限制
	if !e.IsKingStep() {
		if e.chess.Has(rule.WK) && e.chess.GetWhiteNum() == 1 ||
			e.chess.Has(rule.BK) && e.chess.GetBlackNum() == 1 {
			if e.IsStep() {
				e.cancelStep()
			}
			e.StartKingStep()
		}
	}
	// 记录操作开始时间
	e.seats[e.opPos].lastTime = time.Now()
}

// IsStep 是否计步中
func (e *SceneEx) IsStep() bool {
	if e.stepLimit > 0 {
		return true
	}
	return false
}

func (e *SceneEx) IsKingStep() bool {
	if e.stepSnId == 0 && e.stepLimit > 0 {
		return true
	}
	return false
}

// CanStep 是否可以计步
func (e *SceneEx) CanStep() bool {
	if e.IsStep() {
		return false
	}
	// 双方都没有兵
	if e.chess.GetChessNum(rule.WP) == 0 && e.chess.GetChessNum(rule.BP) == 0 {
		return true
	}
	return false
}

// StartStep 玩家开始计步
func (e *SceneEx) StartStep(p *PlayerEx) bool {
	if !e.CanStep() {
		return false
	}

	e.stepSnId = p.GetSnId()
	e.stepNum = 1
	e.stepLimit = rule.PlayerStepLimit
	return true
}

// StartKingStep 开始孤王计步
func (e *SceneEx) StartKingStep() {
	e.stepKing = 0
	c := rule.White
	if e.chess.Has(rule.WK) && e.chess.GetWhiteNum() == 1 {
		c = rule.Black
	}

	//双车：8回合
	//单车：16回合
	//双象：22回合
	//双马：32回合
	//单象：44回合
	//单马：64回合
	//其他情况：64回合
	r := e.chess.GetChessNum(rule.ToPiece(c, rule.R))
	if r == 2 {
		e.stepLimit = 8
	} else if r == 1 {
		e.stepLimit = 16
	}

	if e.stepLimit == 0 {
		s := e.chess.GetChessNum(rule.ToPiece(c, rule.S))
		if s == 2 {
			e.stepLimit = 22
		} else {
			n := e.chess.GetChessNum(rule.ToPiece(c, rule.N))
			if n == 2 {
				e.stepLimit = 32
			} else if s == 1 {
				e.stepLimit = 44
			} else if n == 1 {
				e.stepLimit = 64
			}
		}
	}

	if e.stepLimit == 0 {
		e.stepLimit = 64
	}

	// 起始回合数
	//e.stepNum = e.chess.GetWhiteNum() + e.chess.GetBlackNum() + 1
	e.stepNum = 1
}

// cancelStep 取消计步
func (e *SceneEx) cancelStep() {
	e.stepSnId = 0
	e.stepNum = 0
	e.stepLimit = 0
}

// CancelStep 玩家取消计步
func (e *SceneEx) CancelStep(p *PlayerEx) bool {
	if !e.IsStep() {
		return false
	}
	if e.stepSnId != p.GetSnId() {
		return false
	}
	e.cancelStep()
	return true
}

// RequestDraw 玩家求和
func (e *SceneEx) RequestDraw(p *PlayerEx) bool {
	if e.drawSnId > 0 {
		return false
	}
	e.drawSnId = p.GetSnId()
	return true
}

// RefuseDraw 玩家拒绝求和
func (e *SceneEx) RefuseDraw(p *PlayerEx) bool {
	if e.drawSnId == 0 {
		return false
	}
	if e.drawSnId == p.GetSnId() {
		return false
	}
	e.drawSnId = 0
	return true
}

// AgreeDraw 玩家同意求和
func (e *SceneEx) AgreeDraw(p *PlayerEx) bool {
	if e.drawSnId == 0 {
		return false
	}
	if e.drawSnId == p.GetSnId() {
		return false
	}
	e.drawSnId = 0
	e.ChangeSceneState(rule.SceneStateBilled)
	return true
}

// CancelDraw 撤销求和
func (e *SceneEx) CancelDraw(p *PlayerEx) bool {
	if e.drawSnId == 0 {
		return false
	}
	if e.drawSnId != p.GetSnId() {
		return false
	}
	e.drawSnId = 0
	return true
}

func (e *SceneEx) GetChessRank(p *PlayerEx) int32 {
	i := sort.Search(len(e.ChessRank), func(i int) bool {
		return int64(e.ChessRank[i]) > p.ChessGrade
	})
	if i == len(e.ChessRank) {
		return e.ChessRank[i-1]
	}
	i = i - 1
	if i < 0 {
		i = 0
	}
	if i < len(e.ChessRank) {
		return e.ChessRank[i]
	}
	return 0
}

func (e *SceneEx) GetChessRankNext(p *PlayerEx) int32 {
	i := sort.Search(len(e.ChessRank), func(i int) bool {
		return int64(e.ChessRank[i]) > p.ChessGrade
	})
	if i == len(e.ChessRank) {
		return e.ChessRank[i-1]
	}
	return e.ChessRank[i]
}

func (e *SceneEx) ToBilled(p1, p2 *PlayerEx, isWin int) (*chesstitians.ChesstitiansPlayerGameBilled, *model.ChesstitiansPerson) {
	// 获取结算规则
	var typeId int32
	var billedRule, billedRuleDraw *server.DB_ChessBilledRules

	// 人机对战不结算
	if e.GetGameId() != common.GameId_ChesstitiansCambodianRobot {
		winRank := e.GetChessRank(p1)
		loseRank := e.GetChessRank(p2)
		if winRank > loseRank {
			typeId = rule.BilledTypeGT
		} else if winRank < loseRank {
			typeId = rule.BilledTypeLT
		} else {
			typeId = rule.BilledTypeEQ
		}

		for _, v := range srvdata.PBDB_ChessBilledRulesMgr.Datas.Arr {
			if v.GetTypeId() == typeId {
				billedRule = v
			}
			if v.GetTypeId() == rule.BilledTypeEQ {
				billedRuleDraw = v
			}
		}
	}

	p1.isWin = int32(isWin)
	p1.winCoin = 0
	p1.taxCoin = 0
	p1.winTimes = 0
	p1.winScore = 0
	p1.otherScore = 0
	p1.nextRank = 0

	switch isWin {
	case rule.Win:
		// 金币和税收
		gainScore := int64(float64(e.GetBaseScore()) * float64(10000-e.GetDBGameFree().GetTaxRate()) / 10000.0)
		p1.winCoin = gainScore
		p1.taxCoin = int64(e.GetBaseScore()) - gainScore

		// 连赢次数
		winTimes := p1.GetGameFreeIdData(e.KeyGamefreeId).Statics.WinGameTimesNum
		e.AddCoin(p1, gainScore, common.GainWay_CoinSceneWin, 0, "system", e.GetSceneName())
		p1.winTimes = int32(winTimes + 1)

		var winScore int32
		if billedRule != nil {
			// 连赢积分
			if p1.GetGameFreeIdData(e.KeyGamefreeId).Statics.GetInt(rule.StaticsChessTime)+1 >= int(billedRule.GetWinTimes()) {
				p1.GetGameFreeIdData(e.KeyGamefreeId).Statics.SetInt(rule.StaticsChessTime, 0)
				p1.AddChessGrade(int64(billedRule.OtherScore))
				p1.otherScore = billedRule.OtherScore
				winScore += billedRule.OtherScore
			} else {
				p1.GetGameFreeIdData(e.KeyGamefreeId).Statics.Incr(rule.StaticsChessTime)
			}
			// 总积分
			e.AddChessGrade(p1, int64(billedRule.GetWinScore()))
			// 本局积分
			winScore += billedRule.GetWinScore()
			p1.winScore = winScore
		}

	case rule.Lose:
		e.AddCoin(p1, int64(-e.GetDBGameFree().GetBaseScore()), common.GainWay_CoinSceneLost, 0, "system", e.GetSceneName())
		p1.GetGameFreeIdData(e.KeyGamefreeId).Statics.SetInt(rule.StaticsChessTime, 0)
		p1.winCoin = int64(-e.GetDBGameFree().GetBaseScore())

		if billedRule != nil {
			// 总积分
			e.AddChessGrade(p1, int64(billedRule.GetLoseScore()))
			// 本局积分
			p1.winScore = proto.Int32(billedRule.GetLoseScore())
		}

	case rule.Draw:
		p1.GetGameFreeIdData(e.KeyGamefreeId).Statics.SetInt(rule.StaticsChessTime, 0)
		if billedRule != nil {
			// 总积分
			e.AddChessGrade(p1, int64(billedRule.GetDrawScore()))
			// 本局积分
			p1.winScore = proto.Int32(billedRule.GetDrawScore())
		}
	}

	if billedRuleDraw != nil {
		// 还有几局晋级
		n := math.Ceil(float64(int64(e.GetChessRankNext(p1))-p1.ChessGrade) / float64(billedRuleDraw.GetWinScore()))
		p1.nextRank = int32(n)
	}

	// 人机对战，没有输赢分，没有积分变化
	if e.GetGameId() == common.GameId_ChesstitiansCambodianRobot {
		p1.winCoin = 0
		p1.taxCoin = 0
		p1.winScore = 0
		p1.otherScore = 0
	}

	billData := &chesstitians.ChesstitiansPlayerGameBilled{
		SnId:          proto.Int32(p1.SnId),
		WinCoin:       proto.Int64(p1.winCoin),
		GameCoin:      proto.Int64(p1.GetCoin()),
		IsWin:         proto.Int32(p1.isWin),
		WinTimes:      proto.Int32(p1.winTimes),
		OtherScore:    proto.Int32(p1.otherScore),
		NextRank:      proto.Int32(p1.nextRank),
		Score:         proto.Int32(int32(p1.ChessGrade)),
		WinScore:      proto.Int32(p1.winScore),
		OldChessGrade: proto.Int64(p1.oldGrade),
	}

	chessPerson := &model.ChesstitiansPerson{
		UserId:      p1.SnId,
		UserIcon:    p1.Head,
		Platform:    p1.Platform,
		Channel:     p1.Channel,
		Promoter:    p1.BeUnderAgentCode,
		PackageTag:  p1.PackageID,
		InviterId:   p1.InviterId,
		WBLevel:     p1.WBLevel,
		IsRob:       p1.IsRob,
		IsFirst:     e.IsPlayerFirst(e.GetPlayer(p1.SnId)),
		IsLeave:     false,
		IsWin:       p1.isWin,
		Seat:        p1.GetPos(),
		GainCoin:    p1.winCoin,
		GainTaxCoin: p1.taxCoin,
	}
	return billData, chessPerson
}
