package game

import (
	"time"

	"hk4e/gs/constant"
	"hk4e/gs/model"
	"hk4e/pkg/logger"
	"hk4e/pkg/random"
	"hk4e/protocol/cmd"
	"hk4e/protocol/proto"
)

// 游戏服务器定时帧管理器

type TickManager struct {
	ticker      *time.Ticker
	tickCount   uint64
	gameManager *GameManager
}

func NewTickManager(gameManager *GameManager) (r *TickManager) {
	r = new(TickManager)
	r.ticker = time.NewTicker(time.Millisecond * 100)
	logger.LOG.Info("game server tick start at: %v", time.Now().UnixMilli())
	r.gameManager = gameManager
	return r
}

func (t *TickManager) OnGameServerTick() {
	t.tickCount++
	now := time.Now().UnixMilli()
	t.onTick100MilliSecond(now)
	if t.tickCount%(10*1) == 0 {
		t.onTickSecond(now)
	}
	if t.tickCount%(10*5) == 0 {
		t.onTick5Second(now)
	}
	if t.tickCount%(10*10) == 0 {
		t.onTick10Second(now)
	}
	if t.tickCount%(10*60) == 0 {
		t.onTickMinute(now)
	}
	if t.tickCount%(10*60*10) == 0 {
		t.onTick10Minute(now)
	}
	if t.tickCount%(10*3600) == 0 {
		t.onTickHour(now)
	}
	if t.tickCount%(10*3600*24) == 0 {
		t.onTickDay(now)
	}
	if t.tickCount%(10*3600*24*7) == 0 {
		t.onTickWeek(now)
	}
}

func (t *TickManager) onTickWeek(now int64) {
	logger.LOG.Info("on tick week, time: %v", now)
}

func (t *TickManager) onTickDay(now int64) {
	logger.LOG.Info("on tick day, time: %v", now)
}

func (t *TickManager) onTickHour(now int64) {
	logger.LOG.Info("on tick hour, time: %v", now)
}

func (t *TickManager) onTick10Minute(now int64) {
	for _, world := range t.gameManager.worldManager.worldMap {
		for _, player := range world.playerMap {
			// 蓝球粉球
			t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 223, ChangeCount: 1}}, true, 0)
			t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 224, ChangeCount: 1}}, true, 0)
		}
	}
}

func (t *TickManager) onTickMinute(now int64) {
	//t.gameManager.ServerAnnounceNotify(100, "test123")
	for _, world := range t.gameManager.worldManager.worldMap {
		for _, player := range world.playerMap {
			// 随机物品
			allItemDataConfig := t.gameManager.GetAllItemDataConfig()
			count := random.GetRandomInt32(0, 4)
			i := int32(0)
			for itemId := range allItemDataConfig {
				itemDataConfig, ok := allItemDataConfig[itemId]
				if !ok {
					logger.LOG.Error("config is nil, itemId: %v", itemId)
					return
				}
				// TODO 3.0.0REL版本中 发送某些无效家具 可能会导致客户端背包家具界面卡死
				if itemDataConfig.ItemEnumType == constant.ItemTypeConst.ITEM_FURNITURE {
					continue
				}
				num := random.GetRandomInt32(1, 9)
				t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: uint32(itemId), ChangeCount: uint32(num)}}, true, 0)
				i++
				if i > count {
					break
				}
			}
			t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 102, ChangeCount: 30}}, true, 0)
			t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 201, ChangeCount: 10}}, true, 0)
			t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 202, ChangeCount: 100}}, true, 0)
			t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 203, ChangeCount: 10}}, true, 0)
		}
	}
}

func (t *TickManager) onTick10Second(now int64) {
	for _, world := range t.gameManager.worldManager.worldMap {
		if !world.IsBigWorld() && (world.multiplayer || !world.owner.Pause) {
			// 刷怪
			scene := world.GetSceneById(3)
			monsterEntityCount := 0
			for _, entity := range scene.entityMap {
				if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER) {
					monsterEntityCount++
				}
			}
			if monsterEntityCount < 30 {
				monsterEntityId := t.createMonster(scene)
				bigWorldOwner := t.gameManager.userManager.GetOnlineUser(1)
				t.gameManager.AddSceneEntityNotify(bigWorldOwner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true)
			}
		}
		for _, player := range world.playerMap {
			if world.multiplayer || !world.owner.Pause {
				// 改面板
				team := player.TeamConfig.GetActiveTeam()
				for _, avatarId := range team.AvatarIdList {
					if avatarId == 0 {
						break
					}
					avatar := player.AvatarMap[avatarId]
					avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK)] = 1000000
					avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL)] = 1.0
					t.gameManager.UpdateUserAvatarFightProp(player.PlayerID, avatarId)
				}
			}
		}
	}
}

func (t *TickManager) onTick5Second(now int64) {
	for _, world := range t.gameManager.worldManager.worldMap {
		if world.IsBigWorld() {
			for applyUid := range world.owner.CoopApplyMap {
				t.gameManager.UserDealEnterWorld(world.owner, applyUid, true)
			}
		}
		for _, player := range world.playerMap {
			if world.multiplayer {
				// 多人世界其他玩家的坐标位置广播
				// PacketWorldPlayerLocationNotify
				worldPlayerLocationNotify := new(proto.WorldPlayerLocationNotify)
				for _, worldPlayer := range world.playerMap {
					playerWorldLocationInfo := &proto.PlayerWorldLocationInfo{
						SceneId: worldPlayer.SceneId,
						PlayerLoc: &proto.PlayerLocationInfo{
							Uid: worldPlayer.PlayerID,
							Pos: &proto.Vector{
								X: float32(worldPlayer.Pos.X),
								Y: float32(worldPlayer.Pos.Y),
								Z: float32(worldPlayer.Pos.Z),
							},
							Rot: &proto.Vector{
								X: float32(worldPlayer.Rot.X),
								Y: float32(worldPlayer.Rot.Y),
								Z: float32(worldPlayer.Rot.Z),
							},
						},
					}
					worldPlayerLocationNotify.PlayerWorldLocList = append(worldPlayerLocationNotify.PlayerWorldLocList, playerWorldLocationInfo)
				}
				t.gameManager.SendMsg(cmd.WorldPlayerLocationNotify, player.PlayerID, 0, worldPlayerLocationNotify)

				// PacketScenePlayerLocationNotify
				scene := world.GetSceneById(player.SceneId)
				scenePlayerLocationNotify := new(proto.ScenePlayerLocationNotify)
				scenePlayerLocationNotify.SceneId = player.SceneId
				for _, scenePlayer := range scene.playerMap {
					playerLocationInfo := &proto.PlayerLocationInfo{
						Uid: scenePlayer.PlayerID,
						Pos: &proto.Vector{
							X: float32(scenePlayer.Pos.X),
							Y: float32(scenePlayer.Pos.Y),
							Z: float32(scenePlayer.Pos.Z),
						},
						Rot: &proto.Vector{
							X: float32(scenePlayer.Rot.X),
							Y: float32(scenePlayer.Rot.Y),
							Z: float32(scenePlayer.Rot.Z),
						},
					}
					scenePlayerLocationNotify.PlayerLocList = append(scenePlayerLocationNotify.PlayerLocList, playerLocationInfo)
				}
				t.gameManager.SendMsg(cmd.ScenePlayerLocationNotify, player.PlayerID, 0, scenePlayerLocationNotify)
			}
		}
	}
}

func (t *TickManager) onTickSecond(now int64) {
	for _, world := range t.gameManager.worldManager.worldMap {
		for _, player := range world.playerMap {
			// 世界里所有玩家的网络延迟广播
			// PacketWorldPlayerRTTNotify
			worldPlayerRTTNotify := new(proto.WorldPlayerRTTNotify)
			worldPlayerRTTNotify.PlayerRttList = make([]*proto.PlayerRTTInfo, 0)
			for _, worldPlayer := range world.playerMap {
				playerRTTInfo := &proto.PlayerRTTInfo{Uid: worldPlayer.PlayerID, Rtt: worldPlayer.ClientRTT}
				worldPlayerRTTNotify.PlayerRttList = append(worldPlayerRTTNotify.PlayerRttList, playerRTTInfo)
			}
			t.gameManager.SendMsg(cmd.WorldPlayerRTTNotify, player.PlayerID, 0, worldPlayerRTTNotify)
		}
	}
}

func (t *TickManager) onTick100MilliSecond(now int64) {
	// 伤害处理和转发
	for _, world := range t.gameManager.worldManager.worldMap {
		for _, scene := range world.sceneMap {
			scene.AttackHandler(t.gameManager)
		}
	}

	// 服务器控制的模拟AI移动

	//bigWorldOwner := t.gameManager.userManager.GetOnlineUser(1)
	//bigWorld := t.gameManager.worldManager.GetBigWorld()
	//bigWorldScene := bigWorld.GetSceneById(3)
	//
	//if len(bigWorldScene.playerMap) < 2 {
	//	return
	//}
	//if t.gameManager.worldManager.worldStatic.aiMoveCurrIndex >= len(t.gameManager.worldManager.worldStatic.aiMoveVectorList)-1 {
	//	return
	//}
	//t.gameManager.worldManager.worldStatic.aiMoveCurrIndex++
	//
	//entityMoveInfo := new(proto.EntityMoveInfo)
	//activeAvatarId := bigWorldOwner.TeamConfig.GetActiveAvatarId()
	//playerTeamEntity := bigWorldScene.GetPlayerTeamEntity(bigWorldOwner.PlayerID)
	//entityMoveInfo.EntityId = playerTeamEntity.avatarEntityMap[activeAvatarId]
	//entityMoveInfo.SceneTime = uint32(bigWorldScene.GetSceneTime())
	//entityMoveInfo.ReliableSeq = uint32(bigWorldScene.GetSceneTime() / 100 * 100)
	//entityMoveInfo.IsReliable = true
	//oldPos := model.Vector{
	//	X: bigWorldOwner.Pos.X,
	//	Y: bigWorldOwner.Pos.Y,
	//	Z: bigWorldOwner.Pos.Z,
	//}
	//newPos := t.gameManager.worldManager.worldStatic.aiMoveVectorList[t.gameManager.worldManager.worldStatic.aiMoveCurrIndex]
	//rotY := math.Atan2(newPos.X-oldPos.X, newPos.Z-oldPos.Z) / math.Pi * 180.0
	//if rotY < 0.0 {
	//	rotY += 360.0
	//}
	//entityMoveInfo.MotionInfo = &proto.MotionInfo{
	//	Pos: &proto.Vector{
	//		X: float32(newPos.X),
	//		Y: float32(newPos.Y),
	//		Z: float32(newPos.Z),
	//	},
	//	Rot: &proto.Vector{
	//		X: 0.0,
	//		Y: float32(rotY),
	//		Z: 0.0,
	//	},
	//	Speed: &proto.Vector{
	//		X: float32((newPos.X - oldPos.X) * 10.0),
	//		Y: float32((newPos.Y - oldPos.Y) * 10.0),
	//		Z: float32((newPos.Z - oldPos.Z) * 10.0),
	//	},
	//	State:  proto.MotionState_MOTION_STATE_RUN,
	//	RefPos: new(proto.Vector),
	//}
	//data, err := pb.Marshal(entityMoveInfo)
	//if err != nil {
	//	logger.LOG.Error("build combat invocations entity move info error: %v", err)
	//	return
	//}
	//combatInvocationsNotify := new(proto.CombatInvocationsNotify)
	//combatInvocationsNotify.InvokeList = []*proto.CombatInvokeEntry{{
	//	CombatData:   data,
	//	ForwardType:  proto.ForwardType_FORWARD_TYPE_TO_ALL_EXCEPT_CUR,
	//	ArgumentType: proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_ENTITY_MOVE,
	//}}
	//t.gameManager.CombatInvocationsNotify(bigWorldOwner.PlayerID, bigWorldOwner, 0, combatInvocationsNotify)
}

func (t *TickManager) createMonster(scene *Scene) uint32 {
	pos := &model.Vector{
		X: 2747,
		Y: 194,
		Z: -1719,
	}
	fpm := map[uint32]float32{
		uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP):            float32(72.91699),
		uint32(constant.FightPropertyConst.FIGHT_PROP_PHYSICAL_SUB_HURT): float32(0.1),
		uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE):       float32(505.0),
		uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK):        float32(45.679916),
		uint32(constant.FightPropertyConst.FIGHT_PROP_ICE_SUB_HURT):      float32(0.1),
		uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK):       float32(45.679916),
		uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP):            float32(72.91699),
		uint32(constant.FightPropertyConst.FIGHT_PROP_FIRE_SUB_HURT):     float32(0.1),
		uint32(constant.FightPropertyConst.FIGHT_PROP_ELEC_SUB_HURT):     float32(0.1),
		uint32(constant.FightPropertyConst.FIGHT_PROP_WIND_SUB_HURT):     float32(0.1),
		uint32(constant.FightPropertyConst.FIGHT_PROP_ROCK_SUB_HURT):     float32(0.1),
		uint32(constant.FightPropertyConst.FIGHT_PROP_GRASS_SUB_HURT):    float32(0.1),
		uint32(constant.FightPropertyConst.FIGHT_PROP_WATER_SUB_HURT):    float32(0.1),
		uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP):           float32(72.91699),
		uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE):      float32(505.0),
	}
	entityId := scene.CreateEntityMonster(pos, 1, fpm)
	return entityId
}
