package fruits

import (
	"math"
	"time"

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

	"mongo.games.com/game/common"
	"mongo.games.com/game/gamerule/fruits"
	"mongo.games.com/game/gamesrv/base"
	"mongo.games.com/game/proto"
	protocol "mongo.games.com/game/protocol/fruits"
)

// ////////////////////////////////////////////////////////////
var ScenePolicyFruitsSington = &ScenePolicyFruits{}

type ScenePolicyFruits struct {
	base.BaseScenePolicy
	states [fruits.FruitsStateMax]base.SceneState
}

// 创建场景扩展数据
func (this *ScenePolicyFruits) CreateSceneExData(s *base.Scene) interface{} {
	sceneEx := NewFruitsSceneData(s)
	if sceneEx != nil {
		if sceneEx.GetInit() {
			s.SetExtraData(sceneEx)
		}
	}
	return sceneEx
}

// 创建玩家扩展数据
func (this *ScenePolicyFruits) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} {
	playerEx := &FruitsPlayerData{Player: p}
	p.SetExtraData(playerEx)
	return playerEx
}

// 场景开启事件
func (this *ScenePolicyFruits) OnStart(s *base.Scene) {
	logger.Logger.Trace("(this *ScenePolicyFruits) OnStart, sceneId=", s.GetSceneId())
	sceneEx := NewFruitsSceneData(s)
	if sceneEx != nil {
		if sceneEx.GetInit() {
			s.SetExtraData(sceneEx)
			s.ChangeSceneState(fruits.FruitsStateStart)
		}
	}
}

// 场景关闭事件
func (this *ScenePolicyFruits) OnStop(s *base.Scene) {
	logger.Logger.Trace("(this *ScenePolicyFruits) OnStop , sceneId=", s.GetSceneId())
}

// 场景心跳事件
func (this *ScenePolicyFruits) OnTick(s *base.Scene) {
	if s == nil {
		return
	}
	if s.GetSceneState() != nil {
		s.GetSceneState().OnTick(s)
	}
}

// 玩家进入事件
func (this *ScenePolicyFruits) OnPlayerEnter(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *ScenePolicyFruits) OnPlayerEnter, sceneId=", s.GetSceneId(), " player=", p.Name)
	if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
		playerEx := &FruitsPlayerData{Player: p}
		playerEx.init()
		playerEx.Clear()

		sceneEx.players[p.SnId] = playerEx

		p.SetExtraData(playerEx)
		FruitsSendRoomInfo(s, sceneEx, playerEx)

		s.FirePlayerEvent(p, base.PlayerEventEnter, nil)
	}
}

// 玩家离开事件
func (this *ScenePolicyFruits) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *ScenePolicyFruits) OnPlayerLeave, sceneId=", s.GetSceneId(), " player=", p.SnId)
	if sceneEx, ok := s.ExtraData.(*FruitsSceneData); ok {
		s.FirePlayerEvent(p, base.PlayerEventLeave, nil)
		sceneEx.OnPlayerLeave(p, reason)
	}
}

// 玩家掉线
func (this *ScenePolicyFruits) OnPlayerDropLine(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *ScenePolicyFruits) OnPlayerDropLine, sceneId=", s.GetSceneId(), " player=", p.SnId)
	s.FirePlayerEvent(p, base.PlayerEventDropLine, nil)
}

// 玩家重连
func (this *ScenePolicyFruits) OnPlayerRehold(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *ScenePolicyFruits) OnPlayerRehold, sceneId=", s.GetSceneId(), " player=", p.SnId)
	if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
		if playerEx, ok := p.GetExtraData().(*FruitsPlayerData); ok {
			FruitsSendRoomInfo(s, sceneEx, playerEx)
		}
	}
}

// 返回房间
func (this *ScenePolicyFruits) OnPlayerReturn(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *ScenePolicyFruits) OnPlayerReturn, GetSceneId()=", s.GetSceneId(), " player=", p.Name)
	if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
		if playerEx, ok := p.GetExtraData().(*FruitsPlayerData); ok {
			//if p.IsMarkFlag(base.PlayerState_Auto) {
			//	p.UnmarkFlag(base.PlayerState_Auto)
			//	p.SyncFlag()
			//}
			//发送房间信息给自己
			FruitsSendRoomInfo(s, sceneEx, playerEx)
			s.FirePlayerEvent(p, base.PlayerEventReturn, nil)
		}
	}
}

func FruitsSendRoomInfo(s *base.Scene, sceneEx *FruitsSceneData, playerEx *FruitsPlayerData) {
	pack := FruitsCreateRoomInfoPacket(s, sceneEx, playerEx)
	logger.Logger.Trace("RoomInfo: ", pack)
	playerEx.SendToClient(int(protocol.FruitsPID_PACKET_FRUITS_SCFruitsRoomInfo), pack)
}
func FruitsCreateRoomInfoPacket(s *base.Scene, sceneEx *FruitsSceneData, playerEx *FruitsPlayerData) interface{} {
	//房间信息
	pack := &protocol.SCFruitsRoomInfo{
		RoomId:     proto.Int(s.SceneId),
		GameId:     proto.Int(s.GameId),
		RoomMode:   proto.Int(s.SceneMode),
		SceneType:  proto.Int(s.SceneType),
		Params:     s.Params,
		NumOfGames: proto.Int(sceneEx.NumOfGames),
		State:      proto.Int(s.SceneState.GetState()),
		ParamsEx:   s.DbGameFree.OtherIntParams,
		GameFreeId: proto.Int32(s.DbGameFree.Id),
		//BetLimit:   s.DbGameFree.BetLimit,
	}

	//自己的信息
	if playerEx != nil {
		pd := &protocol.FruitsPlayerData{
			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),
			Pos:         proto.Int(playerEx.Pos),
			Flag:        proto.Int(playerEx.GetFlag()),
			City:        proto.String(playerEx.City),
			HeadOutLine: proto.Int32(playerEx.HeadOutLine),
			VIP:         proto.Int32(playerEx.VIP),
		}
		pack.Player = pd
		pack.NowGameState = proto.Int(playerEx.gameState)
		pack.BetIdx = proto.Int(playerEx.betIdx)
		pack.FreeTimes = proto.Int(playerEx.freeTimes)
		pack.MaryFreeTimes = proto.Int(playerEx.maryFreeTimes)
		//玛丽
		pack.MaryTotalWin = proto.Int64(playerEx.winOutMaryCoin + playerEx.winMidMaryCoin)
		pack.Cards = playerEx.result.EleValue
		if playerEx.maryFreeTimes > 0 && playerEx.result != nil {
			pack.MaryWinId = proto.Int32(playerEx.result.MaryOutSide)
			pack.MaryCards = playerEx.result.MaryMidArray
		}
		//免费 当局的
		if playerEx.freeTimes > 0 && playerEx.result != nil {
			pack.Cards = playerEx.result.EleValue
		}
		pack.WinLineCoin = proto.Int64(playerEx.winLineCoin)
		pack.WinJackpot = proto.Int64(playerEx.winNowJackPotCoin)
		pack.WinEle777Coin = proto.Int64(playerEx.winEle777Coin)
		pack.FreeTotalWin = proto.Int64(playerEx.winFreeCoin)
		pack.WinRate = proto.Int64(playerEx.winLineRate + playerEx.JackPot7Rate)
		pack.WinFreeTimes = proto.Int(playerEx.winFreeTimes)

		var wl []*protocol.FruitsWinLine
		for _, r := range playerEx.result.WinLine {
			wl = append(wl, &protocol.FruitsWinLine{
				Poss:   r.Poss,
				LineId: proto.Int(r.LineId),
			})
		}
		pack.WinLines = wl
	}
	proto.SetDefaults(pack)
	return pack
}
func (this *ScenePolicyFruits) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	if s == nil || p == nil {
		return false
	}
	logger.Logger.Trace("(this *ScenePolicyFruits) OnPlayerOp, sceneId=", s.GetSceneId(), " player=", p.SnId, " opcode=", opcode, " params=", params)
	if s.GetSceneState() != nil {
		if s.GetSceneState().OnPlayerOp(s, p, opcode, params) {
			p.SetLastOPTimer(time.Now())
			return true
		}
		return false
	}
	return true
}

func (this *ScenePolicyFruits) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *ScenePolicyFruits) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " eventcode=", evtcode, " params=", params)
	if s.GetSceneState() != nil {
		s.GetSceneState().OnPlayerEvent(s, p, evtcode, params)
	}
}

// 当前状态能否换桌
func (this *ScenePolicyFruits) CanChangeCoinScene(s *base.Scene, p *base.Player) bool {
	if s == nil || p == nil {
		return false
	}
	if s.GetSceneState() != nil {
		return s.GetSceneState().CanChangeCoinScene(s, p)
	}
	return false
}

// 状态基类
type SceneBaseStateFruits struct {
}

func (this *SceneBaseStateFruits) GetTimeout(s *base.Scene) int {
	if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
		return int(time.Now().Sub(sceneEx.GetStateStartTime()) / time.Second)
	}
	return 0
}

func (this *SceneBaseStateFruits) CanChangeTo(s base.SceneState) bool {
	return true
}

// 当前状态能否换桌
func (this *SceneBaseStateFruits) CanChangeCoinScene(s *base.Scene, p *base.Player) bool {
	return true
}
func (this *SceneBaseStateFruits) OnEnter(s *base.Scene) {
	if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
		sceneEx.SetStateStartTime(time.Now())
	}
}

func (this *SceneBaseStateFruits) OnLeave(s *base.Scene) {}
func (this *SceneBaseStateFruits) OnTick(s *base.Scene) {
	if time.Now().Sub(s.GameStartTime) > time.Second*3 {
		if sceneEx, ok := s.ExtraData.(*FruitsSceneData); ok {
			prizePool := int64(math.Floor(float64(sceneEx.jackpot.GetTotalSmall()) / 10000))
			pack := &protocol.SCFruitsPrize{
				PrizePool: proto.Int64(prizePool),
			}
			proto.SetDefaults(pack)
			//logger.Logger.Trace("SCFruitsPrize: ", pack)
			s.Broadcast(int(protocol.FruitsPID_PACKET_FRUITS_SCFruitsPrize), pack, 0)
			for _, p := range sceneEx.players {
				if p.IsOnLine() {
					p.leaveTime = 0
					continue
				}
				p.leaveTime++
				if p.leaveTime < 60*2 {
					continue
				}
				//踢出玩家
				sceneEx.PlayerLeave(p.Player, common.PlayerLeaveReason_LongTimeNoOp, true)
			}
		}
		s.GameStartTime = time.Now()
	}
	if sceneEx, ok := s.ExtraData.(*FruitsSceneData); ok {
		//for _, p := range sceneEx.players {
		//	//游戏次数达到目标值
		//	todayGamefreeIDSceneData, _ := p.GetDaliyGameData(int(sceneEx.DbGameFree.GetId()))
		//	if !p.IsRob &&
		//		todayGamefreeIDSceneData != nil &&
		//		sceneEx.DbGameFree.GetPlayNumLimit() != 0 &&
		//		todayGamefreeIDSceneData.GameTimes >= int64(sceneEx.DbGameFree.GetPlayNumLimit()) {
		//		s.PlayerLeave(p.Player, common.PlayerLeaveReason_GameTimes, true)
		//	}
		//}
		if sceneEx.CheckNeedDestroy() {
			for _, player := range sceneEx.players {
				if !player.IsRob {
					if player.freeTimes == 0 && player.maryFreeTimes == 0 {
						//离开有统计
						sceneEx.PlayerLeave(player.Player, common.PlayerLeaveReason_OnDestroy, true)
					}
				}
			}
			if s.GetRealPlayerCnt() == 0 {
				sceneEx.SceneDestroy(true)
			}
		}
	}
	//if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
	//	if time.Now().Sub(sceneEx.mqLogTime) >= time.Minute*1 {
	//		now := time.Now()
	//		sceneEx.mqLogTime = now.Add(-time.Second * time.Duration(now.Second()))
	//
	//		waterVal := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId)
	//		waterVal = int64(math.Floor(float64(waterVal) / float64(fruits.NowByte)))
	//
	//		jkVal1 := int64(math.Floor(float64(sceneEx.jackpot.GetTotalSmall()) / float64(fruits.NowByte)))
	//		base.JackPotMgr.WJackPotUpdate(sceneEx.GetGameFreeId(), sceneEx.Platform, waterVal, jkVal1, 0, 0, 0)
	//	}
	//}
}
func (this *SceneBaseStateFruits) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	return false
}
func (this *SceneBaseStateFruits) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
}

// ////////////////////////////////////////////////////////////
// 开始状态
// ////////////////////////////////////////////////////////////
type SceneStateStartFruits struct {
	SceneBaseStateFruits
}

func (this *SceneStateStartFruits) GetState() int {
	return fruits.FruitsStateStart
}

func (this *SceneStateStartFruits) CanChangeTo(s base.SceneState) bool {
	return false
}

// 当前状态能否换桌
func (this *SceneStateStartFruits) CanChangeCoinScene(s *base.Scene, p *base.Player) bool {
	if playerEx, ok := p.GetExtraData().(*FruitsPlayerData); ok {
		if playerEx.IsOnLine() && (playerEx.freeTimes > 0 || playerEx.maryFreeTimes > 0) {
			return false
		}
	}
	return true
}

func (this *SceneStateStartFruits) GetTimeout(s *base.Scene) int {
	return 0
}

func (this *SceneStateStartFruits) OnEnter(s *base.Scene) {
	this.SceneBaseStateFruits.OnEnter(s)
	if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
		sceneEx.SetGameNowTime(time.Now())
	}
}

// 状态离开时
func (this *SceneStateStartFruits) OnLeave(s *base.Scene) {
	this.SceneBaseStateFruits.OnLeave(s)
	logger.Logger.Tracef("(this *SceneStateStartFruits) OnLeave, sceneid=%v", s.GetSceneId())
}

// 玩家操作
func (this *SceneStateStartFruits) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	logger.Logger.Tracef("(this *SceneStateStartFruits) OnPlayerOp, sceneid=%v params=%v", s.GetSceneId(), params)
	if this.SceneBaseStateFruits.OnPlayerOp(s, p, opcode, params) {
		return true
	}
	if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
		if playerEx, ok := p.GetExtraData().(*FruitsPlayerData); ok {
			switch opcode {
			case fruits.FruitsPlayerOpStart:
				playerEx.Clear()
				if len(params) > 0 {
					//只有开始算操作
					p.LastOPTimer = time.Now()
					idx := int(params[0])
					if len(sceneEx.DbGameFree.GetOtherIntParams()) <= idx {
						pack := &protocol.SCFruitsOp{
							OpCode:    proto.Int(opcode),
							OpRetCode: proto.Int(3),
						}
						playerEx.SendToClient(int(protocol.FruitsPID_PACKET_FRUITS_SCFruitsOp), pack)
						return false
					}
					if playerEx.maryFreeTimes > 0 {
						playerEx.gameState = fruits.MaryGame
						playerEx.maryFreeTimes--
						playerEx.nowMaryTimes++
					} else if playerEx.freeTimes > 0 {
						playerEx.gameState = fruits.FreeGame
						playerEx.freeTimes--
						playerEx.nowFreeTimes++
					}
					//水池上下文环境
					playerEx.cpCtx = base.CoinPoolMgr.GetCoinPoolCtx(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId)
					if playerEx.gameState == fruits.Normal {
						playerEx.freeTotal = 0
						playerEx.betIdx = idx
						playerEx.betCoin = int64(sceneEx.DbGameFree.GetOtherIntParams()[idx])
						playerEx.oneBetCoin = playerEx.betCoin / 9
						//playerEx.isReportGameEvent = true
						playerEx.noWinTimes++

						if playerEx.Coin < int64(s.DbGameFree.GetBetLimit()) {
							//押注限制(低于该值不能押注)
							pack := &protocol.SCFruitsOp{
								OpCode:    proto.Int(opcode),
								OpRetCode: proto.Int(2),
							}
							playerEx.SendToClient(int(protocol.FruitsPID_PACKET_FRUITS_SCFruitsOp), pack)
							return false
						}
						if playerEx.betCoin > playerEx.Coin {
							//金币不足
							pack := &protocol.SCFruitsOp{
								OpCode:    proto.Int(opcode),
								OpRetCode: proto.Int(1),
							}
							playerEx.SendToClient(int(protocol.FruitsPID_PACKET_FRUITS_SCFruitsOp), pack)
							return false
						}
						playerEx.CurrentBet = playerEx.betCoin
						playerEx.CurrentTax = 0
						//SysProfitCoinMgr.PushBetAndSysOut(sceneEx.sysProfitCoinKey, playerEx.betCoin, -playerEx.betCoin)
						//没有免费次数 扣钱
						p.Statics(s.KeyGameId, s.KeyGamefreeId, -playerEx.betCoin, false)
						playerEx.AddCoin(-playerEx.betCoin, common.GainWay_HundredSceneLost, 0, "system", s.GetSceneName())
						sceneEx.AddPrizeCoin(playerEx)
					}
					if !s.Testing {
						//sceneEx.Regulation(playerEx, 0)
					}
					norms, frees, marys, key := sceneEx.GetEleWeight(playerEx.WBState)
					playerEx.weightPos = key
					if playerEx.gameState == fruits.MaryGame {
						playerEx.result.CreateMary(marys)
						playerEx.CreateMary()
					} else if playerEx.gameState == fruits.FreeGame {
						playerEx.freeTotal++
						playerEx.CreateResult(frees, sceneEx)
					} else {
						playerEx.CreateResult(norms, sceneEx)
					}

					sceneEx.Win(playerEx)

					if playerEx.gameState == fruits.FreeGame && playerEx.freeTotal >= 100 {
						playerEx.freeTotal = 0
						playerEx.freeTimes = 0
					}
					//发送结算
					sceneEx.SendBilled(playerEx)

					sceneEx.SaveLog(playerEx, 0)

					if playerEx.gameState == fruits.Normal {
						playerEx.winJackPotCoin = 0
						playerEx.winEle777Coin = 0
						playerEx.winLineCoin = 0
					}
					playerEx.wl = nil
				}
			case fruits.FruitsPlayerOpSwitch:
				if len(params) > 0 && playerEx.freeTimes == 0 && playerEx.maryFreeTimes == 0 {
					idx := int(params[0])
					if len(sceneEx.DbGameFree.GetOtherIntParams()) > idx {
						playerEx.betIdx = idx
						playerEx.betCoin = int64(sceneEx.DbGameFree.GetOtherIntParams()[idx])
						playerEx.oneBetCoin = playerEx.betCoin / 9
					}
				}
			}
		}
	}
	return true
}

// 玩家事件
func (this *SceneStateStartFruits) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
	logger.Logger.Trace("(this *SceneStateStartFruits) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " evtcode=", evtcode)
	this.SceneBaseStateFruits.OnPlayerEvent(s, p, evtcode, params)
	if sceneEx, ok := s.GetExtraData().(*FruitsSceneData); ok {
		switch evtcode {
		case base.PlayerEventEnter:
			prizePool := int64(math.Floor(float64(sceneEx.jackpot.GetTotalSmall()) / 10000))
			pack := &protocol.SCFruitsPrize{
				PrizePool: proto.Int64(prizePool),
			}
			proto.SetDefaults(pack)
			//logger.Logger.Trace("SCFruitsPrize: ", pack)
			p.SendToClient(int(protocol.FruitsPID_PACKET_FRUITS_SCFruitsPrize), pack)
		}
	}
}

func (this *SceneStateStartFruits) OnTick(s *base.Scene) {
	this.SceneBaseStateFruits.OnTick(s)
}

// //////////////////////////////////////////////////////////////////////////////
func (this *ScenePolicyFruits) RegisteSceneState(state base.SceneState) {
	if state == nil {
		return
	}
	stateid := state.GetState()
	if stateid < 0 || stateid >= fruits.FruitsStateMax {
		return
	}
	this.states[stateid] = state
}

func (this *ScenePolicyFruits) GetSceneState(s *base.Scene, stateid int) base.SceneState {
	if stateid >= 0 && stateid < fruits.FruitsStateMax {
		return this.states[stateid]
	}
	return nil
}

func init() {
	//主状态
	ScenePolicyFruitsSington.RegisteSceneState(&SceneStateStartFruits{})
	core.RegisteHook(core.HOOK_BEFORE_START, func() error {
		base.RegisteScenePolicy(common.GameId_Fruits, fruits.RoomMode_Classic, ScenePolicyFruitsSington)
		return nil
	})
}
