-- 精灵系统

--db
--[=[
    human.db.elfData = {
        [elfId1] = {
            level = 0,
            star = 0,
        },
        [elfId2] = {
            level = 0,
            star = 0,
        },
    }

]=]--

local Msg = require("core.Msg")
local Lang = require("common.Lang")
local Broadcast = require("broadcast.Broadcast")
local ElfConfig = require("excel.elf")
local ItemConfig = require("excel.item").item
local Grid = require("bag.Grid")
local BagLogic = require("bag.BagLogic")
local Skill = require("combat.Skill")
local RoleAttr = require("role.RoleAttr")
local RoleDefine = require("role.RoleDefine")
local ObjHuman = require("core.ObjHuman")
local RoleSystemLogic = require("roleSystem.RoleSystemLogic")
local RoleSystemDefine = require("roleSystem.RoleSystemDefine")
local HuanJingTowerLogic = require("huanjingTower.HuanjingTowerLogic")
local TalismanLogic = require("talisman.TalismanLogic")
local TriggerLogic = require("trigger.TriggerLogic")
local TriggerDefine = require("trigger.TriggerDefine")
local ChengjiuLogic = require("chengjiu.ChengjiuLogic")

local GiftLogic

local ELF_UPGRADELV_LOG_TAG = "elfUpGradeLv"
local ELF_UPGRADESTAR_LOG_TAG = "elfUpGradeStar"
local ELF_COND_TOWER_LEVEL =  600
local ELF_2_CHENGJIU_TASKID = 406 -- 精灵系统对应的成就任务Id


local function initElfData(human)
    human.db.elfData = {}
end

local function getElfData(human)
    return human.db.elfData
end

local function updateElfData(human, elfId, newLevel, newStar)
    local elfData = getElfData(human)
    if not elfData then
        initElfData(human)
        elfData = getElfData(human)
    end

    elfData[elfId] = elfData[elfId] or {level = 0, star = 0}

    if newLevel then
        elfData[elfId].level = newLevel
    end

    if newStar then
        elfData[elfId].star = newStar
    end
end

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

local function getNextStarCostCnt(nextStar)
    for _, starCfg in ipairs(ElfConfig.UpGradeStar) do
        if nextStar == starCfg.star then
            return starCfg.itemCnt
        end
    end

    return 0
end

local function generateCfgByQuality(targetQuality)
    local tbl = {}
    for id, cfg in ipairs(ElfConfig.Elf) do
        if cfg.elfQuality == targetQuality then
            tbl[id] = cfg
        end
    end

    if not next(tbl) then
        return nil
    end

    return tbl
end

local function getElfCfgById(targetElfId)
    for _, elfCfg in ipairs(ElfConfig.Elf) do
        if elfCfg.elfId == targetElfId then
            return elfCfg
        end
    end
end



-- 计算一共可以升多少级, 消耗多少道具
local function calcUpGrade(nowLv, itemAllCnt, maxLv)
    local addLv, oldItemAllCnt, itemCostCnt = 0, itemAllCnt, 0
    while true do
        nowLv = nowLv + 1
        if nowLv > maxLv then
            break
        end

        itemCostCnt = nowLv * 3 + 2
        if itemAllCnt < itemCostCnt then
            break
        end

        addLv = addLv + 1
        itemAllCnt = itemAllCnt - itemCostCnt
    end

    local useItemCnt = oldItemAllCnt - itemAllCnt

    return addLv, useItemCnt
end
-- 计算当前所有精灵的总星级
local function calcAllElfStar(elfDataList)
    local stars = 0
    for _, elfData in pairs(elfDataList) do
        stars = stars + elfData.star
    end

    return stars
end
-- 计算精灵当前等级加成属性之和
local function calcLvAttr(elfLv, attrCfg)
    local nowAttrVal = 0
    for i=1, elfLv do
        nowAttrVal = nowAttrVal + attrCfg[1] * i + attrCfg[2]
    end
    return nowAttrVal
end



local function populateMsgSimpleData(net, elfCfg, itemCfg, elfData)
    if not net or not elfCfg or not itemCfg then
        return
    end

    local elfNowLv = elfData and elfData.level or 0
    local elfNowStar = elfData and elfData.star or 0

    net.elfId = elfCfg.elfId
    net.elfName = itemCfg.name
    net.elfIcon = itemCfg.icon
    net.elfLv = elfNowLv
    net.elfStar = elfNowStar
    net.elfQuality = elfCfg.elfQuality
    net.maxLv = elfCfg.elfMaxLv
    net.maxStar = elfCfg.elfMaxStar

    local upGradeLvItemId = elfCfg.upGradeLvItemId
    local upGradeLvItemCnt = elfNowLv >= elfCfg.elfMaxLv and 0 or (elfNowLv + 1) * 3 + 2
    Grid.makeItem(net.elfUpGradeLvCost, upGradeLvItemId, upGradeLvItemCnt)

    local upGradeStarItemId = elfCfg.upGradeStarItemId
    local upGradeStarItemCnt = elfNowStar >= elfCfg.elfMaxStar and 0 or getNextStarCostCnt(elfNowStar+1)
    Grid.makeItem(net.elfUpGradeStarCost, upGradeStarItemId, upGradeStarItemCnt)
end

local function populateMsgAttr(attrNet, attrCfg, attrId, elfLv, isMax, attrMul)
    local sumAttrVal = calcLvAttr(elfLv, attrCfg)
    attrNet.nowAttr.key = attrId
    attrNet.nowAttr.value = sumAttrVal * (1 + attrMul)
    attrNet.addAtrr.key = attrId
    attrNet.addAtrr.value = (attrCfg[1] * (elfLv + 1) + attrCfg[2]) * (1 + attrMul)
    if isMax then
        attrNet.addAtrr.value = 0
    end
end

local function populateMsgAttr2(attrNet, attrId, attrVal, elfStar, isMax, attrMul)
    attrMul = 1 + attrMul

    attrNet.nowAttr.key = attrId
    attrNet.nowAttr.value = attrVal * elfStar * attrMul
    attrNet.addAtrr.key = attrId
    attrNet.addAtrr.value = attrVal
    if isMax then
        attrNet.addAtrr.value = 0
    end
end




--是否开启本系统, 内部使用, 需要领取任务奖励后才解锁
local function isOpen(human)
    -- local towerLevel = HuanJingTowerLogic.getTowerLevel(human)
    -- if towerLevel >= ELF_COND_TOWER_LEVEL then
    --     return true
    -- end
    -- return false
    local state = ChengjiuLogic.GetTaskState(human, ELF_2_CHENGJIU_TASKID)
    if state == 2 then
        return true
    end

    return false
end
-- 重算战力
local function updatePower(human)
    RoleAttr.cleanHeroAttrCache(human)
    RoleAttr.doCalc(human)
    ObjHuman.sendAttr(human, RoleDefine.ZHANDOULI)
end
--红点判断
local function dotJudgment(human, cfgHtbl)
    local elfData = getElfData(human)
    for _, cfg in pairs(cfgHtbl) do
        local nowLevel, nowStar = 0, 0
        if elfData and elfData[cfg.elfId] then
            nowLevel = elfData[cfg.elfId].level
            nowStar = elfData[cfg.elfId].star
        end

        if nowStar < cfg.elfMaxStar then
            local upGradeStarCostCnt = getNextStarCostCnt(nowStar+1)
            if BagLogic.getItemCnt(human, cfg.upGradeStarItemId) >= upGradeStarCostCnt then
                return true
            end
        end

        -- 需要精灵可激活或已激活
        if nowStar >= 1 and nowLevel < cfg.elfMaxLv then
            nowLevel = nowLevel + 1
            local costItemCnt = nowLevel * 3 + 2
            if BagLogic.getItemCnt(human, cfg.upGradeLvItemId) >= costItemCnt then
                return true
            end
        end
    end

    return false
end
-- 红点更新
local function updateDot(human, targetQuality)
    local cfgHtbl = generateCfgByQuality(targetQuality)

    if not dotJudgment(human, cfgHtbl) then
        local dotID = 0
        if targetQuality == 1 then
            dotID = RoleSystemDefine.ROLE_SYS_ID_2032
        elseif targetQuality == 2 then
            dotID = RoleSystemDefine.ROLE_SYS_ID_2033
        elseif targetQuality == 3 then
            dotID = RoleSystemDefine.ROLE_SYS_ID_2034
        else
            dotID = RoleSystemDefine.ROLE_SYS_ID_2035
        end

        --刷新单页
        RoleSystemLogic.onDot(human, dotID)
        --刷新入口处
        RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_2031)
    end
end



-- 外部调用,精灵加成
function doCalcHero(human, addAttrs)
    if not human or not human.db then
        return
    end

    local elfData = getElfData(human)
    if not elfData then
        return
    end

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

    for elfId, singleElfData in pairs(elfData) do
        local elfCfg = getElfCfgById(elfId)
        if elfCfg then
            -- 等级加成
            if singleElfData.level > 0 then
                local atkVal = calcLvAttr(singleElfData.level, elfCfg.nAttack1)
                local hpVal = calcLvAttr(singleElfData.level, elfCfg.nLife1)
                RoleAttr.updateValue(RoleDefine.ATK, atkVal * attrMul, addAttrs)
                RoleAttr.updateValue(RoleDefine.HP, hpVal * attrMul, addAttrs)
            end

            -- 星级加成
            RoleAttr.updateValue(RoleDefine.ATK, elfCfg.nAttack2 * singleElfData.star * attrMul, addAttrs)
            RoleAttr.updateValue(RoleDefine.HP, elfCfg.nLife2 * singleElfData.star * attrMul, addAttrs)
            RoleAttr.updateValue(RoleDefine.DEF, elfCfg.nDefense2 * singleElfData.star * attrMul, addAttrs)
            RoleAttr.updateValue(RoleDefine.SPEED, elfCfg.nSpeed2 * singleElfData.star * attrMul, addAttrs)
        end

    end
end

-- 外部调用, 本系统是否开启
function ModuleisOpen(human)
    -- return isOpen(human)
    local towerLevel = HuanJingTowerLogic.getTowerLevel(human)
    if towerLevel >= ELF_COND_TOWER_LEVEL then
        return true
    end
    return false
end

-- 外部调用, 是否有红点
function isDot(human, dotConfig)
    if not isOpen(human) then
        return false
    end
    --入口处的红点判断
    if dotConfig.id == RoleSystemDefine.ROLE_SYS_ID_2031 then
        return dotJudgment(human, ElfConfig.Elf)
    else
        --单个分页的红点
        local elfQuality = 0
        if dotConfig.id == RoleSystemDefine.ROLE_SYS_ID_2032 then
            elfQuality = 1
        elseif dotConfig.id == RoleSystemDefine.ROLE_SYS_ID_2033 then
            elfQuality = 2
        elseif dotConfig.id == RoleSystemDefine.ROLE_SYS_ID_2034 then
            elfQuality = 3
        else
            elfQuality = 4
        end

        local cfgHtbl = generateCfgByQuality(elfQuality)
        if not cfgHtbl then
            return false
        end

        return dotJudgment(human, cfgHtbl)
    end
end

-- 外部调用,是否激活了精灵
function IsActivateElf(human, elfId)
    if not isOpen(human) then
        return false
    end

    local elfData = getElfData(human)
    if not elfData or not elfData[elfId] then
        return false
    end

    return true
end

-- 外部调用,获取精灵当前技能
function GetElfSkill(human, elfId)
    -- if not isOpen(human) then
    --     return
    -- end

    local elfData = getElfData(human)
    if not elfData or not elfData[elfId] then
        return
    end

    local elfNowStar = elfData[elfId].star
    local elfCfg = getElfCfgById(elfId)
    if not elfCfg then
        return
    end

    return elfCfg.skillArr[elfNowStar]
end




-- 请求某个品质的所有精灵的简单数据
function Elf_SimpleData_Query(human, targetElfQuality)
    if not isOpen(human) then
        return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED)
    end

    local elfData = getElfData(human) or {}
    local msgRet = Msg.gc.GC_ELF_SIMPLEDATA_QUERY
    local elfArr = msgRet.elfArr
    elfArr[0] = 0
    local len = 0
    msgRet.allStars = calcAllElfStar(elfData)

    for _, elfCfg in ipairs(ElfConfig.Elf) do
        if elfCfg.elfQuality == targetElfQuality then
            local elfId = elfCfg.elfId
            local itemCfg = ItemConfig[elfId]
            if itemCfg then
                len = len + 1
                populateMsgSimpleData(elfArr[len], elfCfg, itemCfg, elfData[elfId])
            end
        end
    end

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

-- 请求某个精灵的详细数据
function Elf_SingleElf_Query(human, elfId)
    if not isOpen(human) then
        return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED)
    end

    local itemCfg = ItemConfig[elfId]
    local elfCfg = getElfCfgById(elfId)
    if not itemCfg or not elfCfg then
        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
    end

    local elfData = getElfData(human) or {}
    local targetElfData = elfData[elfId]
    local msgRet = Msg.gc.GC_ELF_SINGLE_QUERY

    populateMsgSimpleData(msgRet.elfSimpleData, elfCfg, itemCfg, targetElfData)

    local elfNowLv = targetElfData and targetElfData.level or 0
    local elfNowStar = targetElfData and targetElfData.star or 0

    local isMaxLv, isMaxStar = false, false
    if elfNowLv >= elfCfg.elfMaxLv then
        isMaxLv = true
    end

    if elfNowStar >= elfCfg.elfMaxStar then
        isMaxStar = true
    end

    local elfSkillDataMsg = msgRet.elfSkillData

    elfSkillDataMsg.nowSkillDesc = ""
    local elfNowSkillId = elfCfg.skillArr[elfNowStar]
    local nowSkillCfg = Skill.GetSkillConfig(elfNowSkillId)
    if nowSkillCfg then
        elfSkillDataMsg.nowSkillDesc = nowSkillCfg.desc
    end

    elfSkillDataMsg.nextSkillDesc = ""
    local elfNextSkillId = isMaxStar and elfCfg.skillArr[#elfCfg.skillArr] or elfCfg.skillArr[elfNowStar+1]
    local nextSkillCfg = Skill.GetSkillConfig(elfNextSkillId)
    if nextSkillCfg then
        elfSkillDataMsg.nextSkillDesc = nextSkillCfg.desc
    end

    elfSkillDataMsg.maxSkillDesc = ""
    local elfMaxSkillId = elfCfg.skillArr[#elfCfg.skillArr]
    local maxSkillCfg = Skill.GetSkillConfig(elfMaxSkillId)
    if maxSkillCfg then
        elfSkillDataMsg.maxSkillDesc = maxSkillCfg.desc
    end

    local attrMul = getAttrMulFromTalisman(human)

    msgRet.elfLvAttrInfo[0] = 2
    populateMsgAttr(msgRet.elfLvAttrInfo[1], elfCfg.nAttack1, RoleDefine.ATK, elfNowLv, isMaxLv, attrMul)
    populateMsgAttr(msgRet.elfLvAttrInfo[2], elfCfg.nLife1, RoleDefine.HP, elfNowLv, isMaxLv, attrMul)

    msgRet.elfStarAttrInfo[0] = 4
    populateMsgAttr2(msgRet.elfStarAttrInfo[1], RoleDefine.HP, elfCfg.nLife2, elfNowStar, isMaxStar, attrMul)
    populateMsgAttr2(msgRet.elfStarAttrInfo[2], RoleDefine.ATK, elfCfg.nAttack2, elfNowStar, isMaxStar, attrMul)
    populateMsgAttr2(msgRet.elfStarAttrInfo[3], RoleDefine.DEF, elfCfg.nDefense2, elfNowStar, isMaxStar, attrMul)
    populateMsgAttr2(msgRet.elfStarAttrInfo[4], RoleDefine.SPEED, elfCfg.nSpeed2, elfNowStar, isMaxStar, attrMul)

    Msg.send(msgRet, human.fd)
end

-- 精灵升级
function Elf_UpGradeLv(human, elfId, opType)
    if not isOpen(human) then
        return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED)
    end

    local elfCfg = getElfCfgById(elfId)
    if not elfCfg then
        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
    end

    local elfData = getElfData(human) or {}

    if not elfData[elfId] then
        return Broadcast.sendErr(human, Lang.ELF_NOT_ACTIVATE)
    end

    local elfNowLv = elfData[elfId].level or 0
    if elfNowLv >= elfCfg.elfMaxLv then
        return Broadcast.sendErr(human, Lang.COMMON_MAXLEVEL)
    end

    local upGradeLvItemId = elfCfg.upGradeLvItemId
    local upGradeLvItemCnt = 0
    local itemAllCnt = BagLogic.getItemCnt(human, upGradeLvItemId)
    if itemAllCnt <= 0 then
        return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
    end

    -- if BagLogic.getItemCnt(human, upGradeLvItemId) < upGradeLvItemCnt then
    --     return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
    -- end

    local addLv = 0
    if opType == 1 then
        addLv = 1
        upGradeLvItemCnt = (elfNowLv + 1) * 3 + 2
    elseif opType == 2 then
        addLv, upGradeLvItemCnt = calcUpGrade(elfNowLv, itemAllCnt, elfCfg.elfMaxLv)
    else
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    if addLv == 0 or BagLogic.getItemCnt(human, upGradeLvItemId) < upGradeLvItemCnt then
        return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
    end

    BagLogic.delItem(human, upGradeLvItemId, upGradeLvItemCnt, ELF_UPGRADELV_LOG_TAG)

    updateElfData(human, elfId, elfNowLv+addLv)

    Elf_SingleElf_Query(human, elfId)

    updatePower(human)

    -- 红点刷新
    updateDot(human, elfCfg.elfQuality)
end

-- 精灵升星
function Elf_UpGradeStar(human, elfId)
    if not isOpen(human) then
        return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED)
    end

    local elfCfg = getElfCfgById(elfId)
    if not elfCfg then
        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
    end

    local elfData = getElfData(human) or {}
    local elfNowStar = elfData[elfId] and elfData[elfId].star or 0
    if elfNowStar >= elfCfg.elfMaxStar then
        return Broadcast.sendErr(human, Lang.COMMON_MAXLEVEL)
    end

    local nextStar = elfNowStar+1
    local upGradeStarItemId = elfCfg.upGradeStarItemId
    local upGradeStarItemCnt = getNextStarCostCnt(nextStar)
    if upGradeStarItemCnt == 0 then
        return Broadcast.sendErr(human, Lang.ELF_MAX_STAR)
    end

    if BagLogic.getItemCnt(human, upGradeStarItemId) < upGradeStarItemCnt then
        return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
    end
    BagLogic.delItem(human, upGradeStarItemId, upGradeStarItemCnt, ELF_UPGRADESTAR_LOG_TAG)

    updateElfData(human, elfId, nil, nextStar)

    Elf_SingleElf_Query(human, elfId)

    updatePower(human)

    -- 红点刷新
    updateDot(human, elfCfg.elfQuality)

    local nAllStar = calcAllElfStar(elfData)
    TriggerLogic.PublishEvent(TriggerDefine.EVENT_TYPE_JINGLING_STAR, human.db._id, 1)

    GiftLogic = GiftLogic or require("topup.GiftLogic")
    GiftLogic.trigger(human, GiftLogic.GIFT_ELF_UPGRADE_STAR, {currentVal = nAllStar}, GiftLogic.GIFT_SEC_TYPE3)

    local BaiZhanChengShenNS = require("baiZhanChengShen.BaiZhanChengShenNS")
    BaiZhanChengShenNS.onElfStarUp(human, elfId)
end

-- 布阵界面, 请求精灵数据
function Elf_GetElfData_FromPosPage(human, targetElfQuality)
    local msgRet = Msg.gc.GC_ELF_POS_QUERY
    local elfArr = msgRet.elfArr
    elfArr[0] = 0
    local len = 0
    local elfData = getElfData(human) or {}

    for _, elfCfg in ipairs(ElfConfig.Elf) do
        if elfCfg.elfQuality == targetElfQuality then
            local elfId = elfCfg.elfId
            local itemCfg = ItemConfig[elfId]
            if itemCfg then
                len = len + 1
                local elfNowLv = elfData and elfData.level or 0
                local elfNowStar = elfData[elfId] and elfData[elfId].star or 0

                elfArr[len].elfId = elfId
                elfArr[len].elfName = itemCfg.name
                elfArr[len].elfIcon = itemCfg.icon
                elfArr[len].elfLv = elfNowLv
                elfArr[len].elfStar = elfNowStar
                elfArr[len].elfQuality = targetElfQuality
                elfArr[len].nowSkillDesc = ""
                elfArr[len].nowSkillIcon = ""
                
                local elfNowSkillId = elfCfg.skillArr[elfNowStar]
                local nowSkillCfg = Skill.GetSkillConfig(elfNowSkillId)
                if nowSkillCfg then
                    elfArr[len].nowSkillDesc = nowSkillCfg.desc
                    elfArr[len].nowSkillIcon = nowSkillCfg.icon
                end
            end
        end

    end

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