-- 战区争霸(跨服)
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 AreaBattleDB = require("areaBattle.AreaBattleDB")
local AreaBattleDefine = require("areaBattle.AreaBattleDefine")
local CombatVideo = require("combat.CombatVideo")
local CombatDefine = require("combat.CombatDefine")
local CombatLogicCS = require("combat.CombatLogicCS")
local BattleDataCS = require("battleDataManager.BattleDataCS")

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

-- 玩家战斗数据缓存表
local battleDataCache = {}

-- 请求序列表, 用于向普通获取玩家战斗数据
local requestArr = {}


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 not table.find(AreaBattleDefine.OPEN_WDAY_AREA, wDay) then
        return false
    end

    local now = os.time()
    local toDayStartTime = getTodayStartTime()

    if wDay == AreaBattleDefine.OPEN_WDAY_AREA[1] and now < (toDayStartTime + AreaBattleDefine.PREPARE_STATE_START_SEC) then
        return false
    end

    if wDay == AreaBattleDefine.OPEN_WDAY_AREA[2] and now > (toDayStartTime + AreaBattleDefine.END_STATE_START_SEC) then
        return false
    end

    return true
end

-- 参战服务器日志格式: "serverId1, serverId2,serverId3"
-- 服务器匹配列表日志格式: "serverId1-serverId2-serverId3-serverId4", 从一个serverId开始, 按顺序每两个serverId匹配到一起战斗
-- 参战服务器信息日志个数: serverId | 本服战胜次数| 本服战败次数 | 战胜玩家uuid-战胜玩家uui
local function writeLog(logStr)
    Log.write(Log.LOGID_OSS_AREABATTLE_BATTLE, logStr)
end


-- 计算一个服的总战力
local function calcSrvPower(playerArray)
    local power = 0
    for _, v in ipairs(playerArray or {}) do
        power = power + (v.power or 0)
    end
    return power
end

-- 获取战斗对象的区服Id, uuid 
local function getBattleObjInfo(matchIdx, battleIdx, objIdentity)
    local matchSrvArr = AreaBattleDB.GetMatchSrvArr()

    local matchData = matchSrvArr[matchIdx]
    if not matchData then
        return
    end

    local targetSrvId = matchData[objIdentity]
    if not targetSrvId then
        return
    end

    local serverList = AreaBattleDB.GetServerList()
    if not serverList[targetSrvId] then
        return
    end

    local srvPlayerArr = serverList[targetSrvId].playerInfoArr
    local playerInfo = srvPlayerArr[battleIdx]

    return targetSrvId, playerInfo and playerInfo.uuid
end


-- 进入新一轮的处理
local function newRoundHandle()
    local stateDB = AreaBattleDB.GetState()

    -- 上一轮奖励没有发放, 在新一轮开始时, 先发奖
    if stateDB == AreaBattleDefine.STATE_AWARD then
        AwardPrizesHandle()
    end

    -- 清除录像数据
    CombatVideo.ClearOutVideoByCombatType(CombatVideo.VIDEOTYPE_AREABATTLE)

    -- 重置录像缓存
    AreaBattleDB.ResetVideoShowCache()

    -- 重置战区争霸数据
    AreaBattleDB.ResetData()

    -- 更新状态
    AreaBattleDB.UpdateState(AreaBattleDefine.STATE_PREPARE)

    -- 通知普通服
    NotifySrvJoin()


    -- 重置缓存数据
    battleDataCache = {}
    requestArr = {}
end

-- 服务器分组算法
local function matchAlgorithm(serverArr, len)
    local usedTb = {}
    local pairTb = {}

    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 i <= len and not usedTb[i] then
                table.insert(tbl, i)
            end
        end
        return tbl
    end

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

        local startIdx = currentIdx+1
        local endIdx = currentIdx+3
        local correctTb = checkRandIdx(startIdx, endIdx)
        local matchIdx = correctTb[math.random(1, #correctTb)]

        usedTb[currentIdx] = true
        usedTb[matchIdx] = true
        table.insert(pairTb, {serverArr[currentIdx], serverArr[matchIdx]})
        currentIdx = currentIdx + 1
    end

    return pairTb
end

-- 生成匹配列表
local function genMacthArr()
    local joinSrvArr = AreaBattleDB.GetJoinSrvArr()
    local joinSrvArr_cp = Util.copyTable(joinSrvArr)
    if not joinSrvArr_cp or #joinSrvArr_cp <= 0 then
        return
    end

    local srvCnt = #joinSrvArr_cp
    if srvCnt > 1 then
        if srvCnt % 2 ~= 0 then
            local deleteSrvId = joinSrvArr_cp[srvCnt]
            joinSrvArr_cp[srvCnt] = nil
            srvCnt = srvCnt - 1

            -- 新修改: 被移除的服务器为轮空服, 轮空服改为发战败服奖励, 发奖励时需要用到参战玩家数据, 所以不删除轮空服数据

            -- 把被移除的服务器从服务器数据列表中移除
            -- local serverList = AreaBattleDB.GetServerList()
            -- serverList[deleteSrvId] = nil
            -- AreaBattleDB.UpdateServerList(serverList)

            -- 记录日志
            local logStr = "移除多余的区服, 区服Id:  " .. deleteSrvId
            writeLog(logStr)
        end

        table.sort(joinSrvArr_cp)
        local matchArr = matchAlgorithm(joinSrvArr_cp, srvCnt)
        AreaBattleDB.UpdateMatchSrvArr(matchArr)
    end
end

-- 获取玩家的战斗数据
local function getPlayerBattleData(serverId, playerUuid, extraArgs)
    extraArgs.serverId = serverId
    extraArgs.playerUuid = playerUuid
    BattleDataCS.GetPlayerCombatData(serverId, playerUuid, BattleDataCS.AREABTTLE_TAG, CombatDefine.COMBAT_TYPE33, extraArgs)
end

-- 分批请求玩家战斗数据
function Timed_GetPlayerBattleData()
    if not requestArr or not next(requestArr) then
        return
    end

    local maxNum = math.min(#requestArr, AreaBattleDefine.GET_BATTLE_MAX_CNT_TIMES)
    for i=1, maxNum do
        local info = table.remove(requestArr)
        getPlayerBattleData(info[1], info[2], info[3])
    end

    if #requestArr > 0 then
        Timer.addLater(2, Timed_GetPlayerBattleData, requestArr)
    end
end

-- 向普通服请求战斗数据
local function requestPlayerBattleData()
    local matchSrvArr = AreaBattleDB.GetMatchSrvArr()
    local serverList = AreaBattleDB.GetServerList()
    if not matchSrvArr or #matchSrvArr == 0 or not next(serverList) then
        return
    end

    for idx, matchSrvTb in ipairs(matchSrvArr) do
        local serverId1 = matchSrvTb[1]
        local serverId2 = matchSrvTb[2]
        local playerArr1 = serverList[serverId1] and serverList[serverId1].playerInfoArr or {}
        local playerArr2 = serverList[serverId2] and serverList[serverId2].playerInfoArr or {}
        local maxPlayerCnt = math.max(#playerArr1, #playerArr2)

        for i=1, maxPlayerCnt do
            local playerUuid1 = playerArr1[i] and playerArr1[i].uuid
            local playerUuid2 = playerArr2[i] and playerArr2[i].uuid

            if playerUuid1 then
                local args = {
                    firstIdx = idx,
                    secondIdx = i,
                    identity = 1, --身份,1-进攻方, 2-防御方
                    serverId = 0,
                    playerUuid = "",
                }
                -- getPlayerBattleData(serverId1, playerUuid1, args)
                requestArr[#requestArr+1] = {serverId1, playerUuid1, args}
            end

            if playerUuid2 then
                local args = {
                    firstIdx = idx,
                    secondIdx = i,
                    identity = 2, --身份,1-进攻方, 2-防御方
                    serverId = 0,
                    playerUuid = "",
                }
                -- getPlayerBattleData(serverId2, playerUuid2, args)
                requestArr[#requestArr+1] = {serverId2, playerUuid2, args}
            end
        end
    end

    local now = os.time()
    AreaBattleDB.UpdateUpLoadStartTi(now)

    Timed_GetPlayerBattleData()
end



-- 处于准备阶段处理, 给服务器进行匹配, 并通知普通服上传玩家战斗数据
local function prepareHandle()
    local stateDB = AreaBattleDB.GetState()
    if stateDB ~= AreaBattleDefine.STATE_PREPARE then
        return
    end

    -- 服务器进行匹配
    genMacthArr()

    -- 让普通服上传战斗数据
    -- requestPlayerBattleData()
end

-- 上一轮 ~ 新一轮准备阶段的处理
local function earlyHanle()
    local now = os.time()
    local stateDB = AreaBattleDB.GetState()
    local nowRoundStartTi = AreaBattleDB.GetNowRoundStartTi()
    local diffDays = Util.diffDay(nowRoundStartTi)

    -- 开启新一轮活动
    if nowRoundStartTi <= 0 or diffDays >= 2 then
        return newRoundHandle()
    end

    -- 处于准备阶段, 普通服上传完本服排名前15的玩家数据后，如果还没有对服务器进行分组, 则生成服务器匹配列表, 并通知这些服务器上传本服玩家战斗数据
    if diffDays < 2 and now - nowRoundStartTi >= AreaBattleDefine.SERVER_DATA_TIME and stateDB == AreaBattleDefine.STATE_PREPARE then
        local matchSrvArr = AreaBattleDB.GetMatchSrvArr()
        if not matchSrvArr or not next(matchSrvArr) then
            prepareHandle()
        end
    end
end


-- 进入战斗阶段的处理
local function BattleStageHandle()
    local stateDB = AreaBattleDB.GetState()
    if stateDB ~= AreaBattleDefine.STATE_BATTLE then
        return
    end

    StartBattle()
end

-- 战斗结束,  把结果更新到DB
local function updateDBBattleResult(battleInfo)
    local attackerServerId = battleInfo.attackerServerId
    local attackerUuid = battleInfo.attackerUuid
    local defenerServerId = battleInfo.defenerServerId
    local defenerUuid = battleInfo.defenerUuid
    local isWin = battleInfo.isWin
    local serverList = AreaBattleDB.GetServerList()

    local attackerSrvData = serverList[attackerServerId]
    if attackerSrvData then
        if isWin == 1 then
            attackerSrvData.winTimes = (attackerSrvData.winTimes or 0) + 1
            attackerSrvData.winPlayerArr = attackerSrvData.winPlayerArr or {}
            table.insert(attackerSrvData.winPlayerArr, attackerUuid)
        else
            attackerSrvData.defeatTimes = (attackerSrvData.defeatTimes or 0) + 1
        end
    end

    local defenerSrvData = serverList[defenerServerId]
    if defenerSrvData then
        if isWin == 0 then
            defenerSrvData.winTimes = (defenerSrvData.winTimes or 0) + 1
            defenerSrvData.winPlayerArr = defenerSrvData.winPlayerArr or {}
            table.insert(defenerSrvData.winPlayerArr, defenerUuid)
        else
            defenerSrvData.defeatTimes = (defenerSrvData.defeatTimes or 0) + 1
        end
    end

    AreaBattleDB.UpdateServerList(serverList)
end

-- 检查服务器是否是轮空服
local function isByeServer(matchSrvArr, serverId)
    local isBye = true
    for _, serverTb in ipairs(matchSrvArr or {}) do
        if table.find(serverTb, serverId) then
            isBye = false
            break
        end
    end

    return isBye
end

-- 生成用于通知各个普通服发奖的数据
local function genNotifyInfo(serverInfo, matchSrvArr, serverId)
    local info = {
        isWin = 0,
        winPlayerArr = {},
        defeatPlayerArr = {},
        isBye = 0, -- 是否轮空
    }

    local isBye = isByeServer(matchSrvArr, serverId)

    if isBye then
        info.isBye = 1
    else
        if (serverInfo.winTimes or 0) > (serverInfo.defeatTimes or 0) then
            info.isWin = 1
        end

        for _, playerInfo in ipairs(serverInfo.playerInfoArr) do
            if table.find(serverInfo.winPlayerArr, playerInfo.uuid) then
                table.insert(info.winPlayerArr, playerInfo.uuid)
            else
                table.insert(info.defeatPlayerArr, playerInfo.uuid)
            end
        end
    end

    return info
end

-- 生成日志
local function genLog()
    local t1, t2 = {}, {}

    local joinSrvArr = AreaBattleDB.GetJoinSrvArr()
    for idx, srvId in ipairs(joinSrvArr or {}) do
        t1[idx] = srvId
    end
    local str1 = table.concat(t1, ",")
    writeLog(str1)


    local len = 0
    local matchSrvArr = AreaBattleDB.GetMatchSrvArr()
    for _, srvTb in ipairs(matchSrvArr or {}) do
        for _, servrId in ipairs(srvTb) do
            len = len + 1
            t2[len] = servrId
        end
    end

    local str2 = table.concat(t2, "-")
    writeLog(str2)



    local serverList = AreaBattleDB.GetServerList()
    for serverId, srvInfo in pairs(serverList or {}) do
        local t = {serverId, srvInfo.winTimes or 0, srvInfo.defeatTimes or 0}
        if srvInfo.winPlayerArr and #srvInfo.winPlayerArr > 0 then
            local s = table.concat(Util.copyTable(srvInfo.winPlayerArr), "-")
            table.insert(t, s)
        end

        local str3 = table.concat(t, "|")
        writeLog(str3)
    end
end


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

-- 通知普通服，争霸开始
function NotifySrvJoin()
    local msgData = InnerMsg.wl.WL_AREABATTLE_OPEN
    local fdList = MiddleManager.MiddleManager_GetAllFD()
    for _, fd in pairs(fdList) do
        InnerMsg.sendMsg(fd, msgData)
    end
end

-- 通知普通服发奖
function NotifySrvAwardPrizes(fd, args)
    local msgData = InnerMsg.wl.WL_AREABATTLE_SEND_REWARD
    msgData.srvBattleRes = args
    InnerMsg.sendMsg(fd, msgData)
end

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

-- 普通服加入战斗
function N2C_JoinBattle(msg)
    local sourceServerId = msg.sourceServerId
    local joinBattleArray = msg.joinBattleArray

    local joinSrvArr = AreaBattleDB.GetJoinSrvArr()
    local serverList = AreaBattleDB.GetServerList()

    if not table.find(joinSrvArr, sourceServerId) and not serverList[sourceServerId] then
        -- 参战列表
        table.insert(joinSrvArr, sourceServerId)
        AreaBattleDB.UpdateJoinSrvArr(joinSrvArr)

        -- 服务器列表
        serverList[sourceServerId] = {
            winTimes = 0,
            defeatTimes = 0,
            winPlayerArr = {},
            playerInfoArr = joinBattleArray
        }
        AreaBattleDB.UpdateServerList(serverList)
    end
end

-- 普通服请求争霸活动的基本数据
function N2C_GetBaseInfo(msg)
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    local msgData = InnerMsg.wl.WL_AREABATTLE_BASEINFO_QUERY
    msgData.playerUuid = msg.playerUuid

    local state = AreaBattleDB.GetState()
    msgData.stage = state
    msgData.startTime, msgData.endTime = 0, 0
    local toDayStartTime = getTodayStartTime()

    if not wDay then
        updateWDay()
    end

    if wDay == AreaBattleDefine.OPEN_WDAY_AREA[1] then
        msgData.startTime = toDayStartTime + AreaBattleDefine.PREPARE_STATE_START_SEC
        msgData.endTime = toDayStartTime + 86400 + AreaBattleDefine.END_STATE_START_SEC

    elseif wDay == AreaBattleDefine.OPEN_WDAY_AREA[2] then
        msgData.startTime = toDayStartTime - 86400 + AreaBattleDefine.PREPARE_STATE_START_SEC
        msgData.endTime = toDayStartTime + AreaBattleDefine.END_STATE_START_SEC

        local now = os.time()
        if state == AreaBattleDefine.STATE_AWARD and now < toDayStartTime + AreaBattleDefine.END_STATE_START_SEC then
            msgData.stage = AreaBattleDefine.STATE_BATTLE
        end
    else
        local subDay = AreaBattleDefine.OPEN_WDAY_AREA[1] - wDay
        msgData.startTime = toDayStartTime + subDay * 86400 + AreaBattleDefine.PREPARE_STATE_START_SEC
        msgData.endTime = toDayStartTime + (subDay + 1) * 86400 + AreaBattleDefine.END_STATE_START_SEC
    end

    InnerMsg.sendMsg(fd, msgData)
end

-- 普通服请求本服参战玩家列表
function N2C_GetJoinPlayerArr(msg)
    local sourceServerId = msg.sourceServerId
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    local msgData = InnerMsg.wl.WL_AREABATTLE_JOINPLAYER_QUERY
    msgData.errCode = 0
    msgData.playerArray = {}
    msgData.playerUuid = msg.playerUuid

    local joinSrvArr = AreaBattleDB.GetJoinSrvArr()
    local mathcList = AreaBattleDB.GetMatchSrvArr()

    -- 没有参加
    if not joinSrvArr or not table.find(joinSrvArr, sourceServerId) then
        msgData.errCode = -1
        return InnerMsg.sendMsg(fd, msgData)
    end

    -- 匹配列表还没生成
    if not mathcList or not next(mathcList) then
        msgData.errCode = -2
        return InnerMsg.sendMsg(fd, msgData)
    end


    local isInMathcArr = false
    for _, matchSrvTb in ipairs(mathcList) do
        if table.find(matchSrvTb, sourceServerId) then
            isInMathcArr = true
            break
        end
    end
    -- 参加了，但是被移除, 没有在本轮匹配列表中
    if not isInMathcArr then
        msgData.errCode = -3
        return InnerMsg.sendMsg(fd, msgData)
    end

    local serverList = AreaBattleDB.GetServerList()
    msgData.playerArray = serverList[sourceServerId] and serverList[sourceServerId].playerInfoArr or {}
    InnerMsg.sendMsg(fd, msgData)
end


-- 普通服请求本次参战的区服的匹配列表
-- {    { {server1, power1}, {server2, power2} },   }
function N2C_GetMatchList(msg)
    local sourceServerId = msg.sourceServerId
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    local msgData = InnerMsg.wl.WL_AREABATTLE_MATCHLIST_QUERY
    msgData.playerUuid = msg.playerUuid
    msgData.matchList = {}

    local mathcList = AreaBattleDB.GetMatchSrvArr()
    local serverList = AreaBattleDB.GetServerList()

    for k, matchSrvTb in ipairs(mathcList) do
        msgData.matchList[k] = {}

        for idx, serverId in ipairs(matchSrvTb) do
            if serverList[serverId] then
                -- table.insert(msgData.matchList[k], serverId)
                local power = calcSrvPower(serverList[serverId].playerInfoArr)
                -- table.insert(msgData.matchList[k], power)
                msgData.matchList[k][idx] = {serverId, power}
            end
        end

    end

    InnerMsg.sendMsg(fd, msgData)
end

-- 普通服请求本服的战斗录像展示数据
function N2C_GetVideoShowData(msg)
    local sourceServerId = msg.sourceServerId
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)

    local msgData = InnerMsg.wl.WL_AREABATTLE_VIDEOSHOW_QUERY
    msgData.errCode = 0
    msgData.playerUuid = msg.playerUuid
    msgData.videoShowData = {}
    msgData.srvInfo = {}

    local state = AreaBattleDB.GetState()
    if state ~= AreaBattleDefine.STATE_AWARD and state ~= AreaBattleDefine.STATE_END then
        msgData.errCode = -1
        return InnerMsg.sendMsg(fd, msgData)
    end

    local videoSecondIdx, leftSrvId, rightSrvId = 0, 0, 0
    local matchSrvArr = AreaBattleDB.GetMatchSrvArr()
    for k, srvTb in ipairs(matchSrvArr or {}) do
        if table.find(srvTb, sourceServerId) then
            videoSecondIdx = k
            leftSrvId = srvTb[1]
            rightSrvId = srvTb[2]
            break
        end
    end

    -- 本轮没有参加活动
    if videoSecondIdx == 0 then
        msgData.errCode = -3
        return InnerMsg.sendMsg(fd, msgData)
    end


    local serverList = AreaBattleDB.GetServerList()
    if serverList[leftSrvId] then
        msgData.srvInfo.leftSrvId = leftSrvId
        msgData.srvInfo.leftWinTimes = serverList[leftSrvId].winTimes or 0
        msgData.srvInfo.leftSrvPower = calcSrvPower(serverList[leftSrvId].playerInfoArr)
    end

    if serverList[rightSrvId] then
        msgData.srvInfo.rightSrvId = rightSrvId
        msgData.srvInfo.rightWinTimes = serverList[rightSrvId].winTimes or 0
        msgData.srvInfo.rightSrvPower = calcSrvPower(serverList[rightSrvId].playerInfoArr)
    end


    local videoArr = AreaBattleDB.GetSrvVideoShowData(videoSecondIdx)
    -- msgData.videoShowData = videoArr

    for _, v in ipairs(videoArr or {}) do
        if (v.atkData and v.atkData.uuid == msg.playerUuid) or (v.defenerData and v.defenerData.uuid == msg.playerUuid) then
            table.insert(msgData.videoShowData, 1, v)
        else
            msgData.videoShowData[#msgData.videoShowData+1] = v
        end

    end

    InnerMsg.sendMsg(fd, msgData)
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

    local now = os.time()
    local toDayStartTime = getTodayStartTime()

    -- 活动第一天, 当前时间 >= 开启时间
    if wDay == AreaBattleDefine.OPEN_WDAY_AREA[1] then
        earlyHanle()
    end

    -- 活动最后一天, 当前时间 < 活动结束时间
    if wDay == AreaBattleDefine.OPEN_WDAY_AREA[2] then

        earlyHanle()

        local stateDB = AreaBattleDB.GetState()
        -- local nowRoundStartTi = AreaBattleDB.GetNowRoundStartTi()

        -- 当前处于准备阶段, 但是当前时间 >= 对战开始时间, 则进入对战阶段
        if now >= (toDayStartTime + AreaBattleDefine.BATTLE_STATE_START_SEC) and stateDB == AreaBattleDefine.STATE_PREPARE then
            -- 防止某些情况下，进入准备阶段后普通服数据还没上传完就进入对战阶段
            local upLoadStartTi = AreaBattleDB.GetUpLoadStartTi()
            if now - upLoadStartTi > AreaBattleDefine.BATTLE_DATA_TIME then

                -- 重启跨服后导致战斗数据缓存没了，则重新获取。 -- 新逻辑: 每次进入战斗阶段时才让普通服上传玩家战斗数据
                if not next(battleDataCache) then
                    if #requestArr == 0 then
                        return requestPlayerBattleData()
                    end
                end

                -- 处于请求战斗数据过程中, 等请求完再进入战斗
                if #requestArr > 0 then
                    return
                end

                AreaBattleDB.UpdateState(AreaBattleDefine.STATE_BATTLE)
                BattleStageHandle()
                return
            end
        end

        -- 当前时间 >= 发奖时间
        if now >= (toDayStartTime + AreaBattleDefine.END_STATE_START_SEC) and stateDB == AreaBattleDefine.STATE_AWARD then
            AwardPrizesHandle()
            AreaBattleDB.UpdateState(AreaBattleDefine.STATE_END)
        end
    end
end

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

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

    if not table.find(AreaBattleDefine.OPEN_WDAY_AREA, wDay) then
        return
    end

    -- 对战阶段
    if wDay == AreaBattleDefine.OPEN_WDAY_AREA[2] and hour >= 12 then
        local now = os.time()
        local stateDB = AreaBattleDB.GetState()
        -- local nowRoundStartTi = AreaBattleDB.GetNowRoundStartTi()
        local upLoadStartTi = AreaBattleDB.GetUpLoadStartTi()

        -- 防止某些情况下，进入准备阶段后，普通服数据还没上传完就进入对战阶段
        if stateDB == AreaBattleDefine.STATE_PREPARE and (now - upLoadStartTi > AreaBattleDefine.BATTLE_DATA_TIME) then

            -- 重启跨服后导致战斗数据缓存没了，则重新获取。-- 新逻辑: 每次进入战斗阶段时才让普通服上传玩家战斗数据
            if not next(battleDataCache) then
                -- 可能存在响应比较慢的情况，保证只执行一次 requestPlayerBattleData
                if #requestArr == 0 then
                    return requestPlayerBattleData()
                end
            end

            -- 处于请求战斗数据过程中, 等请求完再进入战斗
            if #requestArr > 0 then
                return
            end

            AreaBattleDB.UpdateState(AreaBattleDefine.STATE_BATTLE)
            BattleStageHandle()
        end
    end

    -- 发奖阶段
    if wDay == AreaBattleDefine.OPEN_WDAY_AREA[2] and hour >= 22 then
        local stateDB = AreaBattleDB.GetState()
        if stateDB == AreaBattleDefine.STATE_AWARD then
            AwardPrizesHandle()
            AreaBattleDB.UpdateState(AreaBattleDefine.STATE_END)
        end
    end
end


-- 通知普通服发奖
function BrocastServer(srvTb)
    for fd, notifyInfo in pairs(srvTb) do
        NotifySrvAwardPrizes(fd, notifyInfo)
    end
end

-- 分批次通知普通服
function BatchServer()
    local matchSrvArr = AreaBattleDB.GetMatchSrvArr()
    if not matchSrvArr or not next(matchSrvArr) then
        return
    end

    local len, delay_sec = 0, 0
    local srvTb = {}
    local serverList = AreaBattleDB.GetServerList()
    for serverId, serverInfo in pairs(serverList or {}) do
        local fd = MiddleManager.getFDBySvrIndex(serverId)
        if fd then
            len = len + 1
            local notifyInfo = genNotifyInfo(serverInfo, matchSrvArr, serverId)
            srvTb[fd] = notifyInfo
        end

        if len >= AreaBattleDefine.BATCH_MAX_SRV_NUM then
            delay_sec = delay_sec + 5
            Timer.addLater(delay_sec, BrocastServer, srvTb)
            srvTb = {}
            len = 0
        end
    end

    if len > 0 then
        delay_sec = delay_sec + 5
        Timer.addLater(delay_sec, BrocastServer, srvTb)
    end
end

-- 发奖
function AwardPrizesHandle()
    genLog()
    BatchServer()
end


-- 开始战斗
function StartBattle()
    for firstIdx, battleDList in pairs(battleDataCache) do
        for secondIdx, playerBattleData in pairs(battleDList) do
            local attackerInfo = playerBattleData.attackerInfo
            local defenerInfo = playerBattleData.defenerInfo

            local args = {
                isWin = 0,
                attackerServerId = "",
                attackerUuid = "",
                defenerServerId = "",
                defenerUuid = ""
            }

            if attackerInfo and defenerInfo then -- 正常情况
                args.attackerServerId = attackerInfo.serverId
                args.attackerUuid = attackerInfo.playerUuid
                args.defenerServerId = defenerInfo.serverId
                args.defenerUuid = defenerInfo.playerUuid
                args.videoSecondIdx = firstIdx

                -- CombatLogicCS.combatBegin(attackerInfo.battleData, defenerInfo.battleData, CombatDefine.COMBAT_TYPE33, FightEnd, args)
                local ok, err = pcall(CombatLogicCS.combatBegin, attackerInfo.battleData, defenerInfo.battleData, CombatDefine.COMBAT_TYPE33, FightEnd, args)
                if not ok then
                    local str = string.format("BattleErr, firstIdx: %d, secondIdx: %d, attackerSrvId: %d, defenerSrvId: %d, attackerUuid: %s, defenerUuid: %s, err: %s", 
                    firstIdx, secondIdx, args.attackerServerId, args.defenerServerId, args.attackerUuid, args.defenerUuid, err)
                    writeLog(str)
                end

            elseif attackerInfo or defenerInfo then
                -- 有一方战斗数据异常, 则跳过战斗，有战斗数据的一方胜利
                local errPlayerIdx = 1
                if attackerInfo then
                    args.isWin = 1
                    args.attackerServerId = attackerInfo.serverId
                    args.attackerUuid = attackerInfo.playerUuid

                    local srvId, playerUuid = getBattleObjInfo(firstIdx, secondIdx, 2)
                    args.defenerServerId = srvId
                    args.defenerUuid = playerUuid

                    errPlayerIdx = 2
                else
                    local srvId, playerUuid = getBattleObjInfo(firstIdx, secondIdx, 1)
                    args.attackerServerId = srvId
                    args.attackerUuid = playerUuid

                    args.isWin = 0
                    args.defenerServerId = defenerInfo.serverId
                    args.defenerUuid = defenerInfo.playerUuid
                end

                updateDBBattleResult(args)

                local str = string.format("BattleDataERR，Err Identity: %d, firstIdx: %d, secondIdx: %d", errPlayerIdx, firstIdx, secondIdx)
                writeLog(str)
            end
        end
    end

    AreaBattleDB.UpdateState(AreaBattleDefine.STATE_AWARD)

    battleDataCache = {}
end

-- 外部调用
-- 收到玩家的战斗数据后, 进行缓存
function BattleDataHanle(msg)
    if msg.errCode == 1 then
        local extraArgs = msg.extraArgs
        local firstIdx = extraArgs.firstIdx
        local secondIdx = extraArgs.secondIdx
        local identity = extraArgs.identity

        battleDataCache[firstIdx] = battleDataCache[firstIdx] or {}
        battleDataCache[firstIdx][secondIdx] = battleDataCache[firstIdx][secondIdx] or {}
        local targetTb = battleDataCache[firstIdx][secondIdx]


        local playerBattleData = nil
        if identity == 1 then
            if not targetTb.attackerInfo then
                targetTb.attackerInfo = {}
                playerBattleData = targetTb.attackerInfo
            end
        end

        if identity == 2 then
            if not targetTb.defenerInfo then
                targetTb.defenerInfo = {}
                playerBattleData = targetTb.defenerInfo
            end
        end

        if playerBattleData then
            -- playerBattleData.errCode = errCode
            playerBattleData.serverId = extraArgs.serverId
            playerBattleData.playerUuid = extraArgs.playerUuid
            playerBattleData.battleData = {
                objList = msg.objList,
                helpList = msg.helpList,
                roleBase = msg.roleBase,
                formation = msg.formation,
                jiBan = msg.jiBan,
                elfList = msg.elfList,
            }
        end
    end

    -- 开始进入战斗
    -- StartBattle()
end

-- 外部调用, 来自本模块的战斗结束后的回调函数
function FightEnd(result, combatType, combatInfo, extraArgs)
    if result == CombatDefine.RESULT_WIN then
        extraArgs.isWin = 1
    end

    updateDBBattleResult(extraArgs)

    combatInfo.time = os.time()
    CombatVideo.SaveCombatVideo(CombatVideo.VIDEOTYPE_AREABATTLE, combatInfo, extraArgs.videoSecondIdx)
end