package baseroom

import (
	"fmt"
	"game/common/proto/pb"
	"github.com/fox/fox/ipb"
	"github.com/fox/fox/log"
	"github.com/fox/fox/processor"
	"github.com/fox/fox/service"
	"github.com/fox/fox/timer"
	"github.com/golang/protobuf/proto"
	"time"
)

// 百人场
type HundredRoom struct {
	room  *BaseRoom[*BaseSeat]
	users map[int64]IPlayer // 所有玩家
}

func NewHundredRoom(id, roomType, gameId int, srv service.IService) (*HundredRoom, pb.ErrCode) {
	baseRoom, code := NewBaseRoom[*BaseSeat](id, roomType, gameId, 0, srv)
	if code != pb.ErrCode_OK {
		return nil, code
	}
	room := &HundredRoom{
		room:  baseRoom,
		users: make(map[int64]IPlayer),
	}
	return room, pb.ErrCode_OK
}

func (r *HundredRoom) Id() int {
	return r.room.Id()
}

func (r *HundredRoom) RoomType() int {
	return r.room.RoomType()
}

func (r *HundredRoom) GameId() int {
	return r.room.GameId()
}

func (r *HundredRoom) GetService() service.IService {
	return r.room.GetService()
}

// 房间玩家数量
func (r *HundredRoom) GetPlayerNum(playerType PlayerType) int {
	if playerType == PT_All {
		return len(r.users)
	}
	num := 0
	for _, user := range r.users {
		switch playerType {
		case PT_User:
			if !user.IsRobot() {
				num++
			}
		case PT_Robot:
			if user.IsRobot() {
				num++
			}
		}
	}
	return num
}

// 查找玩家所在的座位
func (r *HundredRoom) FindPlayer(uid int64) (IPlayer, bool) {
	u, ok := r.users[uid]
	return u, ok
}

// 添加玩家，如果已存在返回false
func (r *HundredRoom) AddPayer(user IPlayer) bool {
	if _, ok := r.users[user.Id()]; ok {
		return false
	}
	r.users[user.Id()] = user
	return true
}

func (r *HundredRoom) DelPlayer(uid int64) {
	delete(r.users, uid)
}

func (r *HundredRoom) RangePlayer(proc func(IPlayer) bool) {
	for _, seat := range r.users {
		if !proc(seat) {
			return
		}
	}
}

func (r *HundredRoom) FilterPlayer(proc func(IPlayer) bool) []IPlayer {
	users := make([]IPlayer, 0)
	for _, user := range r.users {
		if proc(user) {
			users = append(users, user)
		}
	}
	return users
}

func (r *HundredRoom) DebugSendMsg(user IPlayer, msgId pb.MsgId, msg proto.Message) {
	log.Debug(r.UserLog(user.Id(), "send msg:%v %v", msgId, msg.String()))
}

func (r *HundredRoom) SendMsg(user IPlayer, msgId pb.MsgId, msg proto.Message) {
	r.DebugSendMsg(user, msgId, msg)
	if user.Robot() != nil {
		user.Robot().OnMessage(msgId, msg)
	} else {
		iMsg := ipb.MakeMsgEx(r.room.srv.Name(), 0, user.Id(), int32(msgId), msg)
		_ = r.room.srv.SendByServiceId(int(pb.ServiceTypeId_STI_Gate), iMsg)
	}

}

func (r *HundredRoom) Broadcast(msgId pb.MsgId, msg proto.Message, exclude ...IPlayer) {
	for _, user := range r.users {
		exist := false
		for _, excludePlayer := range exclude {
			if excludePlayer.Id() == user.Id() {
				exist = true
				break
			}
		}
		if !exist {
			r.SendMsg(user, msgId, msg)
		}
	}
}

func (r *HundredRoom) NewTimer(timerType timer.ITimeType, duration time.Duration, args ...any) {
	r.room.NewTimer(timerType, duration, args...)
}

func (r *HundredRoom) CancelTimer(timerType timer.ITimeType) {
	r.room.CancelTimer(timerType)
}

func (r *HundredRoom) CancelAllTimer() {
	r.room.CancelAllTimer()
}

func (r *HundredRoom) Log(format string, a ...any) string {
	return r.room.Log(format, a...)
}

func (r *HundredRoom) UserLog(uid int64, format string, a ...any) string {
	head := ""
	user := r.users[uid]
	if user != nil {
		head = fmt.Sprintf("room:%v type:%v user:%v robot:%v ", r.Id(), r.RoomType(), uid, user.IsRobot())
	} else {
		head = fmt.Sprintf("room:%v type:%v ", r.Id(), r.RoomType())
	}

	return head + fmt.Sprintf(format, a...)
}

func (r *HundredRoom) Unmarshal(cmd int32, data []byte) (any, error) {
	return r.room.Unmarshal(cmd, data)
}

func (r *HundredRoom) Dispatch(user IPlayer, cmd int32, params ...any) error {
	return r.room.Dispatch(user, cmd, params...)
}

func (r *HundredRoom) RegisterMessages(metas processor.RegisterMetas) {
	r.room.RegisterMessages(metas)
}

// 注册时间事件及处理
func (r *HundredRoom) RegisterTimerMessages(metas processor.RegisterTimerMetas) {
	r.room.RegisterTimerMessages(metas)
}

// 初始化房间
func (r *HundredRoom) OnInit() {

}
