-- 诸神圣域(跨服)
-- A 先挑战B, C跟着挑战B, 挑战都胜利, C先于A把结果发到跨服上。处理方式: C先与B交换排名, A再与C交换排名

local InnerMsg = require("core.InnerMsg")
local CombatVideo = require("combat.CombatVideo")
local GodsAreaDB = require("godsArea.GodsAreaDB")
local MiddleManager = require("middle.MiddleManager")
local GodsAreaConfig = require("excel.godsArea")
local Log = require("common.Log")
local Timer = require("core.Timer")

local Util = require("common.Util")

-- 请求战斗到结束时间: 5s
local MAX_CHALLENGE_TIME = 5

-- 每天发奖时间, 晚上23:00
local SEND_REWARD_HOUR = 23

-- 正在被挑战的排名列表
local challengeList = {}



local function getSameIdx(heroList, targetUid)
    for k,  v in pairs(heroList) do
        if v.heroUuid == targetUid then
            return k
        end
    end
end

-- 通过uid查找排名
local function getRankInfoByUid(rankList, uid)
    local finalRank = 0
    for rank, rankData in ipairs(rankList) do
        if rankData.uid and rankData.uid == uid then
            return rank, rankData
        end
    end
    return finalRank
end

-- 获取某个服的在榜人数
local function getRankListBySrvId(rankList, targetSrvId)
    local rankTb = {}
    for rank, rankData in ipairs(rankList) do
        if rankData.serverId and rankData.serverId == targetSrvId then
            rankTb[rankData.uid] = rank
        end
    end

    return rankTb
end

-- 清理超时的挑战数据
local function clearChallengeList()
    if not next(challengeList) then
        return
    end

    local now = os.time()
    for k ,v in pairs(challengeList) do
        if v.startTime + MAX_CHALLENGE_TIME < now then
            challengeList[k] = nil
        end
    end
end


local function writeLog(logId ,logStr)
    -- Log.write(Log.LOGID_OSS_GODSAREA_CHALLENGE, logStr)
    Log.write(logId, logStr)
end

local function getAllSrvFd()
    local fdList = MiddleManager.MiddleManager_GetAllFD()

    local fdArray = {}
    local len = 0
    for srvId, fd in pairs(fdList) do
        len = len + 1
        fdArray[len] = {srvId, fd}
    end

    if len == 0 then
        return
    end

    return fdArray
end

--通知玩家
local function notifyPlayer(playerUid, serverId)
    local fd = MiddleManager.getFDBySvrIndex(serverId)
    local msgData = InnerMsg.wl.WL_GODSATREA_UPDATE_PLAYER_INFO
    msgData.playerUid = playerUid
    InnerMsg.sendMsg(fd, msgData)
end

-- 通知玩家更新数据。新需求，兼容老数据。
local function playerInfoCheck(rankList)
    for _, playerInfo in ipairs(rankList) do
        if playerInfo.uid and not playerInfo.power then
            notifyPlayer(playerInfo.uid, playerInfo.serverId)
        end
    end
end



-- 通知游戏服
function BrocastServer(srvTb, rankList)
    for _, srvInfo in ipairs(srvTb) do
        local rankTb = getRankListBySrvId(rankList, srvInfo[1])
        CS_Send_Reward(srvInfo[2], rankTb)

        local logStr = string.format("跨服开始通知普通服, 普通服Id: %d", srvInfo[1])
        writeLog(Log.LOGID_OSS_GODSAREA_MAIL ,logStr)
    end
end


-- 把连接到本跨服的普通服进行分批
function BatchServer()
    local cnt = 0
    local maxNum = 10
    local delay_sec = 0
    local srvTb = {}
    local fdArray = getAllSrvFd()


    if not fdArray then
        local logStr = "跨服获取不到普通服的fd, 通知普通服失败"
        writeLog(Log.LOGID_OSS_GODSAREA_MAIL ,logStr)
        return
    end

    local rankList = GodsAreaDB.GetRankList()

    for _, v in ipairs(fdArray) do
        cnt = cnt + 1
        srvTb[cnt] = v

        if cnt >= maxNum then
            delay_sec = delay_sec + 5
            Timer.addLater(delay_sec, BrocastServer, srvTb, rankList)

            -- Timer.addLater(2, BrocastServer, srvTb, rankList)
            cnt = 0
            srvTb = {}
        end
    end

    if cnt > 0 then
        Timer.addLater(2, BrocastServer, srvTb, rankList)
    end
end


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

    if hour == SEND_REWARD_HOUR then
        local delay_sec = math.random(1, 30)
        Timer.addLater(delay_sec, BatchServer)

        local logStr = string.format("[跨服]开始发奖, 当前时间: %s, 延迟: %d 秒通知", os.time(), delay_sec)
        writeLog(Log.LOGID_OSS_GODSAREA_MAIL ,logStr)
    end
end

-- 测试
function oneMin()
    -- local delay_sec = math.random(3, 5)
    -- Timer.addLater(delay_sec, BatchServer)

    -- local logStr = string.format("[跨服]开始发奖, 当前时间: %s, 延迟: %d 秒通知", os.time(), delay_sec)
    -- writeLog(Log.LOGID_OSS_GODSAREA_MAIL ,logStr)
end




-- 普通服请求排行榜数据
function CS_RankList_Query(sourceServerId, playerUid)
    local rankList = GodsAreaDB.GetRankList()

    local msgData = InnerMsg.wl.WL_GODSATREA_QUERY_RANKLIST
    msgData.myRank = 0
    msgData.playerUid = playerUid
    msgData.rankList = {}
    local msgRankList = msgData.rankList

    for rank, playerInfo in ipairs(rankList) do
        msgRankList[rank] = {
            body = playerInfo.body or 0,
            name = playerInfo.name or "",
            uid = playerInfo.uid,
            power = playerInfo.power,
            serverId = playerInfo.serverId,
            head = playerInfo.head,
            headFrame = playerInfo.headFrame,
        }

        if playerInfo.uid and playerInfo.uid == playerUid then
            msgData.myRank = rank
        end
    end


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

    playerInfoCheck(rankList)
end

-- 普通服请求某个排名的玩家数据
function CS_GetPlayerInfo(sourceServerId, targetRank, targetUid, playerUid)
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    local msgData = InnerMsg.wl.WL_GODSATREA_QUERY_PLAYER_INFO
    msgData.res = -1
    msgData.playerInfo = {}
    msgData.playerUid = playerUid

    local rankList = GodsAreaDB.GetRankList()
    local rankData = rankList[targetRank]

    -- 数据异常
    if not rankData then
        return InnerMsg.sendMsg(fd, msgData)
    end

    -- 客户端的数据不是最新数据
    if rankData.uid and rankData.uid ~= targetUid then
        msgData.res = -2
        return InnerMsg.sendMsg(fd, msgData)
    end

    msgData.res = 0
    msgData.playerInfo.name = rankData.name
    msgData.playerInfo.lv = rankData.level
    msgData.playerInfo.head = rankData.head
    msgData.playerInfo.headFrame = rankData.headFrame
    msgData.playerInfo.rank = targetRank

    if rankData.uid then
        msgData.playerInfo.uid = rankData.uid
        msgData.playerInfo.defendObjList = rankData.heroList
    end

    InnerMsg.sendMsg(fd, msgData)
end

-- 普通服查询是否可以挑战某个排名
function CS_Challenge_Query(sourceServerId, defenseRank, defenseUid, attackerUid)
    local rankList = GodsAreaDB.GetRankList()
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)

    local msgData = InnerMsg.wl.WL_GODSATREA_CHALLENGE_QUERY
    msgData.res = 0
    msgData.attackerUid = attackerUid
    msgData.defenseRank = defenseRank
    msgData.defenseUid = defenseUid
    msgData.defenseServerId = 0

    local rankData = rankList[defenseRank]
    if not rankData then
        msgData.res = -1
        return InnerMsg.sendMsg(fd, msgData)
    end

    -- 客户端的排行数据不是最新数据
    if rankData.uid and defenseUid ~= rankData.uid then
        msgData.res = -2
        return InnerMsg.sendMsg(fd, msgData)
    end


    -- 不能挑战比自己排名低的
    local attackerRank = getRankInfoByUid(rankList, attackerUid)
    -- if attackerRank ~= 0 and attackerRank < defenseRank then
    --     msgData.res = -3
    --     return InnerMsg.sendMsg(fd, msgData)
    -- end

    clearChallengeList()

    -- 如果有一方处于挑战/被挑战中, 则提醒
    local now = os.time()
    local aChallengeInfo = challengeList[attackerRank]
    local dChallengeInfo = challengeList[defenseRank]
    if aChallengeInfo and (aChallengeInfo.startTime + MAX_CHALLENGE_TIME) > now then
        msgData.res = 1
    end

    if dChallengeInfo and (dChallengeInfo.startTime + MAX_CHALLENGE_TIME) > now then
        msgData.res = 2
    end

    -- 把被挑战方加入正在挑战列表
    challengeList[defenseRank] = {
        startTime = now,
        attackerUid = attackerUid,
        attackerRank = attackerRank,
        defenseUid = defenseUid,
    }

    -- 如果挑战方在排行榜上, 也加入挑战列表
    if attackerRank ~= 0 then
        challengeList[attackerRank] = {
            startTime = now,
            attackerUid = attackerUid,
            attackerRank = attackerRank,
            defenseUid = defenseUid,
            defenseRank = defenseRank,
        }
    end

    msgData.defenseServerId = rankData.serverId or 0
    msgData.defenseName = rankData.name or "匿名玩家"
    InnerMsg.sendMsg(fd, msgData)
end

-- 普通服通知跨服挑战胜利
function CS_Challenge_Win(sourceServerId, defenseRank, defenseUid, attackerUid, attackInfo)
    local rankList = GodsAreaDB.GetRankList()
    local defenseRankData = rankList[defenseRank]
    local attackerRank, attackerRankData = getRankInfoByUid(rankList, attackerUid)

    local msgData = InnerMsg.wl.WL_GODSATREA_UPDATE_CHENGHAO
    local fd = MiddleManager.getFDBySvrIndex(defenseRankData.serverId)

    local attackData = attackInfo
    attackData._id = defenseRankData._id
    -- 挑战者在榜上则用榜上的展示数据
    if attackerRank ~= 0 then
        attackData = attackerRankData
    end

    -- 挑战方排名高于防守方排名则不做其他操作
    if attackData.rank and attackData.rank ~= 0 and attackData.rank < defenseRankData.rank then
        return
    end

    -- 防守方当前是玩家
    if defenseRankData.uid then
        -- 通知失败方更新称号
        msgData.targetUid = defenseRankData.uid
        msgData.newRank = attackerRank
        msgData.isWinner = 0
        msgData.enemyName = attackData.name or ""
        InnerMsg.sendMsg(fd, msgData)
    end

    -- 挑战者是榜上玩家
    if attackerRank ~= 0 then
        -- 失败方排名更新为胜利方原排名
        defenseRankData.rank = attackerRank
        GodsAreaDB.UpdateRankData(attackerRank, defenseRankData)
    end

    -- 胜利方排名更新为失败方原排名
    attackData.rank = defenseRank
    GodsAreaDB.UpdateRankData(defenseRank, attackData)


    -- 通知胜利方更新称号
    fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    msgData.targetUid = attackerUid
    msgData.newRank = defenseRank
    msgData.isWinner = 1
    msgData.enemyName = defenseRankData.name or ""
    InnerMsg.sendMsg(fd, msgData)


    local logStr = string.format("挑战胜利, attackerUid: %s, attackerRank: %d, defenseRank: %d, defenseOldUid: %s, defenseNowUid: %s",
    attackerUid, attackerRank, defenseRank, defenseUid, defenseRankData.uid or defenseUid)
    writeLog(Log.LOGID_OSS_GODSAREA_CHALLENGE ,logStr)
end

local function getTargetVideo(videoArray, playerUid)
    local len = 0
    local tbl = {}

    -- if not playerUid or not videoArray then
    --     return tbl
    -- end

    for _, videoData in ipairs(videoArray) do
        if videoData.combatInfo.defender.uuid == playerUid then
            len = len +  1
            tbl[len] = videoData
        end
    end
    return tbl
end

-- 普通服请求战斗录像数据
function CS_Query_CombatVideo(sourceServerId, playerUid, targetRank)
    local videoArray = CombatVideo.getCombatVideosByType(CombatVideo.VIDEOTYPE_GODSAREA, targetRank)
    local fd = MiddleManager.getFDBySvrIndex(sourceServerId)
    local msgData = InnerMsg.wl.WL_GODSATREA_QUERY_RANK_VIDEO

    local rankList = GodsAreaDB.GetRankList()
    local rankData = rankList[targetRank]
    local targetUuid = rankData.uid or ""
    -- if not targetUuid then
    --     local rankCfg = GodsAreaConfig.rankList[targetRank]
    --     targetUuid = rankCfg.monsterOutID
    -- end

    local targetVideoArray = getTargetVideo(videoArray, targetUuid)

    msgData.playerUid = playerUid
    msgData.isFinish = 0
    msgData.videoData = {}
    local videoCnt = #targetVideoArray

    if videoCnt <= 0 then
        msgData.isFinish = 1
        InnerMsg.sendMsg(fd, msgData)
        return
    end


    for k,v in ipairs(targetVideoArray) do
        if k > CombatVideo.GODSAREA_RECORD_MAX_CNT then
            break
        end

        msgData.videoData = v
        if k == videoCnt or k == CombatVideo.GODSAREA_RECORD_MAX_CNT then
            msgData.isFinish = 1
        end

        InnerMsg.sendMsg(fd, msgData)
    end
end

-- 更新玩家基础数据
function CS_Update_PlayerInfo(playerUid, newPlayerInfo)
    local rankList = GodsAreaDB.GetRankList()
    local rank, rankData = getRankInfoByUid(rankList, playerUid)
    if rank == 0 then
        return
    end

    for k,v in pairs(newPlayerInfo) do
        rankData[k] = v
    end
    GodsAreaDB.UpdateRankData(rank, rankData)
end

-- 更新英雄数据
function CS_Update_HeroInfo(playerUid, newHeroInfo)
    local rankList = GodsAreaDB.GetRankList()
    local rank, rankData = getRankInfoByUid(rankList, playerUid)
    if rank == 0 then
        return
    end


    local isChange = false
    if newHeroInfo.opType == 0 then
        local rmIdx = getSameIdx(rankData.heroList, newHeroInfo.removeHeroUuid)

        if rmIdx then
            isChange = true
            -- table.remove(rankData.heroList, rmIdx)
            rankData.heroList[rmIdx] = nil
            rankData.power = newHeroInfo.power
        end
    elseif newHeroInfo.opType == 1 then
        for _, v in pairs(newHeroInfo.heroList) do
            local targetIdx = getSameIdx(rankData.heroList, v.heroUuid)
            if targetIdx then
                isChange = true
                rankData.heroList[targetIdx] = v
                rankData.power = newHeroInfo.power
                break
            end
        end
    else
        if next(newHeroInfo.heroList) then
            rankData.heroList = newHeroInfo.heroList
            rankData.power = newHeroInfo.power
            isChange = true
        end
    end

    if isChange then
        GodsAreaDB.UpdateRankData(rank, rankData)
    end
end



-- 通知游戏服, 给玩家发奖
function CS_Send_Reward(fd, rankTb)
    local msgData = InnerMsg.wl.WL_GODSATREA_BROCAST_REWARD
    msgData.uid2RankTb = rankTb or {}
    InnerMsg.sendMsg(fd, msgData)
end