-- 跨服商业活动-巅峰战场(跨服)

local Msg = require("core.Msg")
local Timer = require("core.Timer")
local DB = require("common.DB")
local CommonDB = require("common.CommonDB")
local CommonDefine = require("common.CommonDefine")
local Log = require("common.Log")
local LuaMongo = _G.lua_mongo
local Util = require("common.Util")
local Grid = require("bag.Grid")
local MiddleConnect = require("middle.MiddleConnect")
local InnerMsg = require("core.InnerMsg")
local MiddleManager = require("middle.MiddleManager")
local NpcConfig = require("excel.jjc").skyladdernpc
local CreateRole = require("role.CreateRole")
local ServerCommerceActDefine = require("serverCommerce.ServerCommerceActDefine")
local CombatDefine = require("combat.CombatDefine")

local dbUpdate = {_id=nil}
local dbUpdateField = {}

local RANK_SHOW_NUM = 50    -- 排行榜显示的数量
local repeateServerIdList = {}

local battleGroundData = {
    -- allAreaRankList = { -- 各个战区排行榜, 榜上的都是真实玩家
    --     [WarZoneServerIdx] = {
    --         [rank] = {
    --             rank = rank,
    --             serverId = serverId,
    --             playerUuid = playerUuid,
    --             name = name,
    --             bodyId = bodyId,
    --             headId = headId,
    --             headFrameId = headFrameId,
    --             heroArr = {heroId1, heroId2},
    --         },
    --     },
    -- },

    -- generaRankList = {   -- 通用排行榜(榜上都是机器人)，各个战区排行榜上没有真实玩家或对应排名没有真实玩家时, 使用该排行榜
    --         [rank] = {
    --             rank = rank,
    --             serverId = serverId,
    --             playerUuid = playerUuid,
    --             name = name,
    --             bodyId = bodyId,
    --             headId = headId,
    --             headFrameId = headFrameId,
    --             monsterOutID = monsterOutID, -- 机器人才有
    --             heroArr = {heroId1, heroId2},
    --         },
    --     },
    -- },

    -- joinList = { -- 参加过该活动的玩家列表
    --     -- {serverId, playerUuid},
    --     -- {serverId2, playerUuid2},
    -- },
}


-- 生成一个排行榜列表
local function genRankList(rankList)
    local function genPlayerData(player, tNpcConfig, rank)
        local r = math.random(1, #tNpcConfig.monsterOutID)
        player.rank = rank
        player.name = CreateRole.getRandomName()
        player.headId = CreateRole.getRandomHead()
        player.headFrameId = CreateRole.getRandomHeadFrame()
        player.bodyId = CreateRole.getRandomBody()
        player.playerUuid = tNpcConfig.monsterOutID[r]
        player.monsterOutID = tNpcConfig.monsterOutID[r]
    end

    local rank = 1
    for _, cfg in ipairs(NpcConfig) do
        for i = 1, cfg.cnt do
            rankList[rank] = {}
            genPlayerData(rankList[rank], cfg, rank)
            rank = rank + 1
            if rank > ServerCommerceActDefine.COMMERCEACT_NPC_CNT then
                break
            end
        end
    end
end

-- 插入数据
local function insertData(data)
    LuaMongo.insert(DB.db_battleground, data)
end
-- 修改db单个字段
local function updateValue(key, value)
	if not key then return end

    if value then
		dbUpdateField["$set"] = {[key]=value}
		dbUpdateField["$unset"] = nil
	else
		dbUpdateField["$set"] = nil
		dbUpdateField["$unset"] = {[key]=1}
	end

	dbUpdate._id = battleGroundData._id
	LuaMongo.update(DB.db_battleground, dbUpdate, dbUpdateField)
end

-- 保存所有数据
local function saveAllData()
    dbUpdate._id = battleGroundData._id
    LuaMongo.update(DB.db_battleground, dbUpdate, battleGroundData)
end

local function loadData()
    LuaMongo.find(DB.db_battleground)
    local data = {}
    if LuaMongo.next(data) then
        battleGroundData = data
    end

    if battleGroundData.allAreaRankList and next(battleGroundData.allAreaRankList) then
        for areaIdx, rankList in pairs(battleGroundData.allAreaRankList) do
            battleGroundData.allAreaRankList[areaIdx] = {}
            for _, player in pairs(rankList) do
                battleGroundData.allAreaRankList[areaIdx][player.rank] = player
            end
        end
    end

    if not battleGroundData.generaRankList then
        battleGroundData.generaRankList = {}
        genRankList(battleGroundData.generaRankList)
        insertData(battleGroundData)
    end

    table.sort(battleGroundData.generaRankList, function (a, b)
        return a.rank < b.rank
    end)
end



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

function onZero()
    if next(repeateServerIdList) then
        repeateServerIdList = {}
    end
end


-- 通过本服Id获取所在战区Id
local function getWarZoneServerIdx(sourceServerId)
    local nServerKey = MiddleConnect.MiddleConnect_TrueServerID2ConfServerID(sourceServerId)
    nServerKey = MiddleConnect.MiddleConnect_GetWarZoneServer(nServerKey)
    return nServerKey
end

-- 通服务器Id获取所在战区Id的最小服务器Id,最大服务器Id
local function getWarZoneServerArea(sourceServerId)
    local nServerKey = MiddleConnect.MiddleConnect_TrueServerID2ConfServerID(sourceServerId)
    return MiddleConnect.MiddleConnect_GetWarZoneServer(nServerKey)
end

-- 生成一个战区排行榜
local function genWarZoneRankList(warZoneServerIdx)
    local isInsert = false
    if not next(battleGroundData) then
        isInsert = true
    end

    battleGroundData.allAreaRankList = battleGroundData.allAreaRankList or {}
    battleGroundData.allAreaRankList[warZoneServerIdx] = {}
    genRankList(battleGroundData.allAreaRankList[warZoneServerIdx])

    if isInsert then
        return insertData(battleGroundData)
    end

    updateValue("allAreaRankList".."."..warZoneServerIdx, battleGroundData.allAreaRankList[warZoneServerIdx])
end

-- 获取本服所在战区的排行榜
local function getMyWarZoneRankList(sourceServerId)
    local warZoneServerIdx = getWarZoneServerIdx(sourceServerId)
    if not battleGroundData.allAreaRankList or not battleGroundData.allAreaRankList[warZoneServerIdx] then
        -- genWarZoneRankList(warZoneServerIdx)
        return
    end

    return battleGroundData.allAreaRankList[warZoneServerIdx]
end

-- 初始化本战区的排行榜
local function initMyWarZoneRankList(sourceServerId)
    local warZoneServerIdx = getWarZoneServerIdx(sourceServerId)
    if not battleGroundData.allAreaRankList or not battleGroundData.allAreaRankList[warZoneServerIdx] then
        battleGroundData.allAreaRankList = battleGroundData.allAreaRankList or {}
        battleGroundData.allAreaRankList[warZoneServerIdx] = {}
    end
end

-- 获取通用排行榜
local function getGeneraRankList()
    return battleGroundData.generaRankList
end

-- 通过玩家uuid获取排名
local function getPlayerRankByUuid(rankList, targetPlayerUuid)
    local targetRank = ServerCommerceActDefine.COMMERCEACT_NPC_CNT + 1
    if not rankList then
        return targetRank
    end

    for rank, rankInfo in pairs(rankList) do
        if rankInfo.playerUuid == targetPlayerUuid then
            targetRank = rank
            break
        end
    end

    return targetRank
end

-- 遍历
local function findVal(list, val)
    for k, info in pairs(list or {}) do
        if info[2] == val then
            return k
        end
    end
end

local function writeLog(logStr)
    Log.write(Log.LOGID_OSS_COMMON_ACT, logStr)
end

-- 发奖
local function issueReward(fd, rankArr)
    local msgData = InnerMsg.wl.WL_BATTLEGROUND_NOTIFY_PRIZEAWARD
    msgData.playerArr = rankArr
    InnerMsg.sendMsg(fd, msgData)
end




-- 普通服请求玩家排名
function BG_N2C_PlayerRank_Req(msg)
    local msgData = InnerMsg.wl.WL_BATTLEGROUND_PLAYER_RANK_QUERY
    msgData.playerRank = 0
    msgData.playerUuid = msg.playerUuid

    local myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    msgData.playerRank = getPlayerRankByUuid(myWarZoneRankList, msg.playerUuid)

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

-- 普通服请求对手数据
function BG_N2C_MatchList_Req(msg)
    local msgData = InnerMsg.wl.WL_BATTLEGROUND_MATCHLIST_QUERY
    msgData.playerUuid = msg.playerUuid
    msgData.playerInfoList = {}

    local myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    local generaRankList = getGeneraRankList()

    for _, rank in ipairs(msg.matchList) do
        local rankInfo = myWarZoneRankList and myWarZoneRankList[rank] or generaRankList[rank]
        if rankInfo then
            msgData.playerInfoList[#msgData.playerInfoList+1] = {
                rank = rank,
                serverId = rankInfo.serverId,
                name = rankInfo.name,
                showBodyId = rankInfo.bodyId
            }
        end
    end

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

-- 普通服请求玩家数据
function BG_N2C_PlayerData_Req(msg)
    local msgData = InnerMsg.wl.WL_BATTLEGROUND_PLAYER_DATA_QUERY
    msgData.playerUuid = msg.playerUuid
    msgData.playerInfo = {}

    local myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    local generaRankList = getGeneraRankList()
    local rankInfo = myWarZoneRankList and myWarZoneRankList[msg.playerRank] or generaRankList[msg.playerRank]

    if rankInfo then
        msgData.playerInfo.serverId = rankInfo.serverId
        msgData.playerInfo.name = rankInfo.name
        msgData.playerInfo.heroHeadId = rankInfo.headId
        msgData.playerInfo.heroHeadFrameId = rankInfo.headFrameId
        msgData.playerInfo.monsteroutId = 0

        if rankInfo.serverId then -- 真实玩家
            msgData.playerInfo.heroArr = {}
            for _, heroId in ipairs(rankInfo.heroArr or {}) do
                msgData.playerInfo.heroArr[#msgData.playerInfo.heroArr+1] = heroId
            end
        else
            -- 机器人
            msgData.playerInfo.monsteroutId = rankInfo.monsterOutID
        end
    end

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

-- 普通服请求排行榜数据
function BG_N2C_RankList_Req(msg)
    local msgData = InnerMsg.wl.WL_BATTLEGROUND_RANKLIST_QUERY
    msgData.playerUuid = msg.playerUuid
    msgData.rankList = {}

    local myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    local generaRankList = getGeneraRankList()

    for rank=1, RANK_SHOW_NUM do
        local rankInfo = myWarZoneRankList and myWarZoneRankList[rank] or generaRankList[rank]
        msgData.rankList[rank] = {
            rank = rank,
            serverId = rankInfo.serverId,
            name = rankInfo.name,
            heroHeadId = rankInfo.headId,
            heroHeadFrameId = rankInfo.headFrameId,
            playerUuid = rankInfo.playerUuid,
        }
    end

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

-- 玩家请求挑战某个排名
function BG_N2C_Challenge_Req(msg)
    local msgData = InnerMsg.wl.WL_BATTLEGROUND_CHALLENGE_QUERY
    msgData.playerUuid = msg.playerUuid
    msgData.playerInfo = {}
    msgData.errCode = 0
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)

    local targetRank = msg.rank
    local myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    local generaRankList = getGeneraRankList()
    local targetRanker = myWarZoneRankList and myWarZoneRankList[targetRank] or generaRankList[targetRank]
    if not targetRanker then
        msgData.errCode = -1
        return InnerMsg.sendMsg(fd, msgData)
    end

    msgData.playerInfo = {
        rank = targetRank,
        playerUuid = targetRanker.playerUuid,
        defServerId = targetRanker.serverId or 0
    }

    InnerMsg.sendMsg(fd, msgData)
end

-- 挑战结束
function BG_N2C_Challenge_End(msg)
    local atkPlayerUuid = msg.playerUuid
    local atkRank = msg.atkRank
    local defRank = msg.defRank
    local challengeRes = msg.challengeRes

    -- 加入参与列表
    battleGroundData.joinList = battleGroundData.joinList or {}
    if not findVal(battleGroundData.joinList, atkPlayerUuid) then
        battleGroundData.joinList[#battleGroundData.joinList+1] = {msg.sourceServerId, atkPlayerUuid}
        updateValue("joinList", battleGroundData.joinList)
    end

    -- 挑战没有胜利
    if challengeRes ~= CombatDefine.RESULT_WIN then
        return
    end

    local myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    if not myWarZoneRankList then
        initMyWarZoneRankList(msg.sourceServerId)
        myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    end


    -- 如果挑战方在榜上, 则检查当前排名与挑战时排名是否一致, 如果不一致则获取最新排名
    local atkRanker = myWarZoneRankList[atkRank]
    if atkRanker and atkRanker.playerUuid ~= atkPlayerUuid then
        atkRank = getPlayerRankByUuid(myWarZoneRankList, msg.playerUuid)
    end


    local msgData = InnerMsg.wl.WL_BATTLEGROUND_NOTIFY_PLAYER
    local fd = MiddleManager.getFDBySvrIndex(msg.sourceServerId)
    msgData.playerUuid = msg.playerUuid
    msgData.newRank = atkRank
    msgData.atkeServerId = msg.sourceServerId
    msgData.atkName = atkRanker and atkRanker.name or msg.playerShowData.name or ""
    msgData.updateType = 0

    -- 如果挑战者排名高于被挑战者排名, 则只通知挑战者刷新匹配列表
    if atkRank < defRank then
        return InnerMsg.sendMsg(fd, msgData)
    end

    local defTemp = myWarZoneRankList[defRank]


    -- 如果挑战方在榜上, 则先把挑战方从排行榜上移除
    if atkRank <= ServerCommerceActDefine.COMMERCEACT_NPC_CNT then
        myWarZoneRankList[atkRank] = nil
    end

    -- 第一次挑战, 则使用生成的玩家数据
    if not atkRanker then
        atkRanker = msg.playerShowData
    end
    -- 把挑战方加入到排行榜上, 排名为防守方原排名
    atkRanker.rank = defRank
    myWarZoneRankList[defRank] = atkRanker

    -- 如果双方都在榜上, 则被挑战方排名下降为挑战方原排名
    if defTemp and atkRank <= ServerCommerceActDefine.COMMERCEACT_NPC_CNT then
        defTemp.rank = atkRank
        myWarZoneRankList[atkRank] = defTemp
    end

    -- 保存排行榜数据
    local warZoneServerIdx = getWarZoneServerIdx(msg.sourceServerId)
    updateValue("allAreaRankList".."."..warZoneServerIdx, battleGroundData.allAreaRankList[warZoneServerIdx])


    -- 通知挑战者排名提高
    fd = MiddleManager.getFDBySvrIndex(atkRanker.serverId)
    msgData.playerUuid = atkRanker.playerUuid
    msgData.newRank = atkRanker.rank
    msgData.atkeServerId = msg.sourceServerId
    msgData.atkName = atkRanker.name
    msgData.updateType = 1
    InnerMsg.sendMsg(fd, msgData)

    -- 如果被挑战方是真实玩家, 则通知
    if defTemp and defTemp.serverId and defTemp.serverId ~= 0 then
        msgData.playerUuid = defTemp.playerUuid
        msgData.newRank = defTemp.rank
        msgData.updateType = 2
        fd = MiddleManager.getFDBySvrIndex(defTemp.serverId)
        InnerMsg.sendMsg(fd, msgData)
    end
end

-- 更换战斗阵容
function BG_N2C_Lineup_Update(msg)
    local myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    local myRank = getPlayerRankByUuid(myWarZoneRankList, msg.playerUuid)
    if myRank > ServerCommerceActDefine.COMMERCEACT_NPC_CNT then
        return
    end

    myWarZoneRankList[myRank].heroArr = msg.heroArr
    local warZoneServerIdx = getWarZoneServerIdx(msg.sourceServerId)
    updateValue("allAreaRankList".."."..warZoneServerIdx, battleGroundData.allAreaRankList[warZoneServerIdx])
end



-- 活动结束
function BG_N2C_Act_End(msg)
    local warZoneServerIdMin, warZoneServerIdMax = getWarZoneServerArea(msg.sourceServerId)

    if not warZoneServerIdMin or warZoneServerIdMin == 0 then
        return
    end

    if repeateServerIdList[warZoneServerIdMin] then
        return
    end

    -- 更新标识
    repeateServerIdList[warZoneServerIdMin] = true

    local fd_2_PlayerList = {}
    local joinList = battleGroundData.joinList
    if not joinList then
        return
    end

    local serverIdxMin = MiddleConnect.MiddleConnect_ConfServerID2TrueServerID(warZoneServerIdMin)
    local serverIdxMax = MiddleConnect.MiddleConnect_ConfServerID2TrueServerID(warZoneServerIdMax)

    -- 参与玩家(包括在榜玩家)
    for k = #joinList, 1, -1 do
        local playerInfo = joinList[k]
        local serverId = playerInfo[1]
        if serverId >= serverIdxMin and serverId <= serverIdxMax then
            local fd = MiddleManager.getFDBySvrIndex(serverId)
            if fd then
                fd_2_PlayerList[fd] = fd_2_PlayerList[fd] or {}
                fd_2_PlayerList[fd][#fd_2_PlayerList[fd]+1] = {ServerCommerceActDefine.COMMERCEACT_NPC_CNT, playerInfo[2]}
            end
            table.remove(joinList, k)
        end
    end

    -- 在榜玩家
    local myWarZoneRankList = getMyWarZoneRankList(msg.sourceServerId)
    for _, player in pairs(myWarZoneRankList or {}) do
        local fd = MiddleManager.getFDBySvrIndex(player.serverId)
        if fd then
            fd_2_PlayerList[fd] = fd_2_PlayerList[fd] or {}
            local idx = findVal(fd_2_PlayerList[fd], player.playerUuid)
            if idx then
                fd_2_PlayerList[fd][idx][1] = player.rank
            end
        end
    end

    if battleGroundData.allAreaRankList and battleGroundData.allAreaRankList[warZoneServerIdMin] then
        battleGroundData.allAreaRankList[warZoneServerIdMin] = nil
    end

    if next(fd_2_PlayerList) then
        -- 写日志
        local logTab2 = Util.serialize(fd_2_PlayerList)
        local logStr2 = table.concat(logTab2)
        Timer.addLater(45, writeLog, logStr2)

        local delay_sec = 0
        for fd, rankArr in pairs(fd_2_PlayerList) do
            delay_sec = delay_sec + 3
            Timer.addLater(delay_sec, issueReward, fd, rankArr)
        end

        -- 更新数据
        if not next(battleGroundData.joinList) then
            battleGroundData.joinList = nil
        end
        updateValue("joinList", battleGroundData.joinList)

        if battleGroundData.allAreaRankList and not next(battleGroundData.allAreaRankList) then
            battleGroundData.allAreaRankList = nil
        end
        updateValue("allAreaRankList", battleGroundData.allAreaRankList)
    end
end
