-- 英雄酒馆功能
-- 统计SSR和UR英雄中不同ID英雄的最高星级,并根据星级获得加成属性

-- db
--[=[
    human.db.heroPubData = nil 
    -- {
    --     activateIdxList = { [idx] = 1, [idx2] = 1,},--当前激活加成属性在配置中的索引列表
    --     heroList = {},
    --     rewardGetList = {}   -- 酒馆奖励领取列表
    -- }
]=]--

local Msg = require("core.Msg")
local HeroLogic = require("hero.HeroLogic")
local Lang = require("common.Lang")
local Broadcast = require("broadcast.Broadcast")
local RoleAttr = require("role.RoleAttr")
local RoleDefine = require("role.RoleDefine")
local ObjHuman = require("core.ObjHuman")
local Util = require("common.Util")
local HeroPubCfg = require("excel.heroPub").pub
local HeroGrid = require("hero.HeroGrid")
local RoleSystemLogic = require("roleSystem.RoleSystemLogic")
local RoleSystemDefine = require("roleSystem.RoleSystemDefine")
local Grid = require("bag.Grid")
local BagLogic = require("bag.BagLogic")
local TalismanLogic = require("talisman.TalismanLogic")


HERO_OP_UPSTAR      = 1     -- 升星/合成
HERO_OP_DEL         = 2     -- 删除
HERO_OP_RETURN      = 3     -- 回退
HERO_OP_ADD         = 4     -- 获得

local LOGTAG = "HeroPub"

-- 获取来自秘宝的属性倍数加成
local function getAttrMulFromTalisman(human)
    local attrMul = TalismanLogic.getTalismanAdd(human, TalismanLogic.OTHER_EFFECT_TBL.HeroPubLogic_Attr_Mul)
    attrMul = attrMul / 100
    return attrMul
end


local function initPubData(human)
    human.db.heroPubData = human.db.heroPubData or {}
    human.db.heroPubData.activateIdxList = human.db.heroPubData.activateIdxList or {}
    human.db.heroPubData.rewardGetList = human.db.heroPubData.rewardGetList or {}

    -- 新增
    -- if not human.db.heroPubData.rewardGetList then
    --     human.db.heroPubData.rewardGetList = {}
    -- end

end

local function getPubData(human)
    return human.db.heroPubData
end

local function updatePubData(human, opType, activateIdx)
    local heroPubData = getPubData(human)
    if not heroPubData then
        initPubData(human)
        heroPubData = getPubData(human)
    end

    if opType > 0 then
        heroPubData.activateIdxList[activateIdx] = 1
    else
        heroPubData.activateIdxList[activateIdx] = nil
    end
end

local function updateRewardGetList(human, rewardIdx)
    local heroPubData = getPubData(human)
    heroPubData.rewardGetList[rewardIdx] = '1'
end



-- 数据格式转换
local function transformHeroData(human)
    local pubHeroList = human.pubHeroList
    if not pubHeroList or not next(pubHeroList) then
        return
    end

    local len = 0
    local heroInfoTbl = {}

    for _, heroInfo in pairs(pubHeroList) do
        len = len + 1
        heroInfoTbl[len] = heroInfo
    end

    return heroInfoTbl
end

local function isCanActivate(idxList, maxIdx)
    if maxIdx <= 0 then
        return false
    end

    for i=1, maxIdx do
        if  not idxList[i] then
            return true
        end
    end

    return false
end

-- 计算当前符合条件的所有英雄的总星级
local function calcAllHeroStar(heroList)
    local stars = 0
    for _, heroInfo in pairs(heroList or {}) do
        stars = stars + heroInfo.star
    end
    return stars
end

-- 根据星级，获得英雄酒馆加成属性在配置中的索引
local function getPubAttrIdx(maxStarHeroList)
    local idx = 0
    local star = calcAllHeroStar(maxStarHeroList)
    if star <= 0 then
        return idx
    end

    for k, v in ipairs(HeroPubCfg) do
        if star < v.activateStar then
            break
        end

        idx = k
    end
    return idx
end

-- 重置缓存的酒馆英雄数据
local function resetPubHeroList(human, newHeroList)
    if not human.pubHeroList then
        human.pubHeroList = {}
    else
        Util.initTable(human.pubHeroList)
    end

    for heroId, heroInfo in pairs(newHeroList) do
        human.pubHeroList[heroId] = {
            uuid = heroInfo.uuid,
            star = heroInfo.star
        }
    end
end



-- 更新战力
local function updatePower(human)
    RoleAttr.cleanHeroAttrCache(human)
    ObjHuman.doCalc(human)
    ObjHuman.sendAttr(human, RoleDefine.ZHANDOULI)
end

-- 更新加成属性
local function updatePubAttr(human)
    local heroPubData = getPubData(human)
    if not heroPubData then
        return
    end

    local bl = false
    local activateIdxList = heroPubData.activateIdxList
    local nowMaxAttrIdx = getPubAttrIdx(human.pubHeroList)
    local maxAttrIdx = #HeroPubCfg

    for i = nowMaxAttrIdx+1, maxAttrIdx do
        if activateIdxList[i] then
            updatePubData(human, 0, i)
            bl = true
        end
    end


    -- 只有加成属性降低才自动更新, 加成属性提高则需要手动更新...
    if bl then
        updatePower(human)
    end
end

-- 进行红点检测
local function redDotCheck(human)
    RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_304)
end

-- 获取宝箱红点状态
local function getBoxRedDot(human)
    local heroPubData = getPubData(human)

    local nowMaxStar = calcAllHeroStar(human.pubHeroList)
    local rewardGetList = heroPubData and heroPubData.rewardGetList or {}

    for idx, starCfg in ipairs(HeroPubCfg) do
        if nowMaxStar >= starCfg.activateStar and not rewardGetList[idx] then
            return true
        end
    end

    return false
end


-- 更新酒馆的宝箱红点
local function updateBoxRedDot(human)
    local msgRet = Msg.gc.GC_HEROPUB_BOX_REDDOT

    msgRet.redDotState = 0
    if getBoxRedDot(human) then
        msgRet.redDotState = 1
    end

    Msg.send(msgRet, human.fd)
end


-- 英雄升星/合成时的处理函数
local function upgradeStarFunc(human, heroId, herouuid)
    local targetHerouuid
    local pubHeroList = human.pubHeroList
    local heroGrid = HeroLogic.getHeroGridByUuid(human, herouuid)

    local oldHeroInfo = pubHeroList[heroId]
    if heroGrid.star > oldHeroInfo.star then
        oldHeroInfo.uuid = herouuid
        oldHeroInfo.star = heroGrid.star

        targetHerouuid = herouuid
    end

    return targetHerouuid
end

-- 英雄回退/删除时的处理函数
local function delHeroFunc(human, heroId, herouuid)
    local targetHerouuid, isDel
    local pubHeroList = human.pubHeroList

    if not pubHeroList or not next(pubHeroList) then
        return
    end
    
    -- 当前星级最高的英雄删除/回退了,
    if pubHeroList[heroId] and pubHeroList[heroId].uuid == herouuid then
        pubHeroList[heroId] = nil
        isDel = true

        -- 获取同ID的英雄中星级最高的
        local newMaxStar, newHerouuid = HeroLogic.GetMaxStarHero(human, heroId)
        if newMaxStar and newHerouuid then
            pubHeroList[heroId] = {uuid = newHerouuid, star = newMaxStar}

            targetHerouuid = newHerouuid
        end
    end

    return targetHerouuid, isDel
end

-- 获得英雄时的处理函数
local function addHeroFunc(human, heroId, herouuid)
    local targetHerouuid
    local pubHeroList = human.pubHeroList

    local heroGrid = HeroLogic.getHeroGridByUuid(human, herouuid)
    if not pubHeroList or not pubHeroList[heroId] then
        targetHerouuid = herouuid
    else
        if pubHeroList[heroId] and pubHeroList[heroId].star < heroGrid.star then
            targetHerouuid = herouuid
        end
    end


    if targetHerouuid then
        human.pubHeroList = human.pubHeroList or {}
        human.pubHeroList[heroId] = human.pubHeroList[heroId] or {}
        human.pubHeroList[heroId].uuid = herouuid
        human.pubHeroList[heroId].star = heroGrid.star
    end

    return targetHerouuid
end



local function respondHeroInfo(human)
    local msgMax = 20
    local msgRet = Msg.gc.GC_HEROPUB_HERO_QUERY
    local msgHeroList = msgRet.heroList

    local heroInfoTbl = transformHeroData(human)
    if not heroInfoTbl then
        msgHeroList[0] = 0
        msgRet.start = 1
        msgRet.isEnd = 1
        Msg.send(msgRet, human.fd)
    else
        local len = 0
        local startTag = 1
        local maxLen =#heroInfoTbl
        for i=1, maxLen do
            len = len + 1
            msgHeroList[0] = len
            local net = { relic = {}, gemData = {}, general = {}}
            local heroGrid = HeroLogic.getHeroGridByUuid(human, heroInfoTbl[i].uuid)
            HeroGrid.makeHeroSimple(net, heroGrid, nil, human)

            msgHeroList[len].heroId = net.id
            msgHeroList[len].heroName = net.name
            msgHeroList[len].heroStar = net.star
            msgHeroList[len].heroCamp = net.camp
            msgHeroList[len].heroBody = net.body
            msgHeroList[len].heroGrade = net.grade

            if len >= msgMax then
                msgRet.start = startTag
                msgRet.isEnd = 0
                if maxLen - len <= 0 then
                    msgRet.isEnd = 1
                    return Msg.send(msgRet, human.fd)
                end
                Msg.send(msgRet, human.fd)

                len = 0
                startTag = 0
                maxLen = maxLen - msgMax
            end
        end

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

local function respndAttrInfo(human)
    local msgMax = 20
    local startTag = 1
    local maxLen = #HeroPubCfg
    local heroPubData = getPubData(human)
    local nowMaxStar = calcAllHeroStar(human.pubHeroList)

    local attrMul = getAttrMulFromTalisman(human)
    attrMul = 1 + attrMul

    local msgRet = Msg.gc.GC_HEROPUB_ATTR_QUERY
    msgRet.star = nowMaxStar
    local attrList = msgRet.attrList

    local len = 0
    for i, cfg in ipairs(HeroPubCfg) do
        len = len + 1
        attrList[0] = len
        attrList[len].index = i
        attrList[len].isActivate = 0
        attrList[len].activateStar = cfg.activateStar
        if heroPubData and heroPubData.activateIdxList[i] then
            attrList[len].isActivate = 1
        end

        local attrInfo = attrList[len].attrInfo
        for k ,v in ipairs(cfg.attrs) do
            attrInfo[k].key = v[1]
            attrInfo[k].value = v[2] * attrMul

            attrInfo[0] = k
        end

        if len >= msgMax then
            msgRet.start = startTag
            msgRet.isEnd = 0

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

            len = 0
            startTag = 0
            maxLen = maxLen - msgMax
        end
    end

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

end

-- local function respondUpdateSingleHero(human, updateHerouuid, delHeroId)
--     local msgRet = Msg.gc.GC_HEROPUB_UPDATE_HERO

--     local net = { relic = {}, gemData = {}, general = {}}
--     if updateHerouuid then
--         local heroGrid = HeroLogic.getHeroGridByUuid(human, updateHerouuid)
--         HeroGrid.makeHeroSimple(net, heroGrid, nil, human)
--     end

--     msgRet.updateHeroInfo.heroId = net.id or delHeroId
--     msgRet.updateHeroInfo.heroName = net.name or ""
--     msgRet.updateHeroInfo.heroStar = net.star or 0
--     msgRet.updateHeroInfo.heroCamp = net.camp or 0
--     msgRet.updateHeroInfo.heroBody = net.body or 0
--     msgRet.updateHeroInfo.heroGrade = net.grade or 0

--     Msg.send(msgRet, human.fd)
-- end



function onLogin(human)
    local maxStarHeroList = HeroLogic.GetHeroMaxStarList(human)

    if next(maxStarHeroList) then

        -- 缓存组成酒馆的英雄列表
        resetPubHeroList(human, maxStarHeroList)

    end
end

function doCalcHero(human, attrs)
    if not human then
        return
    end

    local heroPubData = getPubData(human)
    if not heroPubData then
        return
    end

    local attrMul = getAttrMulFromTalisman(human)
    attrMul = 1 + attrMul

    local activateIdxList = heroPubData.activateIdxList
    for k, v in ipairs(HeroPubCfg) do
        if activateIdxList[k] then
            for _, attrInfo in ipairs(v.attrs) do
                RoleAttr.updateValue(attrInfo[1], attrInfo[2] * attrMul, attrs)
            end
        end
    end
end

-- 英雄总star有更新(升星/合成, 回退, 删除, 增加)
function UpdateHero(human, opType, heroId, herouuid)
    local updateHerouuid, isDel

    if opType == HERO_OP_UPSTAR then
        updateHerouuid = upgradeStarFunc(human, heroId, herouuid)
    elseif opType == HERO_OP_DEL then
        updateHerouuid, isDel = delHeroFunc(human, heroId, herouuid)
    elseif opType == HERO_OP_RETURN then
        updateHerouuid = delHeroFunc(human, heroId, herouuid)
    elseif opType == HERO_OP_ADD then
        updateHerouuid = addHeroFunc(human, heroId, herouuid)
    end


    local delHeroId = 0
    if opType == HERO_OP_DEL and not updateHerouuid and isDel then --英雄被删，且背包中没有同ID的英雄
        delHeroId = heroId
    end

    if updateHerouuid or delHeroId > 0 then
        redDotCheck(human)

        updatePubAttr(human)

        updateBoxRedDot(human)
        -- respondUpdateSingleHero(human, updateHerouuid, delHeroId)

        -- respndAttrInfo(human)
    end

end

--红点判断
function isDot(human)
    local heroPubData = getPubData(human)
    local nowMaxAttrIdx = getPubAttrIdx(human.pubHeroList)


    if not heroPubData then
        if nowMaxAttrIdx <= 0 then
            return false
        else
            return true
        end
    end

    if isCanActivate(heroPubData.activateIdxList, nowMaxAttrIdx) then
        return true
    end

    if getBoxRedDot(human) then
        return true
    end

    return false
end

-- GM 设置激活
function GM_SetAttrIdx(human, idx)
    if not idx then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    if idx < 0 then
        idx = 0
    end

    local reallyIdx = getPubAttrIdx(human.pubHeroList)
    if idx > reallyIdx then
        idx = reallyIdx
    end

    -- if idx > #HeroPubCfg then
    --     idx = #HeroPubCfg
    -- end

    local heroPubData = getPubData(human)
    if heroPubData then
        Util.initTable(heroPubData.activateIdxList)
    end


    updatePubData(human, 1, idx)

    ObjHuman.GM_SaveDB(human)
end



-- 查询
function PubQuery(human)
    respondHeroInfo(human)
    respndAttrInfo(human)
    updateBoxRedDot(human)
end

--激活属性
function ActivatePubAtrr(human, targetIdx)
    local nowMaxIdx = getPubAttrIdx(human.pubHeroList)

    if targetIdx > nowMaxIdx then
        return Broadcast.sendErr(human, Lang.HEROPUB_STAR_NOT_ENOUGH)
    end

    local heroPubData = getPubData(human)
    if heroPubData and heroPubData.activateIdxList and heroPubData.activateIdxList[targetIdx] then
        return Broadcast.sendErr(human, Lang.BINGSHU_LEARN_ERR_HAD)
    end

    updatePubData(human, 1, targetIdx)

    local msgRet = Msg.gc.GC_HEROPUB_ACTIVATE
    msgRet.index = targetIdx
    Msg.send(msgRet, human.fd)

    --更新战力
    updatePower(human)

    --红点检测
    redDotCheck(human)

end

-- 奖励查询
function RewardQuery(human)
    local msgMax = 10
    local startTag, len = 1, 0
    local maxLen = #HeroPubCfg
    local heroPubData = getPubData(human)
    local rewardGetList = heroPubData and heroPubData.rewardGetList
    local nowMaxStar = calcAllHeroStar(human.pubHeroList)

    local msgRet = Msg.gc.GC_HEROPUB_REWARD_QUERY
    msgRet.nowStar = nowMaxStar
    msgRet.isEnd = 0
    local rewardList = msgRet.rewardList

    for idx, starCfg in ipairs(HeroPubCfg) do
        len = len + 1
        rewardList[len].reallyIdx = idx
        rewardList[len].condStar = starCfg.activateStar

        rewardList[len].state = 0
        if nowMaxStar >= starCfg.activateStar then
            rewardList[len].state = 1
        end
        if rewardGetList and rewardGetList[idx] then
            rewardList[len].state = 2
        end

        local itemArray = rewardList[len].itemArray
        for k, itemCfg in ipairs(starCfg.reward) do
            itemArray[0] = k
            Grid.makeItem(itemArray[k], itemCfg[1], itemCfg[2])
        end

        if len >= msgMax then
            rewardList[0] = len
            msgRet.start = startTag

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

            len = 0
            startTag = 0
        end
    end

    if len > 0 then
        rewardList[0] = len
        msgRet.start = startTag
        msgRet.isEnd = 1
        Msg.send(msgRet, human.fd)
    end
end

-- 奖励领取
function RewardGet(human)
    local heroPubData = getPubData(human)
    if not heroPubData or not heroPubData.rewardGetList then
        initPubData(human)
        heroPubData = getPubData(human)
    end
    local rewardGetList = heroPubData.rewardGetList
    local nowMaxStar = calcAllHeroStar(human.pubHeroList)

    local itemList = {}
    for idx, starCfg in ipairs(HeroPubCfg) do
        if nowMaxStar >= starCfg.activateStar and not rewardGetList[idx] then
            for _, itemCfg in ipairs(starCfg.reward) do
                local itemId = itemCfg[1]
                itemList[itemId] = (itemList[itemId] or 0) + itemCfg[2]
            end

            updateRewardGetList(human, idx)
        end
    end

    BagLogic.addItemList(human, itemList, LOGTAG)
    RewardQuery(human)
    redDotCheck(human)
    updateBoxRedDot(human)
end