package service

import (
	"fengkuangGameServerJob/dao"
	"fengkuangGameServerJob/model"
	"fengkuangGameServerJob/pkg/util"
	"fmt"
	"math/rand"
	"strconv"
	"strings"
	"time"
)

var (
	nearByDelimiter   = "|"                   //附近的人在有序集合中的分隔符
	robotNearByPrefix = "0" + nearByDelimiter //机器人在附近的人上的上的前缀
)

// StationService 跑商相关服务层
type StationService struct {
}

func NewStationService() *StationService {
	return &StationService{}
}

// GetTcpList 获取所有的tcp列表
func (s *StationService) GetTcpList() []int {
	return dao.GetTcpList()
}

// GetServerIdsByTcpId 通过tcpId来获取当前tcp_id下有哪些server_id
func (s *StationService) GetServerIdsByTcpId(tcpId int) []int {
	return dao.GetServerIdsByTcp(tcpId)
}

// GetRandMissions 随机获取任务
func (s *StationService) GetRandMissions(missions []*StationMissionItem, num int) []*StationMissionItem {
	ret := make([]*StationMissionItem, 0, num)
	missionsLen := len(missions)
	for i := 0; i < num; i++ {
		randIdx := rand.Intn(missionsLen)
		ret = append(ret, missions[randIdx])
	}
	return ret
}

// FindMissionByMID 根据跑商任务ID来获取任务配置信息
func (s *StationService) FindMissionByMID(missions []*StationMissionItem, missionId uint8) *StationMissionItem {
	var tmp *StationMissionItem
	for _, v := range missions {
		if v.MissionId == missionId {
			tmp = v
		}
	}
	return tmp
}

// DoSingleTcpStation 处理单个tcp的跑商机器人事件
func (s *StationService) DoSingleTcpStation(tcpId int, doDestroy bool) error {
	//1. 根据tcp_id找出对应的server_id
	serverIds := s.GetServerIdsByTcpId(tcpId)
	//2. 找出当前tcp的前n名机器人,n=0则选择全部
	robots, err := dao.GetRobotsByServerIds(serverIds, []string{"robot_id", "station_slots"}, 40)
	if err != nil || len(robots) == 0 {
		return err
	}
	robotIds := make([]int, 0, len(robots))
	robotsSign := make([]string, 0, len(robots))
	for _, v := range robots {
		robotIds = append(robotIds, v.RobotId)
		robotsSign = append(robotsSign, fmt.Sprintf(robotNearByPrefix+"%d", v.RobotId))
	}
	//3. 批量获取跑商的前置信息
	//3.1 获取当前机器人的所有跑商任务记录
	missionsExist, err := dao.GetRobotsStationMissions(robotIds, []string{"id", "robot_id", "end_unix"})
	if err != nil {
		return err
	}
	//3.2 跑商任务的配置
	missionsConf, err := GetStationMissionsConf()
	if err != nil {
		return err
	}
	//3.3 随机获取附近的人
	nearBys, err := dao.GetStationRandNearBy(tcpId, len(robots))
	if err != nil {
		return err
	}
	//3.3.1 找出附近的人中真实玩家的ID
	playerIds := make([]int, 0, len(robots))
	for _, v := range nearBys {
		tmpS := strings.Split(v, nearByDelimiter)
		tmpPlayerId, _ := strconv.Atoi(tmpS[0])
		if tmpPlayerId > 0 {
			playerIds = append(playerIds, tmpPlayerId)
		}
	}
	//3.3.2 获取真实玩家的跑商任务信息
	var allPlayerMissions []*model.StationMission
	if len(playerIds) > 0 && doDestroy == true {
		allPlayerMissions, _ = dao.GetPlayersStationMissions(playerIds, []string{"id", "mission_serial_num", "robot_id", "end_unix", "station_mission_id", "destroy_end_unix", "pillages", "player_id"})
	}
	//4 处理机器人的事件
	log := make([]*model.StationDestory, 0, len(playerIds))
	for idx, robot := range robots {
		//4.1 处理机器人自己的跑商任务
		err = s.HandlerRobotSelfMission(robot, missionsExist, missionsConf)
		if err != nil {
			return err
		}
		//4.2 掠夺或破坏其他玩家的商队
		//4.2.1 附近的人的数量<=机器人的数量||当前附近的人是机器人则略过
		if doDestroy == false || idx >= len(nearBys) || strings.HasPrefix(nearBys[idx], robotNearByPrefix) == true {
			continue
		}
		//4.2.2 解析出真实玩家的ID
		tmpNearByArr := strings.Split(nearBys[idx], nearByDelimiter)
		playerId, _ := strconv.Atoi(tmpNearByArr[0])
		if playerId <= 0 {
			continue
		}
		//4.2.3 遍历任务,找到playerId一个可破坏或可掠夺的任务即可
		nowUnix := time.Now().Unix()
		for _, tmpPlayerMission := range allPlayerMissions {
			if tmpPlayerMission.StationMissionId == 0 || tmpPlayerMission.PlayerId != playerId {
				//未发布任务
				continue
			}
			if tmpPlayerMission.EndUnix <= nowUnix && tmpPlayerMission.Pillages >= 3 {
				//任务完成超过被掠夺上限的
				continue
			}
			if tmpPlayerMission.EndUnix > nowUnix && tmpPlayerMission.DestroyEndUnix != 0 {
				//任务未完成但被破坏过的
				continue
			}
			tmpMConf := s.FindMissionByMID(missionsConf, tmpPlayerMission.StationMissionId)
			if tmpMConf.Id == 0 {
				continue
			}
			var (
				affected int64
				flag     uint8
				award    string
			)
			if tmpPlayerMission.EndUnix <= nowUnix {
				affected, err = dao.IncrStationPillages(tmpPlayerMission.ID, 3)
				flag = 2
				award = tmpMConf.LootRewards
			} else {
				affected, err = dao.DestroyStation(tmpPlayerMission.ID, tmpMConf.DestoryTime)
				flag = 1
				award = tmpMConf.DestoryRewards
			}
			if err != nil {
				return err
			}
			if affected == 0 {
				continue
			}
			tmpLog := model.StationDestory{
				PlayerId: tmpPlayerMission.PlayerId,
				MixId:    robot.RobotId,
				IsPlayer: 0,
				Flag:     flag,
				IsWho:    2,
				Award:    award,
			}
			log = append(log, &tmpLog)
			break
		}
	}
	//批量记录掠夺、破坏日志
	if len(log) > 0 {
		if err = dao.SaveDestroyLogs(log); err != nil {
			return err
		}
	}
	//4 把当前机器人加入附近的人当中
	return dao.AddRobotsToNearBy(robotsSign, tcpId)
}

// HandlerRobotSelfMission 机器人处理自己的跑商任务
func (s *StationService) HandlerRobotSelfMission(robot *model.Robot, missionsExist []*model.StationMission, missionsConf []*StationMissionItem) (err error) {
	nowUnix := time.Now().Unix()
	//1 获取单个机器人商队总量
	tmpSlotNum := robot.StationSlots
	//2 当前机器人的所有跑商任务
	tmpMissionsNum := 0 //跑商任务在数据库中记录的条数
	for key, missionExistInfo := range missionsExist {
		if missionExistInfo.RobotId != robot.RobotId {
			continue
		}
		tmpMissionsNum++
		//任务到期了,更新重置任务
		if missionExistInfo.EndUnix <= nowUnix {
			randSingleMission := s.GetRandMissions(missionsConf, 1)
			time.Sleep(time.Millisecond)//执行太快了Uint64Random生成的都是一样的,暂且先这样
			missionExistInfo.MissionSerialNum = fmt.Sprintf("%d", util.Uint64Random(uint64(key), 1))
			missionExistInfo.StationMissionId = randSingleMission[0].MissionId
			missionExistInfo.EndUnix = nowUnix + int64(randSingleMission[0].MissionTime)
			missionExistInfo.DestroyEndUnix = 0
			missionExistInfo.Pillages = 0
			err = dao.ResetSingleMission(missionExistInfo)
			if err != nil {
				return err
			}
		}
	}
	//3 若机器人有空闲的商队则新增任务
	tmpAddMissionNum := int(tmpSlotNum) - tmpMissionsNum
	if tmpAddMissionNum > 0 {
		tmpSaveMissions := make([]*model.StationMission, 0, tmpAddMissionNum)
		//生成随机的任务
		tmpRandMissionConf := s.GetRandMissions(missionsConf, tmpAddMissionNum)
		//组成写入的数据
		for k, v := range tmpRandMissionConf {
			time.Sleep(time.Millisecond)//执行太快了Uint64Random生成的都是一样的,暂且先这样
			tmpSaveMissions = append(tmpSaveMissions, &model.StationMission{
				PlayerId:         0,
				RobotId:          robot.RobotId,
				MissionSerialNum: fmt.Sprintf("%d", util.Uint64Random(uint64(robot.RobotId), uint64(k))),
				StationMissionId: v.MissionId,
				EndUnix:          nowUnix + int64(v.MissionTime),
				DestroyEndUnix:   0,
				Pillages:         0,
			})
		}
		if len(tmpSaveMissions) > 0 {
			err = dao.SaveRobotsMissions(tmpSaveMissions)
		}
	}
	return err
}
