-- 天元系统

local Lang = require("common.Lang")
local Msg = require("core.Msg")
local BagLogic = require("bag.BagLogic")
local HeroLogic = require("hero.HeroLogic")
local ObjHuman = require("core.ObjHuman")
local Grid = require("bag.Grid")
local RoleAttr = require("role.RoleAttr")
local HeroTianYuanCfg = require("excel.heroTianYuan")
local Broadcast = require("broadcast.Broadcast")
local RoleDefine = require("role.RoleDefine")
local TalismanLogic = require("talisman.TalismanLogic")

local GiftLogic

local LOGTAG = "HeroTianYuan" --日志标识


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


local function initData(heroGrid)
    heroGrid.tianYuanData = {
        pointIdx = 0,
        stage = 0,
    }
end

local function updateData(heroGrid, newPointIdx, newStage)
    if not heroGrid.tianYuanData then
        initData(heroGrid)
    end

    if newPointIdx then
        heroGrid.tianYuanData.pointIdx = newPointIdx
    end

    if newStage then
        heroGrid.tianYuanData.stage = newStage
    end
end



-- 系统开启条件检查
local function openCheck(human, heroID, heroIndex)
    local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
    if not heroGrid then
        return Broadcast.sendErr(human, Lang.FUWEN_HERO_GRID_ERR)
    end

    local varCfg = HeroTianYuanCfg.var[1]
    if heroGrid.star < varCfg.unLockCondStar then
        return Broadcast.sendErr(human, Lang.HEROPUB_STAR_NOT_ENOUGH)
    end

    return true
end

-- 获取正确的消耗道具信息
local function getTargetItemArr(nowStage, nowPointIdx, maxStage)
    local varCfg = HeroTianYuanCfg.var[1]
    local targetStageCfgIdx = math.min(nowStage + 1, maxStage)
    local targetStageCfg = HeroTianYuanCfg.upGrade[targetStageCfgIdx]

    local itemCfg
    if nowPointIdx < varCfg.pointMaxNum and nowStage < maxStage then
        itemCfg = targetStageCfg.pointCost
    else
        itemCfg = targetStageCfg.stageCost
    end

    local itemArr = {}
    for i, itemInfo in ipairs(itemCfg) do
        itemArr[i] = { itemInfo[1], itemInfo[2] }
    end

    return itemArr
end

local function transformData(targetList, sourceArr, mul)
    mul = mul or 1
    for _, tb in ipairs(sourceArr) do
        local id = tb[1]
        local val = tb[2]
        targetList[id] = (targetList[id] or 0) + val * mul
    end
end

-- 统计数据, dataType: 1-加成属性, 2-消耗道具
local function calcData(nowStage, nowPointIdx, dataType)
    if nowStage <= 0 and nowPointIdx <= 0 then
        return
    end

    local dataList = {}
    local maxPointNum = HeroTianYuanCfg.var[1].pointMaxNum

    for i = 1, nowStage do
        -- 天元突破的消耗道具/加成属性
        local stageCfg = HeroTianYuanCfg.upGrade[i]
        if stageCfg then
            local sourceData = stageCfg.stageCost
            if dataType == 1 then
                sourceData = stageCfg.stageAttrs
            end
            transformData(dataList, sourceData)
        end

        -- 天元点的消耗道具/加成属性
        stageCfg = HeroTianYuanCfg.upGrade[i+1]
        if stageCfg then
            local sourceData = stageCfg.pointCost
            local pointNum = 0

            if i == nowStage and nowPointIdx > 0 then
                pointNum = nowPointIdx
            elseif i ~= nowStage then
                pointNum = maxPointNum
            end

            if pointNum > 0 then
                if dataType == 1 then
                    sourceData = stageCfg.pointAttrs
                end
                transformData(dataList, sourceData, pointNum)
            end
        end
    end

    -- 0 ~ 1重天元点的消耗道具/加成属性
    local pointNum = nowPointIdx
    if nowStage >= 1 then
        pointNum = maxPointNum
    end

    local stageOneCfg = HeroTianYuanCfg.upGrade[1]
    local sourceData = stageOneCfg.pointCost
    if dataType == 1 then
        sourceData = stageOneCfg.pointAttrs
    end
    transformData(dataList, sourceData, pointNum)

    return dataList
end

-- 获取下一次提升增加的属性
local function getNextAttrs(nowStage, nowPointIdx, maxPointNum)
    nowStage = math.min(nowStage+1, #HeroTianYuanCfg.upGrade)
    local stageCfg = HeroTianYuanCfg.upGrade[nowStage]

    if nowPointIdx >= maxPointNum then -- 当前天元点已全部点亮, 需要突破天元
        return stageCfg.stageAttrs
    else
        return stageCfg.pointAttrs
    end
end

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



-- 英雄天元红点检测
function isTianYuanDot(human, heroGrid)
    local varCfg = HeroTianYuanCfg.var[1]
    if heroGrid.star < varCfg.unLockCondStar then
        return false
    end

    local tianYuanData = heroGrid.tianYuanData
    local nowPointIdx = tianYuanData and tianYuanData.pointIdx or 0
    local nowStage = tianYuanData and tianYuanData.stage or 0
    local maxStage = #HeroTianYuanCfg.upGrade

    if nowStage >= maxStage then
        return false
    end

    local itemArr = getTargetItemArr(nowStage, nowPointIdx, maxStage)
    for _, item in ipairs(itemArr) do
        if BagLogic.getItemCnt(human, item[1]) < item[2] then
            return false
        end
    end

    return true
end

-- 计算返还材料
function CalcReturnItem(human, heroGrid)
    if not heroGrid or not heroGrid.tianYuanData then
        return
    end

    local nowStage = heroGrid.tianYuanData.stage or 0
    local nowPointIdx = heroGrid.tianYuanData.pointIdx or 0
    local itemList = calcData(nowStage, nowPointIdx, 2)

    return itemList
end

-- 重置英雄天元数据
function ResetTianYuanData(human, heroGrid)
    if not heroGrid or not heroGrid.tianYuanData then
        return
    end

    heroGrid.tianYuanData = nil
end

-- 英雄天元加成
function doCalcHero(human, heroGrid, tatgetAttrs)
    if not heroGrid or not heroGrid.tianYuanData then
        return
    end

    local nowStage = heroGrid.tianYuanData.stage or 0
    local nowPointIdx = heroGrid.tianYuanData.pointIdx or 0
    local sourceAttrs = calcData(nowStage, nowPointIdx, 1)

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

    for attrId, attrVal in pairs(sourceAttrs or {}) do
        RoleAttr.updateValue(attrId, attrVal * attrMul, tatgetAttrs)
    end
end



-- 查询英雄天元信息
function HeroTianYuan_Query(human, heroID, heroIndex)
    local res = openCheck(human, heroID, heroIndex)
    if res ~= true then
        return
    end

    local maxPointNum = HeroTianYuanCfg.var[1].pointMaxNum
    local upGradeCfg = HeroTianYuanCfg.upGrade

    local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
    local tianYuanData = heroGrid.tianYuanData
    local nowPointIdx = tianYuanData and tianYuanData.pointIdx or 0
    local nowStage = tianYuanData and tianYuanData.stage or 0

    local msgRet = Msg.gc.GC_HEROTY_QUERY
    msgRet.pointIdx = nowPointIdx
    msgRet.stageIdx = nowStage
    msgRet.stageMax = #upGradeCfg
    msgRet.maxPoint = maxPointNum

    -- 消耗
    local itemArr = getTargetItemArr(nowStage, nowPointIdx, msgRet.stageMax)
    local item = itemArr[1]
    local itemId, itemCnt = item[1], item[2]
    if nowStage >= msgRet.stageMax then
        itemCnt = 0
    end
    Grid.makeItem(msgRet.cost, itemId, itemCnt)

    -- msgRet.cost[0] = #itemArr
    -- for i, item in ipairs(itemArr) do
    --     local itemId, itemCnt = item[1], item[2]
    --     if nowStage >= msgRet.stageMax then
    --         itemCnt = 0
    --     end

    --     Grid.makeItem(msgRet.cost[i], itemId, itemCnt)
    -- end

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

    -- 总加成属性
    msgRet.attrs[0] = 0
    local attrs = calcData(nowStage, nowPointIdx, 1)
    if attrs then
        local len = 0
        for attrId, attrVal in pairs(attrs) do
            len = len + 1
            msgRet.attrs[0] = len
            msgRet.attrs[len].key = attrId
            msgRet.attrs[len].value = attrVal * attrMul
        end
    end

    -- 下一次提升增加的属性
    msgRet.nextAttrs[0] = 0
    if nowStage < msgRet.stageMax then
        local nextAttrs = getNextAttrs(nowStage, nowPointIdx, maxPointNum)
        if nextAttrs then
            msgRet.nextAttrs[0] = #nextAttrs
            for i, attrTb in ipairs(nextAttrs) do
                msgRet.nextAttrs[i].key = attrTb[1]
                msgRet.nextAttrs[i].value = attrTb[2] * attrMul
            end
        end
    end

    Msg.send(msgRet, human.fd)
end

-- 请求点亮天元点
function HeroTianYuan_PointUpGrade(human, heroID, heroIndex)
    local res = openCheck(human, heroID, heroIndex)
    if res ~= true then
        return
    end

    local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
    local varCfg = HeroTianYuanCfg.var[1]

    local tianYuanData = heroGrid.tianYuanData
    local nowPointIdx = tianYuanData and tianYuanData.pointIdx or 0
    local nowStage = tianYuanData and tianYuanData.stage or 0

    if nowPointIdx >= varCfg.pointMaxNum then
        return Broadcast.sendErr(human, Lang.HERO_TY_POINT_MAX)
    end

    if nowStage >= #HeroTianYuanCfg.upGrade then
        return Broadcast.sendErr(human, Lang.HERO_TY_STAGE_MAX)
    end

    local targetCfgIdx = nowStage + 1
    local targetStageCfg = HeroTianYuanCfg.upGrade[targetCfgIdx]

    if not targetStageCfg then
        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
    end

    -- 消耗检查
    for _, itemInfo in ipairs(targetStageCfg.pointCost) do
        if BagLogic.getItemCnt(human, itemInfo[1]) < itemInfo[2] then
            return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
        end
    end

    -- 扣除消耗
    for _, itemInfo in ipairs(targetStageCfg.pointCost) do
        BagLogic.delItem(human, itemInfo[1], itemInfo[2], LOGTAG)
    end


    -- 更新点亮天元点索引
    nowPointIdx = nowPointIdx + 1
    updateData(heroGrid, nowPointIdx)

    -- 推送最新数据给客户端
    HeroTianYuan_Query(human, heroID, heroIndex)

    -- 更新战力
    updatePower(human, heroID, heroIndex)

    -- 刷新红点
    HeroLogic.refreshDot(human, heroGrid.uuid)
end

-- 请求天元突破
function HeroTianYuan_StageUpGrade(human, heroID, heroIndex)
    local res = openCheck(human, heroID, heroIndex)
    if res ~= true then
        return
    end

    local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
    local varCfg = HeroTianYuanCfg.var[1]

    local tianYuanData = heroGrid.tianYuanData
    local nowPointIdx = tianYuanData and tianYuanData.pointIdx or 0
    local nowStage = tianYuanData and tianYuanData.stage or 0

    if nowPointIdx < varCfg.pointMaxNum then
        return Broadcast.sendErr(human, Lang.HERO_TY_POINT_NOT_ENOUGH)
    end

    if nowStage >= #HeroTianYuanCfg.upGrade then
        return Broadcast.sendErr(human, Lang.HERO_TY_STAGE_MAX)
    end

    local nextStage = nowStage + 1
    local nextStageCfg = HeroTianYuanCfg.upGrade[nextStage]
    if not nextStageCfg then
        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
    end

    -- 消耗检查
    for _, itemInfo in ipairs(nextStageCfg.stageCost) do
        if BagLogic.getItemCnt(human, itemInfo[1]) < itemInfo[2] then
            return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
        end
    end

    -- 扣除消耗
    for _, itemInfo in ipairs(nextStageCfg.stageCost) do
        BagLogic.delItem(human, itemInfo[1], itemInfo[2], LOGTAG)
    end

    -- 更新天元点索引, 天元重数
    updateData(heroGrid, 0, nextStage)

    -- 推送最新数据给客户端
    HeroTianYuan_Query(human, heroID, heroIndex)

    -- 更新战力
    updatePower(human, heroID, heroIndex)

    -- 刷新红点
    HeroLogic.refreshDot(human, heroGrid.uuid)

    -- 弹窗礼包
    GiftLogic = GiftLogic or require("topup.GiftLogic")
    GiftLogic.trigger(human, GiftLogic.GIFT_HEROTIANYUAN_UPGRADE_STAR, {currentVal = nextStage}, GiftLogic.GIFT_SEC_TYPE3)
end