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

-- db
-- human.db.ServerCommerce.battleGround = {
--     heroBag = {}, -- 英雄背包
--     isHaveNewHero = false, -- 是否获得新英雄
--     unLockIdx = 0, -- 英雄解锁层数
--     freeChallengeCnt = 5, -- 免费挑战次数
--     lastResetTime = 1123156, -- 上一次重置免费挑战次数的时间戳
--     lineUp = {          -- 战斗阵容数据
--         formation = 1,
--         heroList = {},
--     },
--     matchList = {rank1, rank2, rank3, rank4, rank5}, -- 对手列表
-- }

local Msg = require("core.Msg")
local Timer = require("core.Timer")
local Config = require("Config")
local Grid = require("bag.Grid")
local BagLogic = require("bag.BagLogic")
local ObjHuman = require("core.ObjHuman")
local MailExcel = require("excel.mail")
local MailManager = require("mail.MailManager")
local Util = require("common.Util")
local Lang = require("common.Lang")
local Broadcast = require("broadcast.Broadcast")
local InnerMsg = require("core.InnerMsg")
local RoleHeadLogic = require("role.RoleHeadLogic")
local ServerCommerceManager = require("serverCommerce.ServerCommerceManager")
local ServerCommerceActDefine = require("serverCommerce.ServerCommerceActDefine")
local battleGroundConfig = require("excel.ServerCommerceBattleGround")
local MonsterExcel = require("excel.monster")
local HeroConfig = require("excel.hero").hero
local HeroDefine = require("hero.HeroDefine")
local CombatDefine = require("combat.CombatDefine")
local CombatLogic = require("combat.CombatLogic")
local CombatPosLogic = require("combat.CombatPosLogic")
local MiddleCommonLogic = require("middle.MiddleCommonLogic")
local RoleDBLogic = require("role.RoleDBLogic")
local Log = require("common.Log")
local lua_mongo = _G.lua_mongo
local RoleDefine = require("role.RoleDefine")


local rankListCache = {}
local lastGetRankListTime = 0
local LOGTYPE = "ServerCommerceActBattleGround"
local SP_JOB_MAX_NUM = 4 -- 牧师+护卫最多可上阵4个


local function initData(human)
    human.db.ServerCommerce.battleGround =
    {
        freeChallengeCnt = ServerCommerceActDefine.COMMERCEACT_DAILY_FREECHALLENGETIMES,
        resetTime = os.time(),
    }
end

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

-- 玩家排名下降, 通过邮件通知
local function rankReduceMail(mailId, receiverUuid, arg)
    if not mailId or not receiverUuid then
        return
    end

    local mailCfg = MailExcel.mail[mailId]
    local content = mailCfg.content
    if arg then
        content = Util.format(content, arg[1], arg[2], arg[3])
    end
    MailManager.add(MailManager.SYSTEM, receiverUuid, mailCfg.title, content, nil, mailCfg.senderName or "GM")
end

-- 排行奖励邮件
local function sendAwardMail(mailId, receiverUuid, rank, itemArray)
    local mailCfg = MailExcel.mail[mailId]
    local content = mailCfg.content
    content = Util.format(content, rank or ServerCommerceActDefine.COMMERCEACT_NPC_CNT)
    MailManager.add(MailManager.SYSTEM, receiverUuid, mailCfg.title, content, itemArray, mailCfg.senderName or "GM")
end

-- 创建一个发奖queue
local function createRewardQueue()
    local issueRewardQueue = {
        playerArray = {},
        insertMaxNum = 100, -- 一次最多插入数据库的邮件数量
        repeatMaxTimes = 3, -- 重试次数
        repeatTb = {},
        extraInfo = {},
    }

    function issueRewardQueue:add(playerInfo)
        table.insert(self.playerArray, playerInfo)
    end

    function issueRewardQueue:insertDB()
        local maxNum = math.min(self.insertMaxNum, #self.playerArray)
        local mailId = battleGroundConfig.var[1].rankAwardMailId
        for i=1, maxNum do
            local resTag = ServerCommerceActDefine.BG_MAIL_SUCC_TAG
            local playerInfo = table.remove(self.playerArray)
            local playerUuid = playerInfo[2]

            local ok, err = pcall(sendAwardMail, mailId, playerUuid, playerInfo[1], playerInfo[3])

            if not ok then
                if not self.repeatTb[playerUuid] or self.repeatTb[playerUuid] < self.repeatMaxTimes then
                    issueRewardQueue:add(playerInfo)
                    self.repeatTb[playerUuid] = (self.repeatTb[playerUuid] or 0) + 1
                end

                resTag = ServerCommerceActDefine.BG_MAIL_FAIL_TAG
            end

            -- 写入日志
            local str = string.format("ServerCommerceActBattleGround PrizeAward result: %s, playerUuid: %s, insertErrTimes: %d, errInfo: %s",
                    resTag, playerUuid, self.repeatTb[playerUuid] or 0, err)

            writeLog(str)
        end

        if #self.playerArray > 0 then
            Timer.addLater(2, self.insertDB, self)
        end
    end

    return issueRewardQueue
end


-- 是否处于活动中
local function isRunning()
    return true == ServerCommerceManager.CommerceAct_IsRun()
end

-- 生成对手算法
local function matchListAlgorithm(rank)
    -- 输入验证
    if not rank or type(rank) ~= "number" or rank < 1 or rank > (ServerCommerceActDefine.COMMERCEACT_NPC_CNT + 1) then
        return {}  -- 返回空列表或根据需求处理错误
    end
    
    local matchList = {}
    local usedRanks = {}
    
    -- 确保玩家自己不会被选为对手
    usedRanks[rank] = true
    
    -- 计算抽取范围
    local minRank = math.max(1, rank - 50)
    local maxRank = math.min(ServerCommerceActDefine.COMMERCEACT_NPC_CNT, rank + 10)
    
    -- 生成所有可能的对手排名
    local possibleRanks = {}
    for i = minRank, maxRank do
        if not usedRanks[i] then
            table.insert(possibleRanks, i)
        end
    end
    
    -- 如果可用对手不足5个，则返回所有可能的对手
    local numToSelect = math.min(5, #possibleRanks)
    
    if numToSelect == 0 then
        return {}
    end
    
    -- 随机抽取指定数量的对手
    for i = 1, numToSelect do
        -- 从剩余可选排名中随机选择一个
        local randomIndex = math.random(#possibleRanks)
        local selectedRank = possibleRanks[randomIndex]
        
        -- 添加到匹配列表
        table.insert(matchList, selectedRank)
        
        -- 从可选列表中移除已选中的排名
        table.remove(possibleRanks, randomIndex)
        
        -- 标记为已使用
        usedRanks[selectedRank] = true
    end

    table.sort( matchList, function (a, b)
        return a > b
    end)

    return matchList
end

-- 生成一个英雄模板数据
local function genHeroGrid(heroId)
    local obj = {}
    obj[1] = heroId
    obj[2] = lua_mongo.id()
    return obj
end

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

-- 填充协议英雄数据
local function populateHeroMsg(net, heroInfo, heroConfig, heroLv, heroStar, heroBagIdx)
    net.heroHeadId = heroConfig.head
    net.heroName = heroConfig.name
    net.heroCamp = heroConfig.camp
    net.heroLv = heroLv
    net.heroStar = heroStar
    net.heroGrade = heroConfig.grade or 0
    net.heroBodyId = heroConfig.body
    net.heroId = heroInfo[1] or 0
    net.heroUuid = heroInfo[2] or ""
    net.heroBagIdx = heroBagIdx or 0
    net.heroJob = heroConfig.job or 1
end

-- 获取可以解锁的英雄信息
local function getUnlockHeroInfoByRank(rank)
    local unLockHero = battleGroundConfig.unLockHero
    for idx, cfg in ipairs(unLockHero) do
        if rank >= cfg.unLockRankArea[1] and rank <= cfg.unLockRankArea[2] then
            return idx, cfg.unLockHeroInfo
        end
    end
end

-- 解锁英雄
local function unlockHero(human, unlockHeroInfo, isInit)
    human.db.ServerCommerce.battleGround = human.db.ServerCommerce.battleGround or {}
    local battleGroundData = human.db.ServerCommerce.battleGround
    battleGroundData.heroBag = battleGroundData.heroBag or {}
    local heroBagData = battleGroundData.heroBag

    if #unlockHeroInfo == 0 then
        for heroId, heroCfg in pairs(HeroConfig) do
            if heroCfg.grade >= HeroDefine.HERO_SSR_GRADE and heroId > 100000 and not findVal(heroBagData, heroId) then
                heroBagData[#heroBagData+1] = genHeroGrid(heroId)
            end
        end

        battleGroundData.isHaveNewHero = true
        return
    end

    -- local heroList = {}
    local heroArr = {}
    for heroId, heroCfg in pairs(HeroConfig) do
        if heroCfg.grade >= HeroDefine.HERO_SSR_GRADE and heroId > 100000 and not findVal(heroBagData, heroId) then
            -- heroList[heroId] = heroCfg
            heroArr[#heroArr+1] = {heroId, heroCfg}
        end
    end

    table.shuffle(heroArr)

    for _, heroCond in ipairs(unlockHeroInfo) do
        local campCond = heroCond[1] or 0
        local numCond = heroCond[2] or 0
        for i=1, numCond do
            for _, heroData in ipairs(heroArr) do
                local heroId =  heroData[1]
                local heroCfg = heroData[2]
                if heroCfg.camp == campCond and not findVal(heroBagData, heroId) then
                    heroBagData[#heroBagData+1] = genHeroGrid(heroId)
                    break
                end
            end
        end
    end

    battleGroundData.isHaveNewHero = true
    if isInit then
        battleGroundData.isHaveNewHero = false
    end
end

-- 获取上阵英雄
local function getLineupHeroArr(human)
    local heroArr
    local heroList = CombatPosLogic.getCombatHeros(human, CombatDefine.COMBAT_TYPE37)
    for _, heroUuid in ipairs(heroList) do
        if heroUuid and heroUuid ~= "" and heroUuid ~= "0" then
            local heroGrid = getHeroGridByUuid(human, heroUuid)
            if heroGrid then
                heroArr = heroArr or {}
                heroArr[#heroArr+1] = heroGrid.id
            end
        end
    end
    return heroArr
end

-- 生成玩家的展示数据
local function populatePlayerShowData(human, showData, rank)
    showData.rank = rank
    showData.serverId = Config.SVR_INDEX
    showData.playerUuid = human.db._id
    showData.name = human.db.name
    showData.bodyId = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_3) or 0
    showData.headId = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_1) or 0
    showData.headFrameId = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_2) or 0
    showData.heroArr = {}

    showData.heroArr = getLineupHeroArr(human)
end

-- 排名没变化, 只刷新匹配列表
local function rankNoChange(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        local db = RoleDBLogic.getDb(msg.playerUuid)
        if not db then
            return
        end

        human = {}
        human.db = db
    end

    local newMatchList = matchListAlgorithm(msg.newRank)
    local battleGroundData = human.db.ServerCommerce.battleGround
    battleGroundData.matchList = newMatchList

    -- 玩家在线
    if human.fd then
        -- BattleGround_MatchPage_Query(human)
        return
    end

    -- 玩家不在线，则保存数据
    ObjHuman.save(human)
end

-- 排名提高
local function rankImprove(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        local db = RoleDBLogic.getDb(msg.playerUuid)
        if not db then
            return
        end

        human = {}
        human.db = db
    end

    human.battleGroundRank = msg.newRank
    -- local newMatchList = matchListAlgorithm(human.battleGroundRank)

    -- 更新对手列表
    local battleGroundData = human.db.ServerCommerce.battleGround
    -- battleGroundData.matchList = newMatchList

    rankNoChange(msg)

    -- 检查是否能解锁新英雄
    local idx, unlockHeroInfo = getUnlockHeroInfoByRank(human.battleGroundRank)
    if idx ~= battleGroundData.unLockIdx then
        unlockHero(human, unlockHeroInfo)
        battleGroundData.unLockIdx = idx
        battleGroundData.isHaveNewHero = true
    end

    -- 玩家在线
    if human.fd then
        -- BattleGround_MatchPage_Query(human)
        return
    end

    -- 玩家不在线，则保存数据
    ObjHuman.save(human)
end

-- 排名降低
local function rankReduce(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        local db = RoleDBLogic.getDb(msg.playerUuid)
        if not db then
            return
        end

        human = {}
        human.db = db
    end

    -- 更新对手列表
    local battleGroundData = human.db.ServerCommerce.battleGround
    battleGroundData.matchList = matchListAlgorithm(msg.newRank)

    -- 邮件通知
    local varCfg = battleGroundConfig.var[1]
    local arg = {msg.atkeServerId - ServerCommerceActDefine.BG_SERVERID_START, msg.atkName, msg.newRank}
    rankReduceMail(varCfg.defeatMailId, human.db._id, arg)

    -- 玩家在线
    if human.fd then
        human.battleGroundRank = msg.newRank
        return
    end

    -- 玩家不在线，则保存数据
    ObjHuman.save(human)
end

-- 战斗结束处理
local function fightEndHanle(human, result)
    local msgData = InnerMsg.lw.LW_BATTLEGROUND_CHALLENGE_END
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.atkRank = human.battleGroundRank
    msgData.defRank = human.battleGroundCache.defRank
    msgData.challengeRes = result
    msgData.playerShowData = {}

    local varCfg = battleGroundConfig.var[1]
    local challengeAward = varCfg.defeatAward

    if result == CombatDefine.RESULT_WIN then
        -- 更新对手列表
        -- local newMatchList = matchListAlgorithm(human.battleGroundRank)
        -- local battleGroundData = human.db.ServerCommerce.battleGround
        -- battleGroundData.matchList = newMatchList

        -- 展示数据
        --if human.battleGroundRank <= ServerCommerceActDefine.COMMERCEACT_NPC_CNT then
            populatePlayerShowData(human, msgData.playerShowData, human.battleGroundCache.defRank)
        --end

        -- 挑战奖励
        challengeAward = varCfg.winAward
    end

    -- 发放挑战奖励
    local finalAwardArr = {}
    for i, itemInfo in ipairs(challengeAward) do
        finalAwardArr[i] = {itemInfo[1], itemInfo[2]}
    end
    BagLogic.addItemList(human, finalAwardArr, LOGTYPE)

    -- 通知跨服更新数据
    InnerMsg.sendMsg(0, msgData)
end

-- 获取排名奖励
local function getRankAward(rank)
    local itemArr
    for i, cfg in ipairs(battleGroundConfig.rankAward) do
        if rank >= cfg.rankArea[1] and rank <= cfg.rankArea[2] then
            itemArr = {}
            for k, itemInfo in ipairs(cfg.rankAward) do
                itemArr[k] = {itemInfo[1], itemInfo[2]}
            end

            break
        end
    end

    return itemArr
end


function updateDaily(human)
    if not isRunning() then
        return
    end

    if human.db.ServerCommerce and not human.db.ServerCommerce.battleGround then
        initData(human)
    end

    local battleGroundData = human.db.ServerCommerce and human.db.ServerCommerce.battleGround
    if not battleGroundData then
        return
    end

    local lastResetTime = battleGroundData.lastResetTime
    if not Util.isSameDay(lastResetTime) then
        battleGroundData.freeChallengeCnt = ServerCommerceActDefine.COMMERCEACT_DAILY_FREECHALLENGETIMES
        battleGroundData.lastResetTime = os.time()
    end
end

-- 根据英雄uuid获取英雄信息
function getHeroGridByUuid(human, heroUuid)
    if not isRunning() then
        return
    end

    if not human.db.ServerCommerce then
        return
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    if not battleGroundData or not battleGroundData.heroBag then
        return
    end

    local heroGrid
    local heroBagData = battleGroundData.heroBag

    for bagIdx, heroInfo in ipairs(heroBagData) do
        if heroInfo[2] == heroUuid then
            heroGrid = {
                id = heroInfo[1],
                bagIndex = bagIdx,
                uuid = heroInfo[2],
                zhandouli = 0
            }
            break
        end
    end

    return heroGrid
end

-- 根据英雄id获取英雄信息
function getHeroGridByheroId(human, heroId)
    if not isRunning() then
        return
    end

    if not human.db.ServerCommerce then
        return
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    if not battleGroundData or not battleGroundData.heroBag then
        return
    end

    local heroGrid
    local heroBagData = battleGroundData.heroBag
    for bagIdx, heroInfo in ipairs(heroBagData) do
        if heroInfo[1] == heroId then
            heroGrid = {
                id = heroInfo[1],
                bagIndex = bagIdx,
                uuid = heroInfo[2]
            }
            break
        end
    end

    return heroGrid
end

-- 是否获得英雄
function isGetHero(human, heroId)
    return getHeroGridByheroId(human, heroId)
end

-- 阵容有更新
function onUpdatePos(human)
    BattleGround_Lineup_Update(human)
end

-- 是否有红点
function isRed(human)
    -- 兼容老数据
    if human.db.ServerCommerce and not human.db.ServerCommerce.battleGround then
        initData(human)
    end

    if not human.db.ServerCommerce or not human.db.ServerCommerce.battleGround then
        return false
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    if not battleGroundData.freeChallengeCnt or battleGroundData.freeChallengeCnt <= 0 then
        return false
    end

    return true
end

-- 更换阵容检查
function checkUpdatePos(human, msg)
    local num = 0
    local heroList = Util.split(msg.heroList, ",")
    for i = 1, CombatDefine.COMBAT_HERO_CNT do
        local uuid = heroList[i] or ""
        if uuid ~= "0" and uuid ~= "" then
            local heroGrid = getHeroGridByUuid(human, uuid)
            if heroGrid then
                local heroId = heroGrid.id
                local heroCfg = HeroConfig[heroId]
                if heroCfg and (heroCfg.job == 1 or heroCfg.job == 4) then
                    num = num + 1
                end
            end
        end
    end

    if num > SP_JOB_MAX_NUM then
        return Broadcast.sendErr(human, Util.format(Lang.BG_SP_JOB_MAXNUM_ERR, SP_JOB_MAX_NUM))
    end

    return true
end





-- 推送主界面信息
local function sendMainPageData(human)
    local msgRet = Msg.gc.GC_SERVEERCOMMERCE_ACT_BATTLEGROUND_MAINPAGE_QUERY
    msgRet.myRank = human.battleGroundRank or (ServerCommerceActDefine.COMMERCEACT_NPC_CNT + 1)
    msgRet.freeChallengeCnt = 0
    msgRet.showBodyId = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_3) or 0

    local battleGroundData = human.db.ServerCommerce and human.db.ServerCommerce.battleGround
    msgRet.freeChallengeCnt = battleGroundData and battleGroundData.freeChallengeCnt or ServerCommerceActDefine.COMMERCEACT_DAILY_FREECHALLENGETIMES
    Msg.send(msgRet, human.fd)
end

-- 推送排行榜数据
local function sendRankListData(human)
    local msgRet = Msg.gc.GC_SERVEERCOMMERCE_ACT_BATTLEGROUND_RANK_QUERY
    msgRet.rankList[0] = 0
    msgRet.isEnd = 0
    msgRet.myRankInfo.rank = ServerCommerceActDefine.COMMERCEACT_NPC_CNT
    msgRet.myRankInfo.serverId = Config.SVR_INDEX - ServerCommerceActDefine.BG_SERVERID_START
    msgRet.myRankInfo.name = human.db.name
    msgRet.myRankInfo.heroHeadId = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_1) or 0
    msgRet.myRankInfo.heroHeadFrameId = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_2) or 0

    local msgMaxLen = 20
    local len = 0
    local rankNum = #rankListCache

    for rank, rankInfo in ipairs(rankListCache) do
        len = len + 1
        msgRet.rankList[0] = len
        msgRet.rankList[len].rank = rank
        msgRet.rankList[len].serverId = rankInfo.serverId and (rankInfo.serverId - ServerCommerceActDefine.BG_SERVERID_START)  or 1
        msgRet.rankList[len].name = rankInfo.name
        msgRet.rankList[len].heroHeadId = rankInfo.heroHeadId
        msgRet.rankList[len].heroHeadFrameId = rankInfo.heroHeadFrameId

        if rankInfo.playerUuid == human.db._id then
            msgRet.myRankInfo.rank = rank
        end

        if len >= msgMaxLen then
            rankNum = rankNum - len

            if rankNum <= 0 then
                msgRet.isEnd = 1
                return Msg.send(msgRet, human.fd)
            end

            Msg.send(msgRet, human.fd)
            len = 0
        end
    end

    if len > 0 then
        msgRet.isEnd = 1
        Msg.send(msgRet, human.fd)
    end
end

-- 主界面信息查询
function BattleGround_MainPage_Query(human)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    if human.db.ServerCommerce and not human.db.ServerCommerce.battleGround then
        initData(human)
    end

    if not human.battleGroundRank then
        local msgData = InnerMsg.lw.LW_BATTLEGROUND_PLAYER_RANK_QUERY
        msgData.sourceServerId = Config.SVR_INDEX
        msgData.playerUuid = human.db._id
        return InnerMsg.sendMsg(0, msgData)
    end

    sendMainPageData(human)
end

-- 匹配界面信息查询
function BattleGround_MatchPage_Query(human)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    if not battleGroundData.matchList or not next(battleGroundData.matchList) then
        battleGroundData.matchList = matchListAlgorithm(human.battleGroundRank)
    end

    local msgData = InnerMsg.lw.LW_BATTLEGROUND_MATCHLIST_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.matchList = {}

    for _, rank in ipairs(battleGroundData.matchList) do
        msgData.matchList[#msgData.matchList+1] = rank
    end

    InnerMsg.sendMsg(0, msgData)
end

-- 刷新匹配对手
function BattleGround_Update_MatchList(human)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    if not human.battleGroundRank then
        return
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    battleGroundData.matchList = matchListAlgorithm(human.battleGroundRank)

    BattleGround_MatchPage_Query(human)
end

-- 匹配对手查询
function BattleGround_Player_Query(human, targetRank)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    if not table.find(battleGroundData.matchList, targetRank) then
        return Broadcast.sendErr(human, Lang.BG_MATCHLIST_ERR)
    end

    local msgData = InnerMsg.lw.LW_BATTLEGROUND_PLAYER_DATA_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.playerRank = targetRank

    InnerMsg.sendMsg(0, msgData)
end

-- 请求挑战某个排名玩家
function BattleGround_Try_Challenge(human, targetRank)
    local msgData = InnerMsg.lw.LW_BATTLEGROUND_CHALLENGE_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.rank = targetRank
    InnerMsg.sendMsg(0, msgData)
end

-- 一键扫荡
function BattleGround_OneClickSweep(human)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    if battleGroundData.freeChallengeCnt <= 0 then
        return Broadcast.sendErr(human, Lang.BG_FREECNT_NOT_ENOUGH)
    end

    local winAwardCfg = battleGroundConfig.var[1].winAward
    local winAwardArr = {}

    for i, itemInfo in ipairs(winAwardCfg) do
        winAwardArr[i] = { itemInfo[1], itemInfo[2] * battleGroundData.freeChallengeCnt }
    end

    battleGroundData.freeChallengeCnt = 0
    BattleGround_MatchPage_Query(human)

    BagLogic.addItemList(human, winAwardArr, LOGTYPE)

    ServerCommerceManager.CommerceAct_SendActInfo(human)
end

-- 英雄背包查询
function BattleGround_HeroBag_Query(human)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    if not battleGroundData.heroBag then
        local idx, unlockHeroInfo = getUnlockHeroInfoByRank(human.battleGroundRank)
        if unlockHeroInfo then
            unlockHero(human, unlockHeroInfo, true)
            battleGroundData.unLockIdx = idx
        end
    end

    -- battleGroundData.isHaveNewHero = false

    local msgRet = Msg.gc.GC_SERVEERCOMMERCE_ACT_BATTLEGROUND_HEROBAG_QUERY
    msgRet.heroArr[0] = 0
    msgRet.isEnd = 0


    local len, msgMaxLen = 0, 0
    local heroNum = #battleGroundData.heroBag
    for heroBagIdx, heroInfo in ipairs(battleGroundData.heroBag) do
        len = len + 1
        msgRet.heroArr[0] = len
        local heroConfig = HeroConfig[heroInfo[1]]
        populateHeroMsg(msgRet.heroArr[len], heroInfo, heroConfig, ServerCommerceActDefine.COMMERCEACT_HERO_LV, ServerCommerceActDefine.COMMERCEACT_HERO_STAR, heroBagIdx)

        if len >= msgMaxLen then
            heroNum = heroNum - len
            if heroNum <= 0 then
                msgRet.isEnd = 1
                return Msg.send(msgRet, human.fd)
            end

            Msg.send(msgRet, human.fd)
            len = 0
        end
    end

    if len > 0 then
        msgRet.isEnd = 1
        Msg.send(msgRet, human.fd)
    end

end

-- 已经知道获得新英雄了
function BattleGround_AlreadyKonw_GetNewHero(human)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    local battleGroundData = human.db.ServerCommerce.battleGround
    battleGroundData.isHaveNewHero = false
end


-- 排行榜查询
function BattleGround_RankList_Query(human)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    local now = os.time()
    if #rankListCache == 0 or now - lastGetRankListTime >= ServerCommerceActDefine.BG_COMMERCEACT_RANKUPDATE then
        local msgData = InnerMsg.lw.LW_BATTLEGROUND_RANKLIST_QUERY
        msgData.sourceServerId = Config.SVR_INDEX
        msgData.playerUuid = human.db._id
        return InnerMsg.sendMsg(0, msgData)
    end

    sendRankListData(human)
end

-- 排行奖励查询
function BattleGround_RankAward_Query(human)
    if not isRunning() then
        return Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    local msgRet = Msg.gc.GC_SERVEERCOMMERCE_ACT_BATTLEGROUND_RANKAWARD_QUERY
    msgRet.rankAwardList[0] = 0

    msgRet.rankAwardList[0] = #battleGroundConfig.rankAward
    for i, cfg in ipairs(battleGroundConfig.rankAward) do
        msgRet.rankAwardList[i].minRank = cfg.rankArea[1]
        msgRet.rankAwardList[i].maxRank = cfg.rankArea[2]
        msgRet.rankAwardList[i].rankAward[0] = #cfg.rankAward

        for k, itemInfo in ipairs(cfg.rankAward) do
            Grid.makeItem(msgRet.rankAwardList[i].rankAward[k], itemInfo[1], itemInfo[2])
        end
    end

    Msg.send(msgRet, human.fd)
end

-- 更新阵容数据
function BattleGround_Lineup_Update(human, msg)
    if not isRunning() then
        return
    end

    -- local battleGroundData = human.db.ServerCommerce.battleGround

    -- local formation = msg.formation
    -- local posList = CombatPosLogic.getPosList(formation)
    -- local heroList = Util.split(msg.heroList, ",", true)

    -- local reapetTb = {}
    -- for i = 1, CombatDefine.COMBAT_HERO_CNT do
    --     local heroId = heroList[i]
    --     if heroId > 0 then
    --         -- 英雄Id检测
    --         if HeroConfig[heroId] then
    --             return Broadcast.sendErr(human, Lang.FUWEN_HERO_GRID_ERR)
    --         end

    --         -- 英雄背包检测
    --         if not battleGroundData.heroBag or not table.find(battleGroundData.heroBag, heroId) then
    --             return Broadcast.sendErr(human, Lang.FUWEN_HERO_GRID_ERR)
    --         end

    --         -- 相同英雄检测
    --         if reapetTb[heroId] then
    --             return Broadcast.sendErr(human, Lang.HERO_SAME)
    --         end

    --         -- 位置检测
    --         if posList[i] == nil and i ~= CombatDefine.COMBAT_HERO_CNT then
    --             return Broadcast.sendErr(human, Lang.POS_ERROR)
    --         end

    --         reapetTb[heroId] = true
    --     end
    -- end

    -- battleGroundData.lineUp = battleGroundData.lineUp or {}
    -- battleGroundData.lineUp.formation = formation
    -- battleGroundData.lineUp.heroList = heroList

    -- 通知跨服更新
    if human.battleGroundRank and human.battleGroundRank <= ServerCommerceActDefine.COMMERCEACT_NPC_CNT then
        local msgData = InnerMsg.lw.LW_BATTLEGROUND_LINEUP_UPDATE
        msgData.sourceServerId = Config.SVR_INDEX
        msgData.playerUuid = human.db._id
        msgData.heroArr = getLineupHeroArr(human)
        InnerMsg.sendMsg(0, msgData)
    end
end

-- 活动结束
function Act_End()
    local msgData = InnerMsg.lw.LW_BATTLEGROUND_ACT_END
    msgData.sourceServerId = Config.SVR_INDEX
    InnerMsg.sendMsg(0, msgData)
end

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

-- 跨服返回玩家排名数据
function BG_C2N_PlayerRank_Res(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    human.battleGroundRank = msg.playerRank
    sendMainPageData(human)
end

-- 跨服返回对手列表数据
function BG_C2N_MatchList_Res(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local msgRet = Msg.gc.GC_SERVEERCOMMERCE_ACT_BATTLEGROUND_MATCHLIST_QUERY
    msgRet.myRank = human.battleGroundRank or (ServerCommerceActDefine.COMMERCEACT_NPC_CNT + 1)
    msgRet.freeChallengeCnt = 0
    msgRet.isGetNew = 0
    msgRet.matchList[0] = 0

    local battleGroundData = human.db.ServerCommerce and human.db.ServerCommerce.battleGround

    local costItem = battleGroundConfig.var[1].cost
    Grid.makeItem(msgRet.exchangeCost, costItem[1], costItem[2])

    msgRet.freeChallengeCnt = battleGroundData and battleGroundData.freeChallengeCnt or ServerCommerceActDefine.COMMERCEACT_DAILY_FREECHALLENGETIMES
    msgRet.isGetNew = battleGroundData and battleGroundData.isHaveNewHero and 1 or 0

    msgRet.matchList[0] = #msg.playerInfoList
    for i, rankInfo in ipairs(msg.playerInfoList) do
        msgRet.matchList[i].rank = rankInfo.rank
        msgRet.matchList[i].serverId = rankInfo.serverId and (rankInfo.serverId - ServerCommerceActDefine.BG_SERVERID_START) or 1
        msgRet.matchList[i].name = rankInfo.name
        msgRet.matchList[i].showBodyId = rankInfo.showBodyId
    end

    Msg.send(msgRet, human.fd)
end

-- 跨服返回单个对手数据
function BG_C2N_PlayerData_Res(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local playerInfo = msg.playerInfo
    local msgRet = Msg.gc.GC_SERVEERCOMMERCE_ACT_BATTLEGROUND_PLAYER_QUERY
    msgRet.serverId = playerInfo.serverId and (playerInfo.serverId - ServerCommerceActDefine.BG_SERVERID_START) or 1
    msgRet.name = playerInfo.name
    msgRet.heroHeadId = playerInfo.heroHeadId
    msgRet.heroHeadFrameId = playerInfo.heroHeadFrameId
    msgRet.heroArr[0] = 0
    msgRet.isQuick = human.db.combatQuick and human.db.combatQuick[CombatDefine.COMBAT_TYPE37] or 0

    local heroInfo = {0}
    if playerInfo.monsteroutId == 0 then -- 真实玩家
        msgRet.heroArr[0] = #playerInfo.heroArr
        for i, heroId in ipairs(playerInfo.heroArr) do
            local heroConfig = HeroConfig[heroId]
            heroInfo[1] = heroId
            populateHeroMsg(msgRet.heroArr[i], heroInfo, heroConfig, ServerCommerceActDefine.COMMERCEACT_HERO_LV, ServerCommerceActDefine.COMMERCEACT_HERO_STAR)
        end
    else
        local monsterOutConfig = MonsterExcel.monsterOut[playerInfo.monsteroutId]
        msgRet.heroArr[0] = #monsterOutConfig.member
        for i, monsterInfo in ipairs(monsterOutConfig.member) do
            local monsterID = monsterInfo[1]
            local mcf = MonsterExcel.monster[monsterID]
            heroInfo[1] = monsterID
            populateHeroMsg(msgRet.heroArr[i], heroInfo, mcf, monsterInfo[2], mcf.star)
        end
    end

    Msg.send(msgRet, human.fd)
end

-- 跨服返回排行榜数据
function BG_C2N_RankList_Res(msg)
    rankListCache = msg.rankList
    lastGetRankListTime = os.time()

    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    sendRankListData(human)
end

-- 跨服返回请求战斗结果
function BG_C2N_Challenge_Res(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    if msg.errCode ~= 0 then
        return Broadcast.sendErr(human, Lang.BG_MATCHLIST_ERR)
    end

    local playerUuid = msg.playerInfo.playerUuid
    local defServerId = msg.playerInfo.defServerId

    human.battleGroundCache = {
        defRank = msg.playerInfo.rank
    }

    if defServerId ~= 0 then -- 真实玩家
        local args = {
            combatType = CombatDefine.COMBAT_TYPE37,
            nServerIndex = defServerId,
            param = playerUuid
        }
        MiddleCommonLogic.MiddleCommonLogic_CombatBegin_LW(human, args)
    else
        CombatLogic.combatBegin(human, nil, {playerUuid}, CombatDefine.COMBAT_TYPE37)
    end
end

-- 跨服通知玩家排名更新
function BG_C2N_RankUpdate(msg)
    if msg.updateType == 1 then -- 排名提高
        rankImprove(msg)
    elseif msg.updateType == 0 then -- 排名没变化
        rankNoChange(msg)
    else
        rankReduce(msg)
    end
end

-- 跨服通知发奖
function BG_C2N_PrizeAward(msg)
    local playerArr = msg.playerArr
    if not next(playerArr) then
        return
    end

    local issueRewardQueue = createRewardQueue()

    for _, playerInfo in ipairs(playerArr) do
        local itemArr = getRankAward(playerInfo[1])
        if itemArr then
            playerInfo[3] = itemArr
            issueRewardQueue:add(playerInfo)
        end
    end

    issueRewardQueue:insertDB()
end



----------------------------------战斗-----------------------------------

function fight(human, args, combatType)
    if combatType ~= CombatDefine.COMBAT_TYPE37 then
        return Broadcast.sendErr(human, Lang.BG_COMBAT_TYPE_ERR)
    end

    local targetRank = tonumber(args[1])
    local battleGroundData = human.db.ServerCommerce.battleGround
    if not targetRank or not table.find(battleGroundData.matchList, targetRank) then
        return Broadcast.sendErr(human, Lang.BG_MATCHLIST_ERR)
    end

    -- if not battleGroundData.lineUp then
    --     return Broadcast.sendErr(human, Lang.SEAL_GROUND_COMBAT_HERO_ERR)
    -- end

    local heroList = CombatPosLogic.getCombatHeros(human, combatType)
    if not next(heroList) then
        return Broadcast.sendErr(human, Lang.SEAL_GROUND_COMBAT_HERO_ERR)
    end

    if battleGroundData.freeChallengeCnt <= 0 then
        local costItem = battleGroundConfig.var[1].cost
        local itemId, itemNum = costItem[1], costItem[2]
        if BagLogic.getItemCnt(human, itemId) < itemNum then
            return Broadcast.sendErr(human, Lang.BG_CONDITION_ERR)
        end

        BagLogic.delItem(human, itemId, itemNum, LOGTYPE)
    else
        battleGroundData.freeChallengeCnt = battleGroundData.freeChallengeCnt - 1
        if battleGroundData.freeChallengeCnt <= 0 then
            ServerCommerceManager.CommerceAct_SendActInfo(human)
        end
    end

    BattleGround_Try_Challenge(human, targetRank)
end

function getCombatMonsterOutID(human, side, args)
    if side ~= CombatDefine.DEFEND_SIDE then return end
    return args[1]
end

function getCombatObjList(human, side, args, combatType)
    if side == CombatDefine.ATTACK_SIDE and not human then return end

    if side == CombatDefine.DEFEND_SIDE and human then
        return
    end

    if not human then
        local uuid = args[1]
        local db = RoleDBLogic.getDb(uuid)
        if not db then
            return
        end
        human = {}
        human.db = db
    end

    -- local battleGroundData = human.db.ServerCommerce.battleGround
    -- local lineUpData = battleGroundData.lineUp
    -- if not lineUpData.heroList or not lineUpData.formation then
    --     return
    -- end

    local heroList, _, formation = CombatPosLogic.getCombatHeros(human, combatType)
    if not next(heroList) then
        return Broadcast.sendErr(human, Lang.SEAL_GROUND_COMBAT_HERO_ERR)
    end

    local heroLv = ServerCommerceActDefine.COMMERCEACT_HERO_LV
    local heroStar = ServerCommerceActDefine.COMMERCEACT_HERO_STAR

    local attrsChange = {
        [RoleDefine.ATK] = 2,
        [RoleDefine.HP] = 1.5,
        [RoleDefine.BAOJI] = 1.7,
        [RoleDefine.HURT_RATE] = 2,
        [RoleDefine.POJIA] = 1.2,
    }

    local fakeHuman = { db = {} }
    local objList = {}
    for i = 1, CombatDefine.COMBAT_HERO_CNT do
        local heroUuid = heroList[i]
        if heroUuid and heroUuid ~= "" and heroUuid ~= "0" then
            local heroInfo = getHeroGridByUuid(human, heroUuid)
            if not heroInfo then
                return Broadcast.sendErr(human, Lang.SEAL_GROUND_COMBAT_HERO_ERR)
            end
            objList[i] = CombatLogic.createHeroObj(fakeHuman, heroInfo.id, heroLv, heroStar, i, nil,  attrsChange)
        end
    end

    local rolebase = CombatLogic.createRoleBaseByDB(human.db)
    return objList, nil, rolebase, formation
end

function onFightEnd(human, result, type, cbParam, combatInfo)
    local battleGroundCache = human.battleGroundCache
    if not battleGroundCache then
        return Broadcast.sendErr(human, Lang.DATA_ERR)
    end

    fightEndHanle(human, result)
end