package room

import (
	"game/common/baseroom"
	"game/common/config/game"
	"game/common/jackpot"
	modelUser "game/common/model/user"
	"game/common/proto/pb"
	"game/common/rpc"
	"game/common/userBindService"
	"game/server/colorgame/model"
	"github.com/fox/fox/log"
	"github.com/fox/fox/processor"
	"github.com/fox/fox/service"
)

type ColorRoom struct {
	*baseroom.HundredRoom
	userMgr     *baseroom.PlayerMgr
	bindService *userBindService.UserBindService
	gameNo      string

	roomCfg    *game.ColorRoomConfig
	timingCfg  *game.ColorGameTiming
	status     pb.ColorGameStatus
	statusTime int64 // 毫秒时间戳

	prizeAreaRange   []*pb.ColorPrizeAreaRange // 五个档位(single有三个加上double,three两个)的赔率范围
	endBetAreaMul    []*pb.ColorBetAreaMul     // 下注结束后，每个区域更新是否爆奖以及实际赔率
	ntfOpenThreeDice *pb.NtfColorOpenThreeDice // 开骰子的消息
	winBetAreaMul    []*pb.ColorBetAreaMul     // 中奖区域及实际赔率
	jackpotMgr       *jackpot.JackPotMgr       // jackpotValue
	jackpotValue     int64                     // jackpot值
	jackpotUser      map[int64]int64           // 本局中jackpot的玩家，用于游戏内广播
	bigUsers         []*pb.ColorBigUser        // 前6个大客户
	trend            [][]pb.ColorType          // 路途
	betAreaInfo      []*pb.ColorBetAreaInfo    // 本局每个投注区域信息
}

func newColorRoom(id, roomType int, srv service.IService, userMgr *baseroom.PlayerMgr, bindService *userBindService.UserBindService) (baseroom.IRoom, pb.ErrCode) {
	// 初始化房间核心数据
	gameId := int(pb.ServiceTypeId_STI_ColorGame)
	hundredRoom, code := baseroom.NewHundredRoom(id, roomType, gameId, srv)
	if code != pb.ErrCode_OK {
		log.ErrorF("new color room err code:%v", code)
		return nil, code
	}

	rm := &ColorRoom{
		HundredRoom:   hundredRoom,
		userMgr:       userMgr,
		bindService:   bindService,
		roomCfg:       &game.ColorRoomConfig{},
		timingCfg:     &game.ColorGameTiming{},
		status:        0,
		statusTime:    0,
		jackpotValue:  0,
		endBetAreaMul: make([]*pb.ColorBetAreaMul, 0, len(pb.ColorBetArea_name)),
		winBetAreaMul: nil,
		jackpotMgr:    jackpot.NewJackpotMgr(gameId, model.UserRedis),
	}

	// 初始化数据在OnInit之前完成
	rm.trend = rm.initGameTrend()
	rm.resetGameData()
	rm.OnInit()
	return rm, code
}

func (rm *ColorRoom) OnInit() {
	rm.RegisterMessages(processor.RegisterMetas{
		pb.MsgId_ReqMatchRoomId:    {pb.ReqMatchRoom{}, rm.onMatchRoom},
		pb.MsgId_ReqColorBettingId: {pb.ReqColorBetting{}, rm.onBet},
		pb.MsgId_ReqEnterRoomId:    {pb.ReqEnterRoom{}, rm.onEnterRoom},
		pb.MsgId_ReqLeaveRoomId:    {pb.ReqLeaveRoom{}, rm.onLeaveRoom},
		pb.MsgId_NtfUserOfflineId:  {pb.NtfUserOffline{}, rm.onUserOffline},
	})
	rm.RegisterTimerMessages(processor.RegisterTimerMetas{
		TtGameStart:      rm.gameStart,
		TtStartBetting:   rm.gameStartBetting,
		TtEndBet:         rm.gameEndBetting,
		TtOpenThreeDices: rm.gameOpenThreeDices,
		TtSettle:         rm.gameSettle,
		TtSecond:         rm.onSecond,
	})

	rm.gameStart()
	return
}

// 游戏开始前重置游戏数据
func (rm *ColorRoom) resetGameData() {
	rm.updateConfig()
	rm.initEndBetAreaMul()
	rm.ntfOpenThreeDice = &pb.NtfColorOpenThreeDice{}
	rm.jackpotValue = rm.jackpotMgr.GetJackpot()
	rm.bigUsers = rm.bigUsers[0:0]
	rm.betAreaInfo = rm.betAreaInfo[:0]
	for area := pb.ColorBetArea_CBA_Yellow; area < pb.ColorBetArea_CBA_Green3; area++ {
		rm.betAreaInfo = append(rm.betAreaInfo, &pb.ColorBetAreaInfo{
			Area:      area,
			TotalBet:  0,
			PlayerNum: 0,
			MyBet:     0,
		})
	}
	rm.initPrizeAreaRange()

	// 清理玩家身上数据
	rm.RangePlayer(func(u baseroom.IPlayer) bool {
		GetPlayer(u).resetData()
		return true
	})

	// 游戏开始前清理不下注玩家
	rm.kickoutUsers()
}

func (rm *ColorRoom) GameNo() string {
	return rm.gameNo
}

// 当前拥有金币
func (rm *ColorRoom) GetGold(user *ColorPlayer) int64 {
	return user.Gold
}

// 加减金币 预加减，没有真实向db服请求
func (rm *ColorRoom) AddGold(user *ColorPlayer, add int64) (int64, bool) {
	if user.Gold+add < 0 {
		return user.Gold, false
	}
	user.Gold += add
	return user.Gold, true
}

// 从db服拿到最新数据，重置玩家数据
func (rm *ColorRoom) setGold(user *ColorPlayer, gold int64) {
	user.Gold = gold
}

// 加减金币 真实抠钱
func (rm *ColorRoom) rpcPayoutGold(user *ColorPlayer, add int64, reason string) (int64, bool) {
	resName := "gold"
	res, code := rpc.RpcAddUserRes(rm.bindService, rm.GetService(), user.Id(), &modelUser.AddUserRes{
		GameId: rm.GameId(),
		GameNo: rm.GameNo(),
		Reason: reason,
		AddRes: map[string]int64{
			resName: add,
		},
	})
	if code == pb.ErrCode_OK {
		return res[resName], true
	}
	return 0, false
}
