package smallrocket

import (
	"time"

	rule "mongo.games.com/game/gamerule/smallrocket"
	"mongo.games.com/game/gamesrv/base"
	"mongo.games.com/game/proto"
	"mongo.games.com/game/protocol/smallrocket"

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

type PlayerData struct {
	SnId  int32
	Head  int32  //头像框
	VIP   int32  //VIP帐号 等级
	Name  string //名字
	Sex   int32  //性别
	IsRob bool

	Coin     int64
	gainCoin int64 //本局赢的金币
	taxCoin  int64 //本局税收
	isBilled bool  //是否结算
	CurIsWin int64 //当局输赢   负数：输  正数：赢

	InviterId        int32             //邀请人Id
	BeUnderAgentCode string            //隶属经销商（推广人）
	CurBetData       []*rule.BetDataEx // 本局的下注信息
	IsPlayerFirst    bool

	Platform  string //平台
	Channel   string //渠道信息
	PackageID string //推广包标识 对应客户端的packagetag
	flag      int
}

type SceneEx struct {
	*base.Scene                        // 场景
	logic        *rule.Logic           // 小火箭算法
	players      map[int32]*PlayerEx   // 玩家信息
	PlayerBackup map[int32]*PlayerData // 本局离场玩家数据备份
	seats        []*PlayerEx           // 本局游戏中的玩家状态数据

	TotalBetPlayer      int           // 本局下注人数
	NextTotalBetPlayers int           // 下局投注人数
	gamePlayerNum       int           // 参与游戏人数
	BoomMul             float64       // 本局火箭飞行爆炸倍数
	BombRandomNum       int           // 本局火箭飞行随机数
	startTime           time.Duration // 本局开始时间
	bombTime            time.Duration // 本局火箭爆炸时间

	HistoryBombMul *rule.SequentialQueue // 房间历史爆炸倍数记录

	RoundId  int // 局数，第几局
	robotNum int // 参与游戏的机器人数量
	logid    string
}

// 游戏是否能开始
func (this *SceneEx) CanStart() bool {
	//人数>=1自动开始
	if len(this.players) >= 0 && (this.GetRealPlayerNum() >= 0 || this.IsPreCreateScene()) {
		return true
	}
	return false
}

// 从房间删除玩家
func (this *SceneEx) delPlayer(p *base.Player) {
	if p, exist := this.players[p.SnId]; exist {
		this.seats[p.GetPos()] = nil
		delete(this.players, p.SnId)
	}
}

// 广播玩家离开
func (this *SceneEx) BroadcastPlayerLeave(p *base.Player, reason int) {
	scLeavePack := &smallrocket.SCSmallRocketPlayerLeave{
		Pos: proto.Int(p.GetPos()),
	}
	proto.SetDefaults(scLeavePack)

	this.Broadcast(int(smallrocket.SmallRocketPacketID_PACKET_SC_SMALLROCKET_PlayerLeave), scLeavePack, p.GetSid())
}

// 玩家离开事件
func (this *SceneEx) OnPlayerLeave(p *base.Player, reason int) {
	this.delPlayer(p)
	this.BroadcastPlayerLeave(p, reason)
}
func (this *SceneEx) SceneDestroy(force bool) {
	//销毁房间
	this.Scene.Destroy(force)
}

func (e *SceneEx) playerOpPack(snId int32, opcode int, opRetCode smallrocket.OpResultCode, params []int64, betDataInfo []*rule.BetDataEx) *smallrocket.SCSmallRocketOp {
	pack := &smallrocket.SCSmallRocketOp{
		SnId:      proto.Int32(snId),
		OpCode:    proto.Int32(int32(opcode)),
		Params:    params,
		OpRetCode: smallrocket.OpResultCode_OPRC_Success,
	}

	if betDataInfo != nil {
		for i := 0; i < len(betDataInfo); i++ {

			tempBetEml := &smallrocket.BetDataInfo{
				BetVal:           proto.Int64(betDataInfo[i].BetVal),
				TakeMul:          proto.Float32(float32(betDataInfo[i].TakeMul)),
				IsCurBet:         proto.Bool(betDataInfo[i].IsCurBet),
				IsNextBet:        proto.Bool(betDataInfo[i].IsNextBet),
				IsTakeGain:       proto.Bool(betDataInfo[i].IsTakeGain),
				IsAutoBetAndTake: proto.Bool(betDataInfo[i].IsAutoBetAndTake),
			}

			pack.BetDataArr = append(pack.BetDataArr, tempBetEml)
		}
	}
	proto.SetDefaults(pack)
	return pack
}

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

func (this *SceneEx) SubBetPlayerNum() {
	this.TotalBetPlayer--
	if this.TotalBetPlayer < 0 {
		this.TotalBetPlayer = 0
	}
}

// 房间信息打包
func (this *SceneEx) SamllRocketCreateRoomInfoPacket(s *base.Scene, p *base.Player) interface{} {
	pack := &smallrocket.SCSmallRocketRoomInfo{
		RoomId:         proto.Int(s.GetSceneId()),
		GameId:         proto.Int(s.GetGameId()),
		RoomMode:       proto.Int(s.GetSceneMode()),
		Params:         this.Params,
		State:          proto.Int(s.GetSceneState().GetState()),
		TimeOut:        proto.Int(s.GetSceneState().GetTimeout(s)),
		BombMul:        proto.Float32(float32(0)),
		BombRandomNum:  proto.Int(0),
		TotalPlayer:    proto.Int(len(this.players)),
		RoundId:        proto.Int(this.RoundId),
		TotalBetPlayer: proto.Int(this.TotalBetPlayer),
		ParamsEx:       nil,
		GameFreeId:     0,
		BaseScore:      proto.Int32(this.GetBaseScore()),
	}

	// 历史积分添加
	if this.HistoryBombMul != nil {
		hisBoomMul := this.HistoryBombMul.GetFloat64Items()
		for i := 0; i < len(hisBoomMul); i++ {
			pack.RoundBoomMuHistory = append(pack.RoundBoomMuHistory, float32(hisBoomMul[i]))
		}
	}

	// 玩家信息
	for _, playerEx := range this.players {

		if p.SnId == playerEx.SnId {
			pd := &smallrocket.SmallRocketPlayerData{
				SnId:        proto.Int32(playerEx.SnId),
				Name:        proto.String(playerEx.Name),
				Head:        proto.Int32(playerEx.Head),
				Sex:         proto.Int32(playerEx.Sex),
				Coin:        proto.Int64(playerEx.Coin),
				Flag:        proto.Int(playerEx.GetFlag()),
				HeadOutLine: proto.Int32(playerEx.HeadOutLine),
				VIP:         proto.Int32(playerEx.VIP),

				WinCoin: proto.Int64(playerEx.gainCoin),
			}

			if playerEx.betData != nil {
				for i := 0; i < len(playerEx.betData); i++ {

					tempBetEml := &smallrocket.BetDataInfo{
						BetVal:           proto.Int64(playerEx.betData[i].BetVal),
						TakeMul:          proto.Float32(float32(playerEx.betData[i].TakeMul)),
						IsCurBet:         proto.Bool(playerEx.betData[i].IsCurBet),
						IsNextBet:        proto.Bool(playerEx.betData[i].IsNextBet),
						IsTakeGain:       proto.Bool(playerEx.betData[i].IsTakeGain),
						IsAutoBetAndTake: proto.Bool(playerEx.betData[i].IsAutoBetAndTake),
					}

					pd.BetDataArr = append(pd.BetDataArr, tempBetEml)
				}
			}
			pack.Players = append(pack.Players, pd)
		}
	}

	//// 备份的玩家信息
	//for _, playerEx := range this.PlayerBackup {
	//	if playerEx != nil {
	//		continue
	//	}
	//
	//	pd := &smallrocket.SmallRocketPlayerData{
	//		SnId: proto.Int32(playerEx.SnId),
	//		Name: proto.String(playerEx.Name),
	//		Head: proto.Int32(playerEx.Head),
	//		Sex:  proto.Int32(playerEx.Sex),
	//		Coin: proto.Int64(playerEx.Coin),
	//		Flag: proto.Int(playerEx.flag),
	//		VIP:  proto.Int32(playerEx.VIP),
	//
	//		WinCoin: proto.Int64(playerEx.gainCoin),
	//	}
	//
	//	if s.SceneState.GetState() == rule.SmallRocketSceneStateBilled {
	//		pd.WinCoin = playerEx.gainCoin
	//	}
	//
	//	// 下注信息
	//	if playerEx.betData != nil {
	//		for i := 0; i < len(playerEx.betData); i++ {
	//
	//			tempBetEml := &smallrocket.BetDataInfo{
	//				BetVal:           proto.Int64(playerEx.betData[i].BetVal),
	//				TakeMul:          proto.Float32(float32(playerEx.betData[i].TakeMul)),
	//				IsCurBet:         proto.Bool(playerEx.betData[i].IsCurBet),
	//				IsNextBet:        proto.Bool(playerEx.betData[i].IsNextBet),
	//				IsTakeGain:       proto.Bool(playerEx.betData[i].IsTakeGain),
	//				IsAutoBetAndTake: proto.Bool(playerEx.betData[i].IsAutoBetAndTake),
	//			}
	//
	//			pd.BetDataArr = append(pd.BetDataArr, tempBetEml)
	//		}
	//	}
	//
	//	pack.Players = append(pack.Players, pd)
	//}

	proto.SetDefaults(pack)
	if p != nil {
		p.SyncFlag()
	}

	logger.Logger.Trace("SCSmallRocketRoomInfo:", pack)
	return pack
}

func NewSmallRocketSceneData(s *base.Scene) *SceneEx {
	sceneEx := &SceneEx{
		Scene:          s,
		logic:          new(rule.Logic),
		players:        make(map[int32]*PlayerEx),
		seats:          make([]*PlayerEx, s.GetPlayerNum()),
		PlayerBackup:   make(map[int32]*PlayerData),
		HistoryBombMul: rule.NewSequentialQueue(5),
	}

	return sceneEx
}

func (this *SceneEx) init() bool {
	this.Clear()
	//this.logic.CalBoomTime(rule.SmallRocketBombMulMaxE)
	return true
}

func (this *SceneEx) GetBaseScore() int32 { //游戏底分
	if this.DbGameFree != nil {
		return this.DbGameFree.GetBaseScore()
	}
	return 1
}

func (this *SceneEx) GetBetMaxCoin() int32 { //游戏底分
	if this.DbGameFree != nil {
		return this.DbGameFree.GetBaseScore() * 10000
	}
	return 1 * 10000
}

// 检查下注是否合法
func (this *SceneEx) CheckBetOp(betVal int64, takeMul int64) bool { //游戏底分

	if betVal <= 0 || takeMul < rule.SmallRocketPlayerTakeMulMax {
		return false
	}

	if betVal < int64(this.GetBaseScore()) || betVal > int64(this.GetBetMaxCoin()) {
		return false
	}

	return true
}

func (this *SceneEx) Clear() {
	this.gamePlayerNum = 0
	this.robotNum = 0
	this.BoomMul = 0

	this.bombTime = 0
	this.BombRandomNum = rule.SmallRocketPlayerTransDataMul
	this.startTime = rule.SmallRocketSceneStartTimeout

	this.PlayerBackup = make(map[int32]*PlayerData)

	this.TotalBetPlayer = 0
	this.NextTotalBetPlayers = 0
	this.HistoryBombMul.Clear()
	this.RoundId = 0

	for i := 0; i < this.GetPlayerNum(); i++ {
		if this.seats[i] != nil {
			this.seats[i].Clear(this.GetBaseScore())
		}
	}
}

func (this *SceneEx) BackupPlayer(p *PlayerEx, isBilled bool) {
	this.PlayerBackup[p.SnId] = &PlayerData{
		SnId:             p.SnId,
		gainCoin:         p.gainCoin,
		taxCoin:          p.taxCoin,
		isBilled:         isBilled,
		IsRob:            p.IsRob,
		Coin:             p.Coin,
		Head:             p.Head,
		flag:             p.GetFlag(),
		Platform:         p.Platform,
		Channel:          p.Channel,
		PackageID:        p.PackageID,
		CurIsWin:         p.CurIsWin,
		Name:             p.Name,
		Sex:              p.Sex,
		VIP:              p.VIP,
		InviterId:        p.InviterId,
		IsPlayerFirst:    this.IsPlayerFirst(p.Player),
		BeUnderAgentCode: p.BeUnderAgentCode,
		CurBetData:       p.CurBetData,
	}
}
