-- 异界之战(跨服)
local InnerMsg = require("core.InnerMsg")
local Log = require("common.Log")
local Timer = require("core.Timer")
local Util = require("common.Util")
local MiddleManager = require("middle.MiddleManager")
local AnotherWorldBattleDB = require("anotherWorldBattle.AnotherWorldBattleDB")
local AnotherWorldBattleDefine = require("anotherWorldBattle.AnotherWorldBattleDefine")
local CombatDefine = require("combat.CombatDefine")
local AnotherWorldBattleConfig = require("excel.anotherWorldBattle")


-- 当天处于星期几(星期六为7, 星期天为1)
local wDay


local function updateWDay()
    wDay = Util.getWeekDay()
end

local function getTodayStartTime()
    local now = os.time()
    return Util.getDayStartTime(now)
end

local function isOpen()
    if not wDay then
        updateWDay()
    end

    if wDay > AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[2] and wDay < AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[1] then
        return false
    end

    local now = os.time()
    local toDayStartTime = getTodayStartTime()
    if wDay == AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[1] and now < (toDayStartTime + AnotherWorldBattleDefine.AB_START_SEC) then
        return false
    end

    -- 本函数中, 为了处理发奖, 周四23点过后不算结束
    -- if wDay == AnotherWorldBattleDefine.OPEN_WDAY_AREA[2] and now > (toDayStartTime + AnotherWorldBattleDefine.AB_BATTLE_END_SEC) then
    --     return false
    -- end

    local lastRoundStartTime = AnotherWorldBattleDB.GetLastRoundStartTime()
    if lastRoundStartTime ~= 0 then
        local diffDays = Util.diffDay(lastRoundStartTime)
        -- <= 6天说明处于本轮活动时间范围内, > 6 且 < 9 说明处于活动结束~新一轮活动未开启的时间段
        if diffDays > AnotherWorldBattleDefine.AB_OPEN_DAYS and diffDays <= AnotherWorldBattleDefine.AB_SUB_DAY then
            return false
        end
    end

    return true
end

local function isRunning()
    if not isOpen() then
        return false
    end

    local now = os.time()
    local toDayStartTime = getTodayStartTime()
    if wDay == AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[2] and now > (toDayStartTime + AnotherWorldBattleDefine.AB_BATTLE_END_SEC) then
        return false
    end

    return true
end


-- 进入新一轮的处理
local function newRoundHandle()
    local stage = AnotherWorldBattleDB.GetStage()

    -- 上一轮奖励没有发放, 在新一轮开始时, 先发奖
    if stage == AnotherWorldBattleDefine.AB_STATE_AWARD then
        IssueRewardManager()
        return AnotherWorldBattleDB.UpdateStage(AnotherWorldBattleDefine.AB_STATE_END)
    end

    -- 重置数据
    AnotherWorldBattleDB.ResetData()

    -- 更新状态
    AnotherWorldBattleDB.UpdateStage(AnotherWorldBattleDefine.AB_STATE_JOIN)

    -- 更新活动开始时间
    local now = os.time()
    AnotherWorldBattleDB.UpdateLastRoundStartTime(now)

    -- 通知所有普通服, 新一轮活动开启了
    ActOpen(now)
end

-- 进入新一轮报名阶段检测
local function joinStageCheck()
    local stage = AnotherWorldBattleDB.GetStage()

    if stage ~= AnotherWorldBattleDefine.AB_STATE_END and stage ~= AnotherWorldBattleDefine.AB_STATE_AWARD then
        return
    end

    -- local lastRoundStartTime = AnotherWorldBattleDB.GetLastRoundStartTime()
    -- local diffDays = Util.diffDay(lastRoundStartTime)

    -- 上一轮活动结束时间为0 或 当前时间 - 上一轮活动开启时间 > 9天, 开启新一轮活动
    -- if lastRoundStartTime == 0 or diffDays > AnotherWorldBattleDefine.AB_SUB_DAY then
        newRoundHandle()
    -- end
end

-- 公会分组算法
local function groupingAlgorithm(unionArray, len)
    local usedTb = {}
    local groupArr = {}

    local function getNextUnuseIdx(nowIdx)
        for i=nowIdx, len do
            if not usedTb[i] then
                return i
            end
        end
    end

    local function checkRandIdx(startIdx, endIdx)
        local tbl= {}
        for i= startIdx, endIdx do
            if not usedTb[i] then
                table.insert(tbl, i)
            end
        end
        return tbl
    end


    local currentIdx = 1
    local selectNum, cnt = 0, 0

    while currentIdx <= len do
        currentIdx = getNextUnuseIdx(currentIdx)
        if not currentIdx then
            break
        end

        local startIdx = currentIdx + 1
        local endIdx = math.min(currentIdx + 19, len)

        groupArr[#groupArr+1] = { unionArray[currentIdx] }
        selectNum = selectNum + 1
        cnt = math.min(AnotherWorldBattleDefine.AB_GROUP_UNION_NUM - 1,  len - selectNum )

        for i=1, cnt do
            local correctTb = checkRandIdx(startIdx, endIdx)
            if #correctTb == 0 then break end

            local matchIdx = correctTb[math.random(1, #correctTb)]
            usedTb[currentIdx] = true
            usedTb[matchIdx] = true
            table.insert(groupArr[#groupArr], unionArray[matchIdx])
            selectNum = selectNum + 1
        end

        currentIdx = currentIdx + 1
    end

    return groupArr
end

-- 分组
local function grouping()
    local function genUnionIdArray(sourceUnionArr, targetUnionArr)
        for k, v in ipairs(sourceUnionArr) do
            targetUnionArr[k] = v.unionId
        end
    end

    local joinUnionArr = AnotherWorldBattleDB.GetJoinUnionArr()
    if not joinUnionArr then
        -- 没有公会参加, 本轮活动结束
        local now = os.time()
        -- AnotherWorldBattleDB.UpdateLastRoundStartTime(now)
        return AnotherWorldBattleDB.UpdateStage(AnotherWorldBattleDefine.AB_STATE_END)
    end

    local len = #joinUnionArr
    if len > AnotherWorldBattleDefine.AB_GROUP_UNION_NUM then
        table.sort(joinUnionArr, function (a, b)
            return a.power > b.power
        end)
    end

    local unionIdArr = {}
    genUnionIdArray(joinUnionArr, unionIdArr)

    local newGroupArray
    if len > AnotherWorldBattleDefine.AB_GROUP_UNION_NUM then
        newGroupArray = groupingAlgorithm(unionIdArr, len)
    else
        newGroupArray = { unionIdArr }
    end

    AnotherWorldBattleDB.UpdateGroupArray(newGroupArray)
end

-- 给各个分组中的公会随机分配出生点
local function randomBaseCity()
    local baseCityIdArr = {}
    for cityId, cityCfg in ipairs(AnotherWorldBattleConfig.city) do
        if cityCfg.isBaseCity == 1 then
            baseCityIdArr[#baseCityIdArr+1] = cityId
        end
    end

    local now = os.time()
    local groupArray = AnotherWorldBattleDB.GetGroupArray()

    for _, unionIdArr in ipairs(groupArray) do
        -- 乱序
        table.shuffle(baseCityIdArr)

        for i, unionId in ipairs(unionIdArr) do
            local union = AnotherWorldBattleDB.GetUnionData(unionId)
            if union then
                union.baseCityId = baseCityIdArr[i]
                union.baseCityStartTime = now
                AnotherWorldBattleDB.UpdateUnionData(unionId, union)
            end
        end
    end
end

-- 获取自己公会所在分组的Id
local function getMyUnionGourpId(myUnionId)
    local groupId = AnotherWorldBattleDB.GetUnionGroupId(myUnionId)
    return groupId
end

-- 获取自己公会/所在区服第一公会所在分组Id
local function getGroupId(myUnionId, myServerId)
    local groupId = getMyUnionGourpId(myUnionId)
    if not groupId then
        groupId = AnotherWorldBattleDB.GetGroupIdByServerId(myServerId)
    end

    return groupId
end

-- 获取排名
local function getRank(rankArr, targetUuid, isUnion)
    local rank = 9999
    if not rankArr or not targetUuid then
        return rank
    end

    for rankIdx, rankInfo in ipairs(rankArr) do
        local rankerUuid = isUnion and rankInfo.guildId or rankInfo.playerId
        if rankerUuid == targetUuid then
            rank = rankIdx
            break
        end
    end

    return rank
end

-- 统计公会的占领情况, 用于发放奖励
local function genUnionOccupyInfo(unionId, union, playerListData)
    local occupyTb = {
        occupyCityArr = {}, -- 当前还占领的城池列表
        point2CityIdArr = {}, -- 曾占领/当前还占领的据点的所属城池Id列表
        occuoyPointNum = 0,
        playerInfoArr = {},
        unionId = unionId,
        unionRank = 0,
    }

    local now = os.time()
    local t1 = occupyTb.occupyCityArr
    local t2 = occupyTb.point2CityIdArr

    t1[#t1+1] = union.baseCityId

    for cityId, cityIno in pairs(union.occupCityList or {}) do
        if cityIno.isOccupy then
            t1[#t1+1] = cityId
        end

        for _, pointInfo in pairs(cityIno.occupyPointList) do
            if pointInfo.playerUuid then
                if not cityIno.isOccupy then
                    occupyTb.occuoyPointNum = occupyTb.occuoyPointNum + 1
                end

                -- 更新据点最新占领时间段的结束时间
                local occupyTimeArr = pointInfo.occupyTimeArr
                local lastTimeTb = occupyTimeArr[#occupyTimeArr]
                if #lastTimeTb == 1 then
                    occupyTimeArr[#occupyTimeArr][2] = now
                end
            end

            t2[#t2+1] = {cityId, pointInfo.occupyTimeArr}
        end
    end

    -- 出生点算5个据点
    local baseCiyuTimeArr = { {union.baseCityStartTime, union.baseCityEndTime or now } }
    for i=1, AnotherWorldBattleDefine.AB_POINT_MAX_NUM do
        t2[#t2+1] = {union.baseCityId,  baseCiyuTimeArr}
    end


    local groupId = getMyUnionGourpId(unionId)
    local unionRankList = AnotherWorldBattleDB.GetUnionRankList(groupId)
    local playerRankList = AnotherWorldBattleDB.GetPlayerRankList(groupId)

    occupyTb.unionRank = getRank(unionRankList, unionId, true)

    for playerUuid, playerInfo in pairs(playerListData) do
        if playerInfo.unionId == unionId then
            local playerRank = getRank(playerRankList, playerUuid)
            occupyTb.playerInfoArr[#occupyTb.playerInfoArr+1] = {playerUuid, playerRank}
        end
    end

    -- 防止本次没有正常发放奖励, 后续补发时, 结束时间异常的情况
    union.baseCityEndTime = now
    AnotherWorldBattleDB.UpdateUnionData(unionId, union)

    return occupyTb
end

-- 发奖
local function issueReward(sourceServerId, occupyInfo)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_ISSUEREWARD
    msgData.unionOccupyInfo = occupyInfo
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 奖励发放管理函数
function IssueRewardManager()
    local delay_sec = 0
    local unionList = AnotherWorldBattleDB.GetUnionList()
    local playerListData = AnotherWorldBattleDB.GetPlayerList()

    for unionId, union in pairs(unionList) do
        local occupyInfo = genUnionOccupyInfo(unionId, union, playerListData)
        delay_sec = delay_sec + 5
        Timer.addLater(delay_sec, issueReward, union.serverId, occupyInfo)
    end
end

-- 检测活动各阶段状态及相关处理
local function timedStageHandle()
    -- 处于报名阶段
    if table.find(AnotherWorldBattleDefine.AB_JOIN_WDAY_AREA, wDay) then
        joinStageCheck()
    end

    -- if wDay == AnotherWorldBattleDefine.AB_JOIN_WDAY then
    --     joinStageCheck()
    -- end

    local now = os.time()

    -- 报名阶段 -> 战斗阶段
    if wDay >= AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[1] and wDay <= AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[2] then
        local stage = AnotherWorldBattleDB.GetStage()
        local toDayStartTime = getTodayStartTime()

        if stage == AnotherWorldBattleDefine.AB_STATE_JOIN and now >= (toDayStartTime + AnotherWorldBattleDefine.AB_START_SEC) then
            -- 分组
            grouping()

            -- 给各个分组中的公会随机分配出生点
            randomBaseCity()

            -- 改为战斗阶段
            return AnotherWorldBattleDB.UpdateStage(AnotherWorldBattleDefine.AB_STATE_BATTLE)
        end
    end

    -- 战斗阶段 -> 发奖阶段
    local toDayStartTime = getTodayStartTime()
    if wDay == AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[2] and now >= (toDayStartTime + AnotherWorldBattleDefine.AB_BATTLE_END_SEC) then
        local stage = AnotherWorldBattleDB.GetStage()

        if stage == AnotherWorldBattleDefine.AB_STATE_BATTLE or stage == AnotherWorldBattleDefine.AB_STATE_AWARD then
            -- 改为发奖阶段
            AnotherWorldBattleDB.UpdateStage(AnotherWorldBattleDefine.AB_STATE_AWARD)

            -- 开始发奖
            IssueRewardManager()

            -- 改为结束阶段
            return AnotherWorldBattleDB.UpdateStage(AnotherWorldBattleDefine.AB_STATE_END)
        end
    end
end



function oneMin()
    if _G.is_middle ~= true then return end

    if not isOpen() then
        return
    end

    -- 与 onHour() 处理错开
    if Util.getMin() == 0 then
        return
    end

    timedStageHandle()
end

function onHour(hour)
    if _G.is_middle ~= true then return end

    if hour == 0 or not wDay then
        updateWDay()
    end

    if not isOpen() then
        return
    end

    timedStageHandle()
end


------------------------------------C2N---------------------------------------------------

-- 错误提示
local function errTips(sourceServerId, playerUuid, errCode)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_TIPS
    msgData.playerUuid = playerUuid
    msgData.errCode = errCode
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 通知玩家，据点被别的玩家占领了
local function pointLose(sourceServerId, playerUuid, loseCityId, losePointIdx)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_POINT_LOSE
    msgData.playerUuid = playerUuid
    msgData.loseCityId = loseCityId
    msgData.losePointIdx = losePointIdx

    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 通知所有普通服, 活动开启
function ActOpen(ti)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_ACT_START
    msgData.startTime = ti or os.time()

    local fdList = MiddleManager.MiddleManager_GetAllFD()
    for _, fd in pairs(fdList) do
        InnerMsg.sendMsg(fd, msgData)
    end
end

------------------------------------N2C---------------------------------------------------

-- 统计单个服公会报名数量
local function calcSvrUnionJoinNum(serverId)
    local num = 0
    local joinUnionArr = AnotherWorldBattleDB.GetJoinUnionArr()
    if not joinUnionArr then
        return num
    end

    for _, unionInfo in ipairs(joinUnionArr) do
        if unionInfo.serverId == serverId then
            num = num + 1
        end
    end

    return num
end

-- 计算多个英雄的总战力
local function calcHerosPower(heroArr)
    local power = 0
    for _, v in ipairs(heroArr) do
        power = power + v.heroPower
    end

    return power
end

-- 统计公会占领不同等级的城池数量
local function calcOccupyCityNum(occupCityList, cityLv)
    if not occupCityList then
        return 0
    end

    local num = 0
    for cityId, occupyInfo in pairs(occupCityList) do
        if occupyInfo.isOccupy then
            local cityCfg = AnotherWorldBattleConfig.city[cityId]
            if cityCfg.cityLv == cityLv then
                num = num + 1
            end
        end
    end

    return num
end

-- 统计公会占领的据点所属城池Id数组
local function calcOccupyPointArr(occupCityList)
    local pointInfoArr = {}

    if not occupCityList then
        return pointInfoArr
    end

    for cityId, occupyInfo in pairs(occupCityList) do
        for _, pointInfo in pairs(occupyInfo.occupyPointList) do
            if pointInfo.playerUuid then
                pointInfoArr[#pointInfoArr+1] = cityId
            end
        end
    end
    return pointInfoArr
end

-- 获取公会占领的城池列表
local function getUnionOccupyArr(unionId)
    local union = AnotherWorldBattleDB.GetUnionData(unionId)
    if not union then
        return
    end

    local occupyCityArr = {}
    occupyCityArr[#occupyCityArr+1] = union.baseCityId

    for cityId, occupyInfo in pairs(union.occupCityList or {}) do
        if occupyInfo.isOccupy then
            occupyCityArr[#occupyCityArr+1] = cityId
        end
    end

    return occupyCityArr
end

-- 检查某个城池与公会占领的城池是否相邻
local function isadJoin(cityIdArr, targetCityId)
    if not cityIdArr then
        return false
    end

    local targetCityCfg = AnotherWorldBattleConfig.city[targetCityId]
    if not targetCityCfg then
        return false
    end

    for _, cityId in ipairs(targetCityCfg.adJoinCityArr) do
        if table.find(cityIdArr, cityId) then
            return true
        end
    end

    return false
end

-- 统计玩家占据的据点数量
local function calcPlayerOccupyPointNum(playerUuid)
    local playerOccupyPonitNum = 0
    local playerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    if playerData and playerData.heroList then
        for _, pointList in pairs(playerData.heroList) do
            for _, _ in pairs(pointList) do
                playerOccupyPonitNum = playerOccupyPonitNum + 1
            end
        end
    end

    return playerOccupyPonitNum
end

-- 检查某个据点是否能被玩家挑战
local function isCanChallengePoint(targetCityId, targetPointIdx, myUnionId, playerUuid)
    -- 活动未开启
    if not isRunning() then
        return -1
    end

    -- 公会没有参加活动
    local groupId = getMyUnionGourpId(myUnionId)
    if not groupId then
        return -2
    end

    local tagetCityData = AnotherWorldBattleDB.GetCityData(groupId, targetCityId)
    if not tagetCityData then
        return -3
    end

    local targetPointData = tagetCityData.pointArr[targetPointIdx]
    if not targetPointData then
        return -5
    end

    -- 自己占领了该据点
    if targetPointData.unionId and targetPointData.unionId == myUnionId and targetPointData.playerUuid == playerUuid then
        return 2
    end

    -- 城池已被本公会占领
    if tagetCityData.occupyUnion and tagetCityData.occupyUnion == myUnionId then
        return -4
    end


    -- 据点已被本公会占领
    if targetPointData.unionId and targetPointData.unionId == myUnionId then
        return -6
    end

    local myUnionData = AnotherWorldBattleDB.GetUnionData(myUnionId)
    if not myUnionData then
        return -7
    end

    -- 城池是否相邻
    local occupyCityArr = getUnionOccupyArr(myUnionId)
    if not isadJoin(occupyCityArr, targetCityId) then
        return -8
    end

    return 1
end

-- 公会是否能报名
local function isCanJoin(sourceServerId, myUnionId)
    if not isRunning() then
        return 2
    end

    local joinUnionArr = AnotherWorldBattleDB.GetJoinUnionArr()
    for _, unionData in ipairs(joinUnionArr or {}) do
        if unionData.unionId == myUnionId then
            return 1
        end
    end


    local num = calcSvrUnionJoinNum(sourceServerId)
    if num >= AnotherWorldBattleDefine.AB_SRV_UNION_MAX_NUM then
        return 2
    end

    return 0
end

-- 检查城池是否被己方公会完全占领
local function isCompleteOccupy(cityData, myUnionId)
    for _, pointInfo in ipairs(cityData.pointArr) do
        if not pointInfo.unionId or pointInfo.unionId ~= myUnionId then
            return false
        end
    end

    return true
end

-- 获取本轮活动战斗阶段的开始时间
local function getBattleStartTime()
    local lastRoundStartTime = AnotherWorldBattleDB.GetLastRoundStartTime()
    local openWDay = Util.getWeekDay(lastRoundStartTime)
    local subDay = 0
    if openWDay == AnotherWorldBattleDefine.AB_JOIN_WDAY_AREA[1] then
        subDay = 2
    else
        subDay = 1
    end

    local openStartTime = Util.getDayStartTime(lastRoundStartTime)
    local battleStartTime = openStartTime + subDay * 86400 + AnotherWorldBattleDefine.AB_START_SEC

    return battleStartTime
end

-- 获取玩家挑战次数相关数据
local function getPlayerChallengeTimesInfo(playerUuid)
    local playerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    -- if not playerData then
    --     return AnotherWorldBattleDefine.AB_PLAYER_CHALLENGE_INIT_TIMES, 0
    -- end

    local challengeTimes, lastTime = AnotherWorldBattleDefine.AB_PLAYER_CHALLENGE_INIT_TIMES, 0

    if playerData and playerData.lastTime then
        lastTime = playerData.lastTime
        challengeTimes = playerData.challengeTimes or AnotherWorldBattleDefine.AB_PLAYER_CHALLENGE_INIT_TIMES
    else
        lastTime = getBattleStartTime()
    end

    local now = os.time()
    local subSex = now - lastTime

    if subSex >= AnotherWorldBattleDefine.AB_PLAYER_CHALLENGETIMES_SEC then
        local addTimes = math.floor(subSex / AnotherWorldBattleDefine.AB_PLAYER_CHALLENGETIMES_SEC)
        challengeTimes = math.min(challengeTimes + addTimes, AnotherWorldBattleDefine.AB_PLAYER_CHALLENGE_MAX_TIMES)
        lastTime = lastTime + addTimes * AnotherWorldBattleDefine.AB_PLAYER_CHALLENGETIMES_SEC

        if challengeTimes == AnotherWorldBattleDefine.AB_PLAYER_CHALLENGE_MAX_TIMES then
            lastTime = 0
        end

        if playerData then
            playerData.challengeTimes = challengeTimes
            playerData.lastTime = lastTime
            AnotherWorldBattleDB.UpdatePlayerData(playerUuid, playerData)
        end
    end

    if not isRunning() then
        lastTime = 0
    end

    return challengeTimes, lastTime
end

-- 获取城池被占领状态
local function getCityState(cityData)
    local state = 0
    if cityData.occupyUnion then
        state = 1
        return state
    end

    local occupyPlayerUuid
    for _, pointInfo in ipairs(cityData.pointArr) do
        if pointInfo.playerUuid then
            if not occupyPlayerUuid then
                occupyPlayerUuid = pointInfo.playerUuid
            end

            if pointInfo.playerUuid ~= occupyPlayerUuid then
                state = 2
                break
            end
        end
    end

    return state
end

-- 获取公会占领据点的数据
local function getOccupPointData(unionId)
    local t2 = {}

    local unionData = AnotherWorldBattleDB.GetUnionData(unionId)
    if not unionData then
        return t2
    end

    for cityId, cityIno in pairs(unionData.occupCityList or {}) do
        for _, pointInfo in pairs(cityIno.occupyPointList) do
            t2[#t2+1] = {cityId, pointInfo.occupyTimeArr}
        end
    end

    -- 出生点算5个据点
    local baseCiyuTimeArr = { {unionData.baseCityStartTime, unionData.baseCityEndTime or now } }
    for i=1, AnotherWorldBattleDefine.AB_POINT_MAX_NUM do
        t2[#t2+1] = {unionData.baseCityId,  baseCiyuTimeArr}
    end

    return t2
end

-- 增加士气条件之时间条件检测
local function moraleCondTimeCheck()
    local now = os.time()
    local battleStartTime = getBattleStartTime()
    local moraleStartTime = battleStartTime + 86400
    return now >= moraleStartTime
end

-- 获取本公会占领据点排名
local function getUnionRank(myUnionId)
    local myRank = 0
    local groupId = getMyUnionGourpId(myUnionId)
    if not groupId then
        return myRank
    end

    local unionRankList = AnotherWorldBattleDB.GetUnionRankList(groupId)
    for rank, randkData in ipairs(unionRankList or {}) do
        if randkData.guildId == myUnionId then
            myRank = rank
            break
        end
    end

    return myRank
end


-- 查询状态
function N2C_GetState_Req(msg)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_GET_STATE
    msgData.playerUuid = msg.playerUuid
    msgData.systemState = 0
    msgData.joinState = 0
    msgData.isTips = msg.isTips or 0

    local stage = AnotherWorldBattleDB.GetStage()
    msgData.systemState = stage

    if stage == 0 then
        local lastRoundStartTime = AnotherWorldBattleDB.GetLastRoundStartTime()
        if lastRoundStartTime == 0 then
            msgData.systemState = 0
        else
            msgData.systemState = 3
        end
    end

    local sourceServerId = msg.sourceServerId
    local num = calcSvrUnionJoinNum(sourceServerId)
    if num >= AnotherWorldBattleDefine.AB_SRV_UNION_MAX_NUM then
        msgData.joinState = 2
    end

    local joinUnionArr = AnotherWorldBattleDB.GetJoinUnionArr()
    for _, unionData in ipairs(joinUnionArr or {}) do
        if unionData.unionId == msg.myUnionId then
            msgData.joinState = 1
        end
    end

    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 报名
function N2C_Join_Req(msg)
    local sourceServerId = msg.sourceServerId
    local playerUuid = msg.playerUuid
    local unionInfo = msg.unionInfo

    local state = isCanJoin(sourceServerId, unionInfo.unionId)
    if state == 2 then
        return errTips(sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_1)
    elseif state == 1 then
        return errTips(sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_8)
    end

    -- 更新参赛列表数据
    local joinUnionArr = AnotherWorldBattleDB.GetJoinUnionArr()
    joinUnionArr = joinUnionArr or {}
    joinUnionArr[#joinUnionArr+1] = {
        unionId = unionInfo.unionId,
        power = unionInfo.power,
        serverId = sourceServerId
    }
    AnotherWorldBattleDB.UpdateJoinUnionArr(joinUnionArr)

    -- 更新公会列表数据
    local newUnionData = {
        serverId = sourceServerId,
        power = unionInfo.power,
        name = unionInfo.name,
    }
    AnotherWorldBattleDB.UpdateUnionData(unionInfo.unionId, newUnionData)

    -- 通知报名成功
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_JOIN
    msgData.playerUuid = playerUuid
    msgData.myUnionId = unionInfo.unionId
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 查询所有城池信息
function N2C_GetAllCity_Req(msg)
    local myUnionId = msg.myUnionId
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_ALLCITY_QUERY
    msgData.cityArr = {}
    msgData.playerUuid = msg.playerUuid
    msgData.myUnionBaseCityId = 0
    msgData.myOccupyCityArr = {}
    msgData.hasPointNum = 0
    msgData.challengeTimes = 0
    msgData.lastTime = 0
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)

    local groupId = getGroupId(myUnionId, msg.sourceServerId)
    if not groupId then
        -- 报名阶段, 或者活动开未开启过处于默认的结束状态
        local stage = AnotherWorldBattleDB.GetStage()
        if stage == AnotherWorldBattleDefine.AB_STATE_JOIN or stage == AnotherWorldBattleDefine.AB_STATE_END then
            return InnerMsg.sendMsg(fd, msgData)
        end

        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local cityList = AnotherWorldBattleDB.GetCityListByGroupId(groupId)
    if not cityList then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end

    local cityArrMsg = msgData.cityArr
    local unionList = AnotherWorldBattleDB.GetUnionList()
    msgData.myUnionBaseCityId = unionList[myUnionId] and unionList[myUnionId].baseCityId or 0

    for cityId, cityInfo in ipairs(cityList) do
        cityArrMsg[cityId] = { occupyPointNum = 0 }
        if cityInfo.occupyUnion then
            cityArrMsg[cityId].occupyUnionName = unionList[cityInfo.occupyUnion] and unionList[cityInfo.occupyUnion].name
        end

        for _, pointInfo in ipairs(cityInfo.pointArr) do
            if pointInfo.unionId and pointInfo.unionId == myUnionId then
                cityArrMsg[cityId].occupyPointNum = cityArrMsg[cityId].occupyPointNum + 1
            end
        end

        cityArrMsg[cityId].cityState = getCityState(cityInfo)
    end

    msgData.myOccupyCityArr = getUnionOccupyArr(myUnionId)
    msgData.hasPointNum = calcPlayerOccupyPointNum(msg.playerUuid)
    local challengeTimes, leftTime = getPlayerChallengeTimesInfo(msg.playerUuid)
    msgData.challengeTimes = challengeTimes
    msgData.lastTime = leftTime
    msgData.occupyPointData = getOccupPointData(myUnionId)

    InnerMsg.sendMsg(fd, msgData)
end

-- 查询某个城池的详细信息
function N2C_GetCityDetailed_Req(msg)
    local myUnionId = msg.myUnionId
    local playerUuid = msg.playerUuid
    local targetCityId = msg.targetCityId

    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_CITYDETAILED_QUERY
    msgData.playerUuid = playerUuid
    msgData.targetCityId = targetCityId
    msgData.myUnionOccupyArr = {}
    msgData.pointArr = {}
    msgData.gatherState = 0
    msgData.gatherTime = -1

    local groupId = getGroupId(myUnionId, msg.sourceServerId)
    if not groupId then
        -- 报名阶段, 或者活动开未开启过处于默认的结束状态
        local stage = AnotherWorldBattleDB.GetStage()
        if stage == AnotherWorldBattleDefine.AB_STATE_JOIN or stage == AnotherWorldBattleDefine.AB_STATE_END then
            return InnerMsg.sendMsg(fd, msgData)
        end

        return errTips(msg.sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local cityData = AnotherWorldBattleDB.GetCityData(groupId, targetCityId)
    if not cityData then
        return errTips(msg.sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end


    local union = AnotherWorldBattleDB.GetUnionData(myUnionId)
    local occupCityList = union and union.occupCityList
    local myUnionOccupyArr = calcOccupyPointArr(occupCityList)
    if union then
        myUnionOccupyArr[#myUnionOccupyArr+1] = union.baseCityId
    end
    msgData.myUnionOccupyArr = myUnionOccupyArr


    local pointArrMsg = msgData.pointArr
    for pointIdx, occupyInfo in ipairs(cityData.pointArr) do
        pointArrMsg[pointIdx] = {}
        local state = isCanChallengePoint(targetCityId, pointIdx, myUnionId, playerUuid)
        pointArrMsg[pointIdx].state = state < 0 and 0 or state

        if occupyInfo.unionId and occupyInfo.playerUuid then
            local occupyUnionData = AnotherWorldBattleDB.GetUnionData(occupyInfo.unionId)
            local occupyPlayerData = AnotherWorldBattleDB.GetPlayerData(occupyInfo.playerUuid)

            if occupyUnionData and occupyPlayerData then
                pointArrMsg[pointIdx].occupyUnionName = occupyUnionData.name
                pointArrMsg[pointIdx].occupyPlayerName = occupyPlayerData.name

                pointArrMsg[pointIdx].power = 0
                local heroList = occupyPlayerData.heroList
                if heroList and heroList[targetCityId] and heroList[targetCityId][pointIdx] then
                    pointArrMsg[pointIdx].power = calcHerosPower(heroList[targetCityId][pointIdx])
                end
            end
        end
    end

    local isOk = isRunning()
    if isOk then
        local myUnionData = AnotherWorldBattleDB.GetUnionData(myUnionId)
        local occupyCityArr = getUnionOccupyArr(myUnionId)
        isOk = isadJoin(occupyCityArr, targetCityId)

        if isOk then
            if not cityData.occupyUnion or cityData.occupyUnion ~= myUnionId then
                if not myUnionData.gatherInfo then
                    msgData.gatherState = 1
                else
                    if myUnionData.gatherInfo.gatherCity == targetCityId then
                        msgData.gatherState = 2
                        msgData.gatherTime = myUnionData.gatherInfo.gatherTime
                    else
                        local now = os.time()
                        if now - myUnionData.gatherInfo.gatherTime >= AnotherWorldBattleDefine.AB_GATHER_CD_SEC then
                            msgData.gatherState = 1
                        end
                    end
                end
            end
        end
    end

    InnerMsg.sendMsg(fd, msgData)
end

-- 查询某个据点信息
function N2C_GetPointDetailed_Req(msg)
    local myUnionId = msg.myUnionId
    local targetCityId = msg.targetCityId
    local targetPointIdx = msg.targetPointIdx

    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_POINTDETAILED_QUERY
    msgData.playerUuid = msg.playerUuid
    msgData.targetCityId = targetCityId
    msgData.targetPointIdx = targetPointIdx
    msgData.pointInfo = {}

    local groupId = getGroupId(myUnionId, msg.sourceServerId)
    if not groupId then
        -- 报名阶段, 或者活动开未开启过处于默认的结束状态
        local stage = AnotherWorldBattleDB.GetStage()
        if stage == AnotherWorldBattleDefine.AB_STATE_JOIN or stage == AnotherWorldBattleDefine.AB_STATE_END then
            return InnerMsg.sendMsg(fd, msgData)
        end

        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local cityData = AnotherWorldBattleDB.GetCityData(groupId, targetCityId)
    if not cityData then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end

    local pointData = cityData.pointArr[targetPointIdx]
    if not pointData then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end


    local pointInfoMsg = msgData.pointInfo
    if pointData.unionId and pointData.playerUuid then
        local playerData = AnotherWorldBattleDB.GetPlayerData(pointData.playerUuid)
        if not playerData then
            return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
        end

        pointInfoMsg.name = playerData.name
        pointInfoMsg.head = playerData.head
        pointInfoMsg.headFrame = playerData.headFrame
        pointInfoMsg.defLv = playerData.lv

        local targetHeroArr = playerData.heroList[targetCityId][targetPointIdx]
        if not targetHeroArr then
            return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
        end
        pointInfoMsg.power = calcHerosPower(targetHeroArr)

        pointInfoMsg.heroArr = {}
        for i, heroInfo in ipairs(targetHeroArr) do
            pointInfoMsg.heroArr[i] = {
                heroBody = heroInfo.heroBody,
                heroStar = heroInfo.heroStar,
                heroLv = heroInfo.heroLevel,
                heroCamp = heroInfo.heroCamp,
                heroIcon = heroInfo.heroIcon,
                heroId = heroInfo.heroId,
                heroQuality = heroInfo.heroQuality,
            }
        end
    end

    local state = isCanChallengePoint(targetCityId, targetPointIdx, myUnionId, msg.playerUuid)
    pointInfoMsg.state = state < 0 and 0 or state

    InnerMsg.sendMsg(fd, msgData)
end

-- 查询公会出生点信息
function N2C_GetBaseCity_Req(msg)
    local myUnionId = msg.myUnionId
    local groupId = getGroupId(myUnionId, msg.sourceServerId)
    if not groupId then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_BASECITY_QUERY
    msgData.playerUuid = msg.playerUuid

    local union = AnotherWorldBattleDB.GetUnionData(myUnionId)
    if not union then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local baseCityInfo = {}
    msgData.baseCityInfo = baseCityInfo

    baseCityInfo.cityId = union.baseCityId
    local pointInfoArr = calcOccupyPointArr(union.occupCityList)
    baseCityInfo.occupyPointNum = #pointInfoArr
    baseCityInfo.myUnionOccupyArr = calcOccupyPointArr(union.occupCityList)
    baseCityInfo.myUnionOccupyArr[#baseCityInfo.myUnionOccupyArr+1] = baseCityInfo.cityId
    baseCityInfo.occupyCityLv2Num = calcOccupyCityNum(union.occupCityList, 2)
    baseCityInfo.occupyCityLv3Num = calcOccupyCityNum(union.occupCityList, 3)
    baseCityInfo.occupyCityLv4Num = calcOccupyCityNum(union.occupCityList, 4)
    baseCityInfo.occupyCityLv5Num = calcOccupyCityNum(union.occupCityList, 5)

    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 查询玩家占领的所有据点信息
function N2C_GetPlayerOccupyPoint_Req(msg)
    local myUnionId = msg.myUnionId
    local playerUuid = msg.playerUuid

    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_PLAYEROCCUPYPOINT_QUERY
    msgData.playerUuid = playerUuid
    msgData.occupyPointArr = {}

    local union = AnotherWorldBattleDB.GetUnionData(myUnionId)
    if not union then
        -- 报名阶段, 或者活动开未开启过处于默认的结束状态
        local stage = AnotherWorldBattleDB.GetStage()
        if stage == AnotherWorldBattleDefine.AB_STATE_JOIN or stage == AnotherWorldBattleDefine.AB_STATE_END then
            return InnerMsg.sendMsg(fd, msgData)
        end

        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end


    local playerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    if not playerData then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_5)
    end

    local heroList = playerData.heroList
    if not heroList then
        return errTips(msg.sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_5)
    end


    local occupyPointArrMsg = msgData.occupyPointArr
    for cityId, pointList in pairs(heroList) do
        for pointIdx, heroInfoArr in pairs(pointList) do
            occupyPointArrMsg[#occupyPointArrMsg+1] = {
                cityId = cityId,
                pointIdx = pointIdx,
                power = calcHerosPower(heroInfoArr),
                heroArr = {},
            }

            local targetHeroArr = occupyPointArrMsg[#occupyPointArrMsg].heroArr
            for _, heroInfo in ipairs(heroInfoArr) do
                targetHeroArr[#targetHeroArr+1] = {
                    heroBody = heroInfo.heroBody,
                    heroStar = heroInfo.heroStar,
                    heroLv = heroInfo.heroLevel,
                    heroCamp = heroInfo.heroCamp,
                    heroIcon = heroInfo.heroIcon,
                    heroId = heroInfo.heroId,
                    heroQuality = heroInfo.heroQuality
                }
            end
        end
    end

    InnerMsg.sendMsg(fd, msgData)
end

-- 查询公会排行榜
function N2C_GetUnionRank_Req(msg)
    local myUnionId = msg.myUnionId
    local groupId = getGroupId(myUnionId, msg.sourceServerId)
    if not groupId then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local unionRankList = AnotherWorldBattleDB.GetUnionRankList(groupId)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_UNIONRANK_QUERY
    msgData.playerUuid = msg.playerUuid
    msgData.myUnionRank = 0
    msgData.unionRankArr = {}

    for rank, randkData in ipairs(unionRankList) do
        msgData.unionRankArr[rank] = {
            name = randkData.name,
            power = randkData.power,
            cityNum = randkData.occupyCityNum,
            pointNum = randkData.occupyPointNum,
        }

        if randkData.guildId == myUnionId then
            msgData.myUnionRank = rank
        end
    end

    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 查询玩家排行榜
function N2C_GetPlayerRank_Req(msg)
    local myUnionId = msg.myUnionId
    local groupId = getGroupId(myUnionId, msg.sourceServerId)
    if not groupId then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local playerRankList = AnotherWorldBattleDB.GetPlayerRankList(groupId)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_PLAYERRANK_QUERY
    msgData.playerUuid = msg.playerUuid
    msgData.myRank = 0
    msgData.playerRankArr = {}

    for rank, randkData in ipairs(playerRankList) do
        if rank > AnotherWorldBattleDefine.AB_RANK_MAX_NUM then
            break
        end

        msgData.playerRankArr[rank] = {
            name = randkData.name,
            power = randkData.power,
            pointNum = randkData.pointNum,
            pointWeight = randkData.pointAllWeight,
        }

        if randkData.playerId == msg.playerUuid then
            msgData.myRank = rank
        end
    end

    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 集结/取消集结
function N2C_Gather_Req(msg)
    local sourceServerId = msg.sourceServerId
    local playerUuid = msg.playerUuid
    local myUnionId = msg.myUnionId
    if not isRunning() then
        return errTips(sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_1)
    end

    local groupId = getMyUnionGourpId(myUnionId)
    if not groupId then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local targetCityId = msg.targetCityId
    local myUnionData = AnotherWorldBattleDB.GetUnionData(myUnionId)
    if not myUnionData then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local gatherInfo = myUnionData.gatherInfo
    if msg.opType == 1 then --集结
        -- 集结冷却时间判断
        local now = os.time()
        if gatherInfo then
            local gatherTime = gatherInfo.gatherTime
            if now - gatherTime < AnotherWorldBattleDefine.AB_GATHER_CD_SEC then
                return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_6)
            end
        end

        -- 城池是否相邻判断
        local occupCityyArr = getUnionOccupyArr(myUnionId)
        if not isadJoin(occupCityyArr, targetCityId) then
            return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_7)
        end

        myUnionData.gatherInfo = myUnionData.gatherInfo or {}
        myUnionData.gatherInfo.gatherTime = now
        myUnionData.gatherInfo.gatherCity = targetCityId
    else
        -- 取消集结

        if not gatherInfo then
            return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_9)
        end

        if targetCityId ~= gatherInfo.gatherCity then
            return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_9)
        end

        gatherInfo.gatherCity = 0
    end

    AnotherWorldBattleDB.UpdateUnionData(myUnionId, myUnionData)

    -- 推送城池数据给客户端，刷新界面
    N2C_GetCityDetailed_Req(msg)

    -- 发给本地服, 用于在公会聊天频道生成链接
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_GATHER
    msgData.playerUuid = msg.playerUuid
    msgData.targetCityId = targetCityId
    msgData.opType = msg.opType
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 查询据点是否可以被挑战
function N2C_TryChallengdePoint_Req(msg)
    local playerUuid = msg.playerUuid
    local myUnionId = msg.myUnionId
    local targetCityId = msg.targetCityId
    local targetPointIdx = msg.targetPointIdx

    if not isRunning() then
        return errTips(msg.sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_1)
    end

    local pChallengeTimes = getPlayerChallengeTimesInfo(playerUuid)
    if pChallengeTimes <= 0 then
        return errTips(msg.sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_12)
    end

    local state = isCanChallengePoint(targetCityId, msg.targetPointIdx, msg.myUnionId, playerUuid)
    if state ~= 1 then
        return
    end

    local occupyPointNum = calcPlayerOccupyPointNum(msg.playerUuid)
    if occupyPointNum >= AnotherWorldBattleDefine.AB_PLAYER_OCCUPY_POINT_MAX_NUM then
        return errTips(msg.sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_10)
    end

    local now = os.time()
    local groupId = getMyUnionGourpId(myUnionId)
    local cityData = AnotherWorldBattleDB.GetCityData(groupId, targetCityId)
    local targetPointData = cityData.pointArr[targetPointIdx]

    -- 检查据点是否有人挑战
    local pointBattleTime = targetPointData.battleTime
    if pointBattleTime and now - pointBattleTime < AnotherWorldBattleDefine.AB_POINT_BATTLE_TIME then
        return errTips(msg.sourceServerId, playerUuid, AnotherWorldBattleDefine.ERR_CODE_11)
    end

    -- 防守方
    local pointOccupyInfo = {targetCityId = targetCityId, targetPointIdx = targetPointIdx}
    if targetPointData.unionId then
        local occupyUnionData = AnotherWorldBattleDB.GetUnionData(targetPointData.unionId)
        pointOccupyInfo.occupySrvId = occupyUnionData.serverId
        pointOccupyInfo.occupyPlayerUuid = targetPointData.playerUuid

        -- 防守方的士气信息
        if occupyUnionData.moraleData then
            if occupyUnionData.moraleData.moraleStartTime + AnotherWorldBattleDefine.AB_MORALE_DURATION >= now then
                pointOccupyInfo.defMoraleAttrIdx = occupyUnionData.moraleData.moraleAttrIdx
            end
        end
    end

    -- 进攻方集结信息
    local myUnionData = AnotherWorldBattleDB.GetUnionData(myUnionId)
    if myUnionData.gatherInfo and myUnionData.gatherInfo.gatherCity == targetCityId then
        pointOccupyInfo.isGather = 1
    end

    -- 进攻方士气信息
    if myUnionData.moraleData then
        if myUnionData.moraleData.moraleStartTime + AnotherWorldBattleDefine.AB_MORALE_DURATION >= now then
            pointOccupyInfo.atkMoraleAttrIdx = myUnionData.moraleData.moraleAttrIdx
        end
    end

    -- 更新据点被挑战时间
    targetPointData.battleTime = now
    AnotherWorldBattleDB.UpdateCityData(groupId, targetCityId, cityData)

    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_POINT_ISCAN_CHALLENGE
    msgData.playerUuid = playerUuid
    msgData.pointInfo = pointOccupyInfo

    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 玩家挑战据点胜利
local function challenge_Win(msg)
    local playerUuid = msg.playerUuid
    local myUnionId = msg.myUnionId
    local targetCityId = msg.targetCityId
    local targetPointIdx = msg.targetPointIdx
    local playerShowInfo = msg.playerShowInfo

    if not isRunning() then
        return
    end

    local groupId = getMyUnionGourpId(myUnionId)
    if not groupId then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local myUnionData = AnotherWorldBattleDB.GetUnionData(myUnionId)
    if not myUnionData then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_3)
    end

    local cityData = AnotherWorldBattleDB.GetCityData(groupId, targetCityId)
    local pointData = cityData.pointArr[targetPointIdx]

    local now = os.time()
    local cityNum, pointNum = 0, 1
    local pointWeight = AnotherWorldBattleConfig.city[targetCityId].pointWeight


    -- 如果城池之前被占领了, 则删除占领城池的公会Id
    if cityData.occupyUnion then
        cityData.occupyUnion = nil
    end

    -- 防守方是真实玩家
    if pointData.unionId and pointData.playerUuid then
        -- 更新防守方公会数据
        local defUnionData = AnotherWorldBattleDB.GetUnionData(pointData.unionId)
        local defOccupCityList = defUnionData.occupCityList
        local defTargerCityData = defOccupCityList[targetCityId]

        -- 更新防守方公会对该据点的占领状态和最后占领时间
        if defTargerCityData and defTargerCityData.occupyPointList and defTargerCityData.occupyPointList[targetPointIdx] then
            local defTargetPointData = defTargerCityData.occupyPointList[targetPointIdx]
            if defTargetPointData then
                -- 删除占领该据点的玩家uuid
                defTargetPointData.playerUuid = nil

                -- 更新对该据点最后占领时间段的结束时间
                if defTargetPointData.occupyTimeArr then
                    local lastOccupyTimeTb = defTargetPointData.occupyTimeArr[#defTargetPointData.occupyTimeArr]
                    lastOccupyTimeTb[2] = now
                end
            end
        end

        -- 删除防守方玩家的防守阵容数据
        local defPlayData = AnotherWorldBattleDB.GetPlayerData(pointData.playerUuid)
        if defPlayData then
            defPlayData.heroList[targetCityId][targetPointIdx] = nil
            AnotherWorldBattleDB.UpdatePlayerData(pointData.playerUuid, defPlayData)
        end


        -- 如果防守方公会之前占领了城池, 则修改占领状态
        if defTargerCityData and defTargerCityData.isOccupy then
            defTargerCityData.isOccupy = false
            cityNum = -1
        end


        -- 更新防守方公会的排行榜数据
        AnotherWorldBattleDB.UpdateUnionRankList(groupId, pointData.unionId, cityNum, -pointNum)
        -- 更新防守方玩家的排行榜数据
        AnotherWorldBattleDB.UpdatePlayerRankList(groupId, pointData.playerUuid, -pointNum, -pointWeight)

        -- 通知玩家
        pointLose(defUnionData.serverId, pointData.playerUuid, targetCityId, targetPointIdx)

        -- 更新防守方公会数据
        AnotherWorldBattleDB.UpdateUnionData(pointData.unionId, defUnionData)
    end

    -- 更新据点最新占领者数据
    pointData.unionId = myUnionId
    pointData.playerUuid = playerUuid

    -- 重置据点被挑战标识
    pointData.battleTime = nil

    -- 更新进攻方公会数据—— 据点占有者, 最新的据点占有时间
    myUnionData.occupCityList = myUnionData.occupCityList or {}
    local occupCityList = myUnionData.occupCityList
    occupCityList[targetCityId] = occupCityList[targetCityId] or {}
    occupCityList[targetCityId].occupyPointList = occupCityList[targetCityId].occupyPointList or {}
    occupCityList[targetCityId].occupyPointList[targetPointIdx] = occupCityList[targetCityId].occupyPointList[targetPointIdx] or {}
    local atkPointInfo = occupCityList[targetCityId].occupyPointList[targetPointIdx]
    atkPointInfo.playerUuid = playerUuid
    atkPointInfo.occupyTimeArr = atkPointInfo.occupyTimeArr or {}
    atkPointInfo.occupyTimeArr[#atkPointInfo.occupyTimeArr+1] = { now }

    --更新进攻者的展示数据
    local atkPlayerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    atkPlayerData = atkPlayerData or {}
    atkPlayerData.name = playerShowInfo.name
    atkPlayerData.lv = playerShowInfo.lv
    atkPlayerData.head = playerShowInfo.head
    atkPlayerData.headFrame = playerShowInfo.headFrame
    atkPlayerData.power = playerShowInfo.power
    atkPlayerData.unionId = myUnionId
    -- 更新挑战次数
    -- atkPlayerData.challengeTimes = (atkPlayerData.challengeTimes or AnotherWorldBattleDefine.AB_PLAYER_CHALLENGE_INIT_TIMES) - 1
    -- if not atkPlayerData.lastTime or atkPlayerData.lastTime == 0 then
    --     atkPlayerData.lastTime = os.time()
    -- end
    local pChallengeTimes, pLastTime = getPlayerChallengeTimesInfo(playerUuid)
    atkPlayerData.challengeTimes = pChallengeTimes - 1
    if pLastTime <= 0 then
        pLastTime = os.time()
    end
    atkPlayerData.lastTime = pLastTime


    -- 增加防守阵容数据
    atkPlayerData.heroList = atkPlayerData.heroList or {}
    atkPlayerData.heroList[targetCityId] = atkPlayerData.heroList[targetCityId] or {}
    atkPlayerData.heroList[targetCityId][targetPointIdx] = playerShowInfo.heroArr

    cityNum = 0

    -- 进攻方完全占领城池了
    if isCompleteOccupy(cityData, myUnionId) then
        -- 更新城池的占领公会
        cityData.occupyUnion = myUnionId

        -- 更新进攻方公会对该城池的占领状态
        occupCityList[targetCityId].isOccupy = true

        -- 如果占领的是发起集结的城池, 那么取消集结
        if myUnionData.gatherInfo and myUnionData.gatherInfo.gatherCity == targetCityId then
            myUnionData.gatherInfo.gatherCity = 0
        end

        cityNum = 1
    end

    -- 更新进攻方公会数据
    AnotherWorldBattleDB.UpdateUnionData(myUnionId, myUnionData)
    -- 更新进攻方玩家数据
    AnotherWorldBattleDB.UpdatePlayerData(playerUuid, atkPlayerData)

    -- 更新进攻方公会的排行榜数据
    AnotherWorldBattleDB.UpdateUnionRankList(groupId, myUnionId, cityNum, pointNum)
    -- 更新进攻方玩家的排行榜数据
    AnotherWorldBattleDB.UpdatePlayerRankList(groupId, playerUuid, pointNum, pointWeight, playerShowInfo.power)


    -- 更新城池数据
    AnotherWorldBattleDB.UpdateCityData(groupId, targetCityId, cityData)
end
-- 玩家挑战据点失败
local function challenge_Fail(msg)
    local playerUuid = msg.playerUuid
    local myUnionId = msg.myUnionId
    local targetCityId = msg.targetCityId
    local targetPointIdx = msg.targetPointIdx
    local playerShowInfo = msg.playerShowInfo

    local groupId = getMyUnionGourpId(myUnionId)
    if not groupId then
        return
    end

    -- 据点挑战结束
    local cityData = AnotherWorldBattleDB.GetCityData(groupId, targetCityId)
    if cityData and cityData.pointArr[targetPointIdx] then
        local targetPointData = cityData.pointArr[targetPointIdx]
        targetPointData.battleTime = nil
        AnotherWorldBattleDB.UpdateCityData(groupId, targetCityId, cityData)
    end

    local playerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    playerData = playerData or {}
    playerData.name = playerShowInfo.name
    playerData.lv = playerShowInfo.lv
    playerData.power = playerShowInfo.power
    playerData.unionId = myUnionId
    -- playerData.challengeTimes = (playerData.challengeTimes or AnotherWorldBattleDefine.AB_PLAYER_CHALLENGE_INIT_TIMES) - 1
    -- if not playerData.lastTime or playerData.lastTime == 0 then
    --     playerData.lastTime = os.time()
    -- end
    local pChallengeTimes, pLastTime = getPlayerChallengeTimesInfo(playerUuid)
    playerData.challengeTimes = pChallengeTimes - 1
    if pLastTime <= 0 then
        pLastTime = os.time()
    end
    playerData.lastTime = pLastTime

    AnotherWorldBattleDB.UpdatePlayerData(playerUuid, playerData)

    -- 加入个人排行榜
    AnotherWorldBattleDB.UpdatePlayerRankList(groupId, playerUuid, 0, 0, playerData.power)
end

--挑战据点结束的处理函数
function N2C_PointChallengeEnd_Handle(msg)
    if msg.challengeRes == CombatDefine.RESULT_WIN then
        challenge_Win(msg)
    else
        challenge_Fail(msg)
    end
end


-- 更新玩家数据
function N2C_UpdatePlayerData_Req(msg)
    if not isRunning() then
        return
    end

    local playerUuid = msg.playerUuid
    local playerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    if not playerData then
        return
    end

    local groupId = getMyUnionGourpId(playerData.unionId)
    if not groupId then
        return
    end

    local isUpdate = false
    for k,v in pairs(msg.updateData) do
        if k == "power" or k == "name" then
            isUpdate = true
        end

        playerData[k] = v
    end

    AnotherWorldBattleDB.UpdatePlayerData(playerUuid, playerData)

    -- 如果是战力/名字更新, 更新玩家排行榜
    if isUpdate then
        AnotherWorldBattleDB.UpdatePlayerRankList(groupId, playerUuid, 0, 0, playerData.power)
    end

end

-- 更新公会数据
function N2C_UpdateUnionData_Req(msg)
    if not isRunning() then
        return
    end

    local myUnionId = msg.myUnionId
    local unionData = AnotherWorldBattleDB.GetUnionData(myUnionId)
    if not unionData then
        return
    end

    local groupId = getMyUnionGourpId(myUnionId)
    if not groupId then
        return
    end

    local isUpdate = false
    for k,v in pairs(msg.updateData) do
        if k == "power" or k == "name" then
            isUpdate = true
        end
        unionData[k] = v
    end

    AnotherWorldBattleDB.UpdateUnionData(myUnionId, unionData)

    -- 如果是战力更新, 更新公会排行榜
    if isUpdate then
        AnotherWorldBattleDB.UpdateUnionRankList(groupId, myUnionId, 0, 0, unionData.power)
    end
end

-- 更新玩家据点防守阵容数据
function N2C_UpdatePointLineup_Req(msg)
    if not isRunning() then
        return
    end

    local playerUuid = msg.playerUuid
    local playerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    if not playerData or not playerData.heroList then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_5)
    end

    local groupId = getMyUnionGourpId(playerData.unionId)
    if not groupId then
        return
    end

    local targetCityId, targetPointIdx = msg.targetCityId, msg.targetPointIdx
    local heroList = playerData.heroList
    if not heroList[targetCityId] or not heroList[targetCityId][targetPointIdx] then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_5)
    end

    heroList[targetCityId][targetPointIdx] = msg.heroArr
    AnotherWorldBattleDB.UpdatePlayerData(playerUuid, playerData)

    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_UPDATE_POINT_LINEIP
    msgData.playerUuid = playerUuid
    msgData.targetCityId = targetCityId
    msgData.targetPointIdx = targetPointIdx
    msgData.formation = msg.formation
    msgData.heroList = msg.heroList
    msgData.helpList = msg.helpList
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    InnerMsg.sendMsg(fd, msgData)
end

-- 更新玩家英雄数据
function N2C_UpdateHeroData_Req(msg)
    if not isRunning() then
        return
    end

    local playerUuid = msg.playerUuid
    local playerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    if not playerData then
        return
    end

    local heroList = playerData.heroList
    if not heroList then
        return
    end

    local targetCityId, targetPointIdx = msg.targetCityId, msg.targetPointIdx
    if not heroList[targetCityId] or not heroList[targetCityId][targetPointIdx] then
        return
    end

    local isUpdate = false
    local newHeroData = msg.heroData
    local heroArr = heroList[targetCityId][targetPointIdx]

    for _, heroData in ipairs(heroArr) do
        if heroData.heroUuid == newHeroData.heroUuid then
            for k, v in pairs(newHeroData) do
                heroData[k] = v
            end

            isUpdate = true
            break
        end
    end

    if isUpdate then
        AnotherWorldBattleDB.UpdatePlayerData(playerUuid, playerData)
    end
end

-- 放弃据点
function N2C_LeavePoint_Req(msg)
    local playerUuid = msg.playerUuid
    local myUnionId = msg.myUnionId
    local targetCityId = msg.targetCityId
    local targetPointIdx = msg.targetPointIdx

    if not isRunning() then
        return
    end

    local groupId = getMyUnionGourpId(myUnionId)
    local cityData = AnotherWorldBattleDB.GetCityData(groupId, targetCityId)
    local targetPointData = cityData.pointArr[targetPointIdx]

    if not targetPointData.unionId or targetPointData.unionId ~= myUnionId or targetPointData.playerUuid ~= playerUuid then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_5)
    end

    local playerData = AnotherWorldBattleDB.GetPlayerData(playerUuid)
    if not playerData then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end

    local heroList = playerData.heroList
    if not heroList or not heroList[targetCityId] or not heroList[targetCityId][targetPointIdx] then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end


    local defUnionData = AnotherWorldBattleDB.GetUnionData(targetPointData.unionId)
    if not defUnionData then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end

    local defOccupCityList = defUnionData.occupCityList
    if not defOccupCityList then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end

    local defTargerCityData = defOccupCityList[targetCityId]
    if not defTargerCityData or not defTargerCityData.occupyPointList or not defTargerCityData.occupyPointList[targetPointIdx] then
        return errTips(msg.sourceServerId, msg.playerUuid, AnotherWorldBattleDefine.ERR_CODE_4)
    end

    local cityNum, pointNum = 0, -1

    -- 更新城池数据, 如果城池之前被本公会占领了, 则删除
    if cityData.occupyUnion and cityData.occupyUnion == myUnionId then
        cityData.occupyUnion = nil
    end

    -- 更新据点数据, 删除据点的 unionId, playerUuid
    targetPointData.unionId = nil
    targetPointData.playerUuid = nil

    -- 更新公会数据, 删除公会数据中占领该据点的玩家uuid
    local defTargetPointData = defTargerCityData.occupyPointList[targetPointIdx]
    defTargetPointData.playerUuid = nil

    -- 更新公会数据, 更新该据点最后占领时间段的结束时间
    if defTargetPointData.occupyTimeArr then
        local lastOccupyTimeTb = defTargetPointData.occupyTimeArr[#defTargetPointData.occupyTimeArr]
        lastOccupyTimeTb[2] = os.time()
    end

    -- 更新公会数据, 如果本公会之前占领了城池, 则修改占领状态
    if defTargerCityData and defTargerCityData.isOccupy then
        defTargerCityData.isOccupy = false
        cityNum = -1
    end

    -- 更新玩家数据, 删除玩家数据中该据点的防守数据
    heroList[targetCityId][targetPointIdx] = nil
    if not next(heroList[targetCityId]) then
        heroList[targetCityId] = nil
    end


    -- 更新公会数据
    AnotherWorldBattleDB.UpdateUnionData(myUnionId, defUnionData)
    -- 更新玩家数据
    AnotherWorldBattleDB.UpdatePlayerData(playerUuid, playerData)

    -- 更新公会的排行榜数据
    AnotherWorldBattleDB.UpdateUnionRankList(groupId, myUnionId, cityNum, pointNum)
    -- 更新玩家的排行榜数据
    local pointWeight = AnotherWorldBattleConfig.city[targetCityId].pointWeight
    AnotherWorldBattleDB.UpdatePlayerRankList(groupId, playerUuid, pointNum, -pointWeight)

    -- 更新城池数据
    AnotherWorldBattleDB.UpdateCityData(groupId, targetCityId, cityData)

    -- 通知普通服, 放弃据点成功
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_LEAVE_POINT
    msgData.playerUuid = playerUuid
    msgData.targetCityId = targetCityId
    msgData.targetPointIdx = targetPointIdx
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    InnerMsg.sendMsg(fd, msgData)

    N2C_GetAllCity_Req(msg)
end

-- 获取本公会士气信息
function N2C_GetMyUnionMoraleInfo_Req(msg)
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_GET_MYUIONMORALE
    msgData.playerUuid = msg.playerUuid
    msgData.moraleState = 0
    msgData.moraleAttrIdx = 1
    msgData.moraleStartTime = 0

    if not isRunning() then
        return InnerMsg.sendMsg(fd, msgData)
    end

    if not moraleCondTimeCheck() then
        msgData.moraleState = -1
        return InnerMsg.sendMsg(fd, msgData)
    end

    local myUnionData = AnotherWorldBattleDB.GetUnionData(msg.myUnionId)
    if not myUnionData then
        return InnerMsg.sendMsg(fd, msgData)
    end

    local now = os.time()
    if myUnionData.moraleData then
        -- 有士气加成且士气加成还没结束
        local moraleStartTime = myUnionData.moraleData.moraleStartTime or 0
        if moraleStartTime + AnotherWorldBattleDefine.AB_MORALE_DURATION >= now then
            msgData.moraleState = 2
            msgData.moraleStartTime = moraleStartTime
            msgData.moraleAttrIdx = myUnionData.moraleData.moraleAttrIdx or 1
            return InnerMsg.sendMsg(fd, msgData)
        end
    end

    local myRank = getUnionRank(msg.myUnionId)
    if myRank > 1 then --占领据点数量第一的公会不能加士气
        msgData.moraleState = 1
        msgData.moraleAttrIdx = myRank
    end

    InnerMsg.sendMsg(fd, msgData)
end

-- 给本公会加士气
function  N2C_UnionMorale_Do_Req(msg)
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    local msgData = InnerMsg.wl.WL_ANOTHERWORLDBATTLE_UIONMORALE_DO
    msgData.playerUuid = msg.playerUuid
    msgData.opRes = -1

    if not isRunning() then
        return InnerMsg.sendMsg(fd, msgData)
    end

    if not moraleCondTimeCheck() then
        return InnerMsg.sendMsg(fd, msgData)
    end

    local myUnionData = AnotherWorldBattleDB.GetUnionData(msg.myUnionId)
    if not myUnionData then
        return InnerMsg.sendMsg(fd, msgData)
    end

    local now = os.time()
    if myUnionData.moraleData then
        -- 有士气加成且士气加成还没结束
        local moraleStartTime = myUnionData.moraleData.moraleStartTime or 0
        if moraleStartTime + AnotherWorldBattleDefine.AB_MORALE_DURATION >= now then
            msgData.opRes = -2
            return InnerMsg.sendMsg(fd, msgData)
        end
    end

    local myRank = getUnionRank(msg.myUnionId)
    if myRank <= 1 then
        return InnerMsg.sendMsg(fd, msgData)
    end

    myUnionData.moraleData = myUnionData.moraleData or {}
    myUnionData.moraleData.moraleStartTime = now
    myUnionData.moraleData.moraleAttrIdx = myRank
    AnotherWorldBattleDB.UpdateUnionData(msg.myUnionId, myUnionData)
    msgData.opRes = 0
    InnerMsg.sendMsg(fd, msgData)

    N2C_GetMyUnionMoraleInfo_Req(msg)
end