--------------------------------
-- 文件名       :   ServerCommerceActPeakBettle.lua
-- 文件说明     :   巅峰战场
-- 创建时间     :   2025/11/13
-- 创建人       :   WWF
--------------------------------

local Util = require("common.Util")
local Lang = require("common.Lang")
local Msg = require("core.Msg")
local ObjHuman = require("core.ObjHuman")
local Broadcast = require("broadcast.Broadcast")
local BagLogic = require("bag.BagLogic")
local Grid = require("bag.Grid")
local ItemDefine = require("bag.ItemDefine")
local CombatLogic = require("combat.CombatLogic")
local CombatDefine = require("combat.CombatDefine")
local CombatPosLogic = require("combat.CombatPosLogic")
local RoleLogic = require("role.RoleLogic")
local RoleDBLogic = require("role.RoleDBLogic")
local MailManager = require("mail.MailManager")
local MailExcel = require("excel.mail")
local ServerCommerceManager = require("serverCommerce.ServerCommerceManager")
local ServerCommerceActDefine = require("serverCommerce.ServerCommerceActDefine")

-- Excel配置表
-- local PeakBattlefieldRewardExcel = require("excel.peakbattlefieldReward")

-- 巅峰战场常量定义
local INIT_RANK = 999
local MATCH_RANK_MIN_OFFSET = 50  -- 向下偏移
local MATCH_RANK_MAX_OFFSET = 10  -- 向上偏移
local MATCH_RANK_MIN = 1          -- 最小排名
local MATCH_RANK_MAX = 999        -- 最大排名
local OPPONENT_LIST_SIZE = 5
local DAILY_FREE_CHALLENGE_CNT = 5
local CHALLENGE_COST_ITEM_ID = 115
local CHALLENGE_COST_ITEM_CNT = 3
local REWARD_ID_WIN = 1001      -- 战胜奖励
local REWARD_ID_LOSE = 1002     -- 战败奖励
local INIT_HERO_CNT_PER_CAMP = 5
local MAIL_ID_DEFEAT = 1  -- 战败通知邮件ID
local MAIL_ID_RANK_REWARD = 0  -- 排名奖励邮件ID

-- 战斗类型
local COMBAT_TYPE_PEAK_BATTLEFIELD = CombatDefine.COMBAT_TYPE35 or 35

-- 数据库相关
local LuaMongo = _G.lua_mongo
local DB = require("common.DB")

-- 排名映射：uuid -> rank
local UUID_2_RANK = {}
-- 排名数据：rank -> data
local RANK_2_DATA = {}

-- 查询条件
local QueryByUuid = {_id = nil}

----------------------------------------- 内部处理开始 -------------------------------------

-- 获取玩家排名
local function getRank(uuid)
    local rank = UUID_2_RANK[uuid]
    return rank or 0
end

-- 获取玩家数据
local function getData(uuid)
    local rank = UUID_2_RANK[uuid]
    if not rank then return end
    return RANK_2_DATA[rank]
end

-- 获取对手列表
local function getOpponentList(uuid)
    local data = getData(uuid)
    if not data then return {} end
    return data.opponentList or {}
end

-- 获取已解锁英雄列表
local function getUnlockedHeroes(uuid)
    local data = getData(uuid)
    if not data then return {} end
    return data.unlockedHeroes or {}
end

-- 获取每日免费挑战次数
local function getFreeChallengeCnt(uuid)
    local data = getData(uuid)
    if not data then return DAILY_FREE_CHALLENGE_CNT end
    
    -- 检查是否需要重置（跨天）
    local lastResetTime = data.lastResetTime or 0
    if not Util.isSameDay(lastResetTime, os.time()) then
        return DAILY_FREE_CHALLENGE_CNT
    end
    
    return data.freeChallengeCnt or DAILY_FREE_CHALLENGE_CNT
end

-- 消耗免费挑战次数
local function consumeFreeChallenge(uuid)
    local data = getData(uuid)
    if not data then return false end
    
    local lastResetTime = data.lastResetTime or 0
    local freeCnt = getFreeChallengeCnt(uuid)
    
    if freeCnt <= 0 then
        return false
    end
    
    -- 跨天重置
    if not Util.isSameDay(lastResetTime, os.time()) then
        data.freeChallengeCnt = DAILY_FREE_CHALLENGE_CNT
        data.lastResetTime = os.time()
    end
    
    data.freeChallengeCnt = (data.freeChallengeCnt or DAILY_FREE_CHALLENGE_CNT) - 1
    updateData(data)
    return true
end

-- 排名比较函数（排名越小越靠前）
local function rankCmp(a, b)
    if a.rank ~= b.rank then
        return a.rank < b.rank
    end
    return (a.time or 0) < (b.time or 0)
end

-- 排序排名
local function sortRank()
    if #RANK_2_DATA > 1 then
        table.sort(RANK_2_DATA, rankCmp)
    end
    for rank = 1, #RANK_2_DATA do
        local uuid = RANK_2_DATA[rank]._id
        UUID_2_RANK[uuid] = rank
        RANK_2_DATA[rank].rank = rank
    end
end

-- 添加玩家
local function addPlayer(human)
    local rank = UUID_2_RANK[human.db._id]
    if rank then return end
    
    local data = {}
    data._id = human.db._id
    data.rank = INIT_RANK
    data.opponentList = {}
    data.unlockedHeroes = {}
    data.freeChallengeCnt = DAILY_FREE_CHALLENGE_CNT
    data.lastResetTime = os.time()
    data.time = os.time()
    data.name = human.db.name or ""
    data.lv = human.db.lv or 1
    data.head = human.db.head or 0
    data.zhandouli = human.db.zhandouli or 0
    
    LuaMongo.insert(DB.db_peak_battlefield, data)
    
    RANK_2_DATA[#RANK_2_DATA + 1] = data
    sortRank()
end

-- 交换排名（挑战胜利时）
local function swapRank(atkUuid, defUuid)
    local atkRank = UUID_2_RANK[atkUuid]
    local defRank = UUID_2_RANK[defUuid]
    
    if not atkRank or not defRank then return end
    
    local atkData = RANK_2_DATA[atkRank]
    local defData = RANK_2_DATA[defRank]
    
    if not atkData or not defData then return end
    
    -- 交换排名
    local tempRank = atkData.rank
    atkData.rank = defData.rank
    defData.rank = tempRank
    
    atkData.time = os.time()
    defData.time = os.time()
    
    -- 清空对手列表（需要重新匹配）
    atkData.opponentList = {}
    defData.opponentList = {}
    
    updateData(atkData)
    updateData(defData)
    
    sortRank()
end

-- 设置对手列表
local function setOpponentList(uuid, opponentList)
    local data = getData(uuid)
    if not data then return end
    
    data.opponentList = opponentList or {}
    updateData(data)
end

-- 更新已解锁英雄
local function updateUnlockedHeroes(uuid, heroList)
    local data = getData(uuid)
    if not data then return end
    
    data.unlockedHeroes = heroList or {}
    updateData(data)
end

-- 更新数据库
local function updateData(data)
    QueryByUuid._id = data._id
    LuaMongo.update(DB.db_peak_battlefield, QueryByUuid, data)
end

-- 获取排名范围内的玩家（用于匹配）
local function getPlayersInRankRange(minRank, maxRank, excludeUuid)
    local result = {}
    excludeUuid = excludeUuid or ""
    
    for rank = 1, #RANK_2_DATA do
        local data = RANK_2_DATA[rank]
        if data.rank >= minRank and data.rank <= maxRank and data._id ~= excludeUuid then
            result[#result + 1] = data
        end
    end
    
    return result
end

-- 获取活动剩余时间（秒）
local function getActivityLeftTime()
    local nStartTime, nEndTime = ServerCommerceManager.CommerceAct_GetOpenAndEndTime()
    if not nEndTime or nEndTime == 0 then
        return 0
    end
    
    local now = os.time()
    local leftTime = math.max(nEndTime - now, 0)
    return leftTime
end

-- 生成对手列表
local function generateOpponents(uuid, rank)
    if rank <= 0 then
        rank = INIT_RANK
    end
    
    local minRank = math.max(rank - MATCH_RANK_MIN_OFFSET, MATCH_RANK_MIN)
    local maxRank = math.min(rank + MATCH_RANK_MAX_OFFSET, MATCH_RANK_MAX)
    
    local candidates = getPlayersInRankRange(minRank, maxRank, uuid)
    
    -- 随机选择5个对手
    local opponentList = {}
    local selected = {}
    local needCnt = OPPONENT_LIST_SIZE
    
    if #candidates > 0 then
        for i = 1, math.min(needCnt, #candidates) do
            local idx = math.random(1, #candidates)
            while selected[idx] do
                idx = math.random(1, #candidates)
            end
            selected[idx] = true
            opponentList[#opponentList + 1] = {
                uuid = candidates[idx]._id,
                rank = candidates[idx].rank
            }
        end
    end
    
    return opponentList
end

-- 检查并解锁英雄（使用系统英雄表，按阵营解锁）
local function checkAndUnlockHeroes(human, rank)
    local HeroExcel = require("excel.hero").hero
    
    local currentUnlocked = getUnlockedHeroes(human.db._id)
    local newUnlocked = {}
    
    -- 根据排名解锁英雄：初始排名时解锁每个阵营的初始英雄
    if rank <= INIT_RANK then
        -- 使用 CombatDefine 中的阵营定义
        local camps = {
            CombatDefine.CAMP_TYPE1,  -- 恶魔（人族）
            CombatDefine.CAMP_TYPE2,  -- 圣堂（妖族）
            CombatDefine.CAMP_TYPE3   -- 不死（兽族）
        }
        
        for _, camp in ipairs(camps) do
            -- 从HeroExcel中获取该阵营的所有英雄
            local campHeroes = {}
            for heroId, heroConfig in pairs(HeroExcel) do
                if heroConfig.camp == camp then
                    campHeroes[#campHeroes + 1] = heroId
                end
            end
            
            -- 随机选择初始数量的英雄
            if #campHeroes > 0 then
                local count = INIT_HERO_CNT_PER_CAMP
                local maxSelect = math.min(count, #campHeroes)
                for i = 1, maxSelect do
                    local idx = math.random(1, #campHeroes)
                    local heroId = campHeroes[idx]
                    
                    -- 检查是否已解锁
                    local found = false
                    for k = 1, #currentUnlocked do
                        if currentUnlocked[k] == heroId then
                            found = true
                            break
                        end
                    end
                    
                    if not found then
                        newUnlocked[#newUnlocked + 1] = heroId
                        currentUnlocked[#currentUnlocked + 1] = heroId
                    end
                    
                    -- 移除已选择的英雄，避免重复
                    table.remove(campHeroes, idx)
                    if #campHeroes == 0 then break end
                end
            end
        end
    end
    
    if #newUnlocked > 0 then
        updateUnlockedHeroes(human.db._id, currentUnlocked)
        -- 发送提示
        Broadcast.sendErr(human, "解锁新英雄！")
    end
end

-- 发送战败邮件
local function sendDefeatMail(defeatedUuid, attackerUuid, newRank)
    local attackerDb = RoleDBLogic.getDb(attackerUuid)
    if not attackerDb then return end
    
    -- 获取邮件配置
    local mailID = MAIL_ID_DEFEAT
    if not mailID or mailID == 0 then
        return
    end
    
    local mailConfig = MailExcel.mail[mailID]
    if not mailConfig then 
        print("[sendDefeatMail] 邮件配置不存在，mailID=" .. (mailID or 0))
        return 
    end
    
    -- 格式化邮件内容
    local content = Util.format(mailConfig.content or "", attackerDb.name or "", newRank)
    
    -- 发送邮件
    MailManager.add(MailManager.SYSTEM, defeatedUuid, mailConfig.title or "巅峰战区赛", content, nil, mailConfig.senderName or "系统")
end

----------------------------------------- 外部调用 -------------------------------------

-- 起服初始化
function Init()
    -- 从数据库加载所有玩家数据
    local cursor = LuaMongo.find(DB.db_peak_battlefield, {})
    if cursor then
        RANK_2_DATA = {}
        UUID_2_RANK = {}
        
        local data = LuaMongo.next(cursor)
        while data do
            RANK_2_DATA[#RANK_2_DATA + 1] = data
            data = LuaMongo.next(cursor)
        end
        
        sortRank()
        print("[ServerCommerceActPeakBettle - Init] 巅峰战场数据加载完成")
    end
    return true
end

-- 活动结束
function End()
    -- 活动结束后可以重置数据（如果需要）
end

-- 重置玩家数据
function ResetData(human)
    if not human then
        return
    end
end

----------------------------------------- 客户端请求 -------------------------------------

-- 查询巅峰战场数据
function CommerceActPeakBettle_Query(human)
    -- 确保玩家已加入
    if not getData(human.db._id) then
        addPlayer(human)
    end
    
    local data = getData(human.db._id)
    if not data then return end
    
    local rank = getRank(human.db._id)
    local freeCnt = getFreeChallengeCnt(human.db._id)
    local opponentList = getOpponentList(human.db._id)
    local unlockedHeroes = getUnlockedHeroes(human.db._id)
    
    -- 如果没有对手列表，生成对手
    if not opponentList or #opponentList == 0 then
        opponentList = generateOpponents(human.db._id, rank)
        setOpponentList(human.db._id, opponentList)
    end
    
    local msgRet = Msg.gc.GC_PEAK_BATTLEFIELD_QUERY
    msgRet.rank = rank
    msgRet.freeChallengeCnt = freeCnt
    
    -- 填充对手列表
    local len = 0
    for i = 1, #opponentList do
        if len >= OPPONENT_LIST_SIZE then break end
        local opponent = opponentList[i]
        local opponentData = getData(opponent.uuid)
        if opponentData then
            len = len + 1
            local net = msgRet.opponentList[len]
            net.uuid = opponent.uuid
            net.rank = opponent.rank or opponentData.rank
            
            -- 填充角色信息
            local db = RoleDBLogic.getDb(opponent.uuid)
            if db then
                RoleLogic.makeRoleBase(db, net.roleBase)
            else
                -- 如果是NPC或离线玩家，使用缓存数据
                net.roleBase.name = opponentData.name or ""
                net.roleBase.lv = opponentData.lv or 1
                net.roleBase.head = opponentData.head or 0
                net.roleBase.zhandouli = opponentData.zhandouli or 0
            end
        end
    end
    msgRet.opponentList[0] = len
    
    -- 填充已解锁英雄
    len = 0
    for i = 1, #unlockedHeroes do
        if len >= 50 then break end
        len = len + 1
        msgRet.unlockedHeroes[len] = unlockedHeroes[i]
    end
    msgRet.unlockedHeroes[0] = len
    
    -- 活动剩余时间
    msgRet.leftTime = getActivityLeftTime()
    
    Msg.send(msgRet, human.fd)
end

-- 刷新对手列表
function CommerceActPeakBettle_Refresh(human)
    local rank = getRank(human.db._id)
    local opponentList = generateOpponents(human.db._id, rank)
    setOpponentList(human.db._id, opponentList)
    
    local msgRet = Msg.gc.GC_PEAK_BATTLEFIELD_REFRESH
    local len = 0
    for i = 1, #opponentList do
        if len >= OPPONENT_LIST_SIZE then break end
        local opponent = opponentList[i]
        local opponentData = getData(opponent.uuid)
        if opponentData then
            len = len + 1
            local net = msgRet.opponentList[len]
            net.uuid = opponent.uuid
            net.rank = opponent.rank or opponentData.rank
            
            local db = RoleDBLogic.getDb(opponent.uuid)
            if db then
                RoleLogic.makeRoleBase(db, net.roleBase)
            else
                net.roleBase.name = opponentData.name or ""
                net.roleBase.lv = opponentData.lv or 1
                net.roleBase.head = opponentData.head or 0
                net.roleBase.zhandouli = opponentData.zhandouli or 0
            end
        end
    end
    msgRet.opponentList[0] = len
    
    Msg.send(msgRet, human.fd)
end

-- 挑战对手
function CommerceActPeakBettle_Challenge(human, opponentUuid)
    -- 检查对手是否在对手列表中
    local opponentList = getOpponentList(human.db._id)
    local found = false
    for i = 1, #opponentList do
        if opponentList[i].uuid == opponentUuid then
            found = true
            break
        end
    end
    
    if not found then
        return Broadcast.sendErr(human, "对手不在列表中")
    end
    
    -- 检查挑战次数
    local freeCnt = getFreeChallengeCnt(human.db._id)
    if freeCnt > 0 then
        -- 使用免费次数
        if not consumeFreeChallenge(human.db._id) then
            return Broadcast.sendErr(human, "免费挑战次数不足")
        end
    else
        -- 消耗道具
        if not BagLogic.checkItem(human, CHALLENGE_COST_ITEM_ID, CHALLENGE_COST_ITEM_CNT) then
            return Broadcast.sendErr(human, "挑战券不足")
        end
        BagLogic.delItem(human, CHALLENGE_COST_ITEM_ID, CHALLENGE_COST_ITEM_CNT, "peak_battlefield_challenge")
    end
    
    -- 启动战斗
    local cbParam = {
        opponentUuid = opponentUuid,
        combatType = COMBAT_TYPE_PEAK_BATTLEFIELD
    }
    
    CombatLogic.combatBegin(human, nil, {opponentUuid = opponentUuid}, COMBAT_TYPE_PEAK_BATTLEFIELD, cbParam, false)
end

-- 战斗结束回调
function CommerceActPeakBettle_OnFightEnd(human, result, combatType, cbParam, combatInfo, param)
    if combatType ~= COMBAT_TYPE_PEAK_BATTLEFIELD then return end
    if not cbParam or not cbParam.opponentUuid then return end
    
    local opponentUuid = cbParam.opponentUuid
    local isWin = (result == CombatDefine.RESULT_WIN)
    
    local oldRank = getRank(human.db._id)
    local newRank = oldRank
    
    -- 胜利：交换排名
    if isWin then
        swapRank(human.db._id, opponentUuid)
        newRank = getRank(human.db._id)
        
        -- 刷新对手列表
        local rank = getRank(human.db._id)
        local opponentList = generateOpponents(human.db._id, rank)
        setOpponentList(human.db._id, opponentList)
        
        -- 检查英雄解锁
        checkAndUnlockHeroes(human, newRank)
    end
    
    -- 失败：发送邮件通知（给被挑战者）
    if not isWin then
        sendDefeatMail(opponentUuid, human.db._id, newRank)
    end
    
    -- 发放奖励（挑战奖励，rewardType=1）
    local rewardId = isWin and REWARD_ID_WIN or REWARD_ID_LOSE
    local rewardConfig = PeakBattlefieldRewardExcel.rankReward[rewardId]
    if rewardConfig and rewardConfig.rewardType == 1 and rewardConfig.reward then
        BagLogic.addItemList(human, rewardConfig.reward, "peak_battlefield_challenge")
    end
    
    -- 发送结果
    local msgRet = Msg.gc.GC_PEAK_BATTLEFIELD_CHALLENGE
    msgRet.result = isWin and 1 or 2
    msgRet.newRank = newRank
    
    -- 填充奖励
    msgRet.reward[0] = 0
    if rewardConfig and rewardConfig.rewardType == 1 and rewardConfig.reward then
        for i = 1, #rewardConfig.reward do
            local item = rewardConfig.reward[i]
            msgRet.reward[0] = msgRet.reward[0] + 1
            Grid.makeItem(msgRet.reward[msgRet.reward[0]], item[1], item[2])
        end
    end
    
    -- 胜利时发送新的对手列表
    if isWin then
        local opponentList = getOpponentList(human.db._id)
        local len = 0
        for i = 1, #opponentList do
            if len >= OPPONENT_LIST_SIZE then break end
            local opponent = opponentList[i]
            local opponentData = getData(opponent.uuid)
            if opponentData then
                len = len + 1
                local net = msgRet.opponentList[len]
                net.uuid = opponent.uuid
                net.rank = opponent.rank or opponentData.rank
                
                local db = RoleDBLogic.getDb(opponent.uuid)
                if db then
                    RoleLogic.makeRoleBase(db, net.roleBase)
                else
                    net.roleBase.name = opponentData.name or ""
                    net.roleBase.lv = opponentData.lv or 1
                    net.roleBase.head = opponentData.head or 0
                    net.roleBase.zhandouli = opponentData.zhandouli or 0
                end
            end
        end
        msgRet.opponentList[0] = len
    else
        msgRet.opponentList[0] = 0
    end
    
    Msg.send(msgRet, human.fd)
end

-- 查询排名奖励
function CommerceActPeakBettle_RankRewardQuery(human)
    local rank = getRank(human.db._id)
    
    local msgRet = Msg.gc.GC_PEAK_BATTLEFIELD_RANK_REWARD_QUERY
    msgRet.rank = rank
    
    -- 填充奖励列表（从Excel配置读取，只读取排名奖励 rewardType=2或3）
    local len = 0
    if PeakBattlefieldRewardExcel.rankReward then
        for rewardID, config in pairs(PeakBattlefieldRewardExcel.rankReward) do
            -- 只处理排名奖励（rewardType=2或3），排除挑战奖励（rewardType=1）
            if config.rewardType and (config.rewardType == 2 or config.rewardType == 3) then
                if config.rank and type(config.rank) == "table" and #config.rank >= 2 then
                    local rankMin = config.rank[1]
                    local rankMax = config.rank[2]
                    if rank >= rankMin and rank <= rankMax then
                        len = len + 1
                        if len <= 20 then
                            msgRet.rewardList[len] = rewardID
                        end
                    end
                end
            end
        end
    end
    msgRet.rewardList[0] = len
    
    Msg.send(msgRet, human.fd)
end

-- 活动结算（活动结束时发放排名奖励）
function CommerceActPeakBettle_OnActivityEnd()
    -- 获取所有玩家数据
    if not RANK_2_DATA then return end
    
    -- 遍历所有排名，发放奖励
    for rank = 1, #RANK_2_DATA do
        local data = RANK_2_DATA[rank]
        if data and data._id then
            -- 根据排名查找对应的奖励配置（只处理排名奖励 rewardType=2或3）
            if PeakBattlefieldRewardExcel.rankReward then
                for rewardID, config in pairs(PeakBattlefieldRewardExcel.rankReward) do
                    -- 只处理排名奖励，排除挑战奖励
                    if config.rewardType and (config.rewardType == 2 or config.rewardType == 3) then
                        if config.rank and type(config.rank) == "table" and #config.rank >= 2 then
                            local rankMin = config.rank[1]
                            local rankMax = config.rank[2]
                            if rank >= rankMin and rank <= rankMax then
                                -- 发放排名奖励（通过邮件）
                                local mailID = MAIL_ID_RANK_REWARD
                                if mailID and mailID > 0 then
                                    local mailConfig = MailExcel.mail[mailID]
                                    if mailConfig and config.reward then
                                        local content = Util.format(mailConfig.content or "", rank)
                                        MailManager.add(MailManager.SYSTEM, data._id, mailConfig.title or "巅峰战场排名奖励", content, config.reward, mailConfig.senderName or "系统")
                                    end
                                end
                                break  -- 找到对应奖励后跳出
                            end
                        end
                    end
                end
            end
        end
    end
end

-- 检查红点
function isRed(human)
    -- 可以根据需要实现红点逻辑
    return false
end

----------------------------------------- 战斗模块接口 -------------------------------------
-- 供战斗模块使用的公共接口

-- 获取玩家数据（供战斗模块使用）
function GetData(uuid)
    return getData(uuid)
end

-- 检查对手是否存在（供战斗模块使用）
function CheckOpponent(opponentUuid)
    local data = getData(opponentUuid)
    return data ~= nil
end

