local BattleConst = require "app/module/battle/battle_const"
local SKILL_ROGUE_CFG = ConfigManager:getConfig("skill_rogue")
local BattleBuffEntity = require "app/userdata/battle/skill/battle_buff_entity"

local BattleRogueSkillHandle = {}

local _changeBaseSkill = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.parameter then
        return
    end
    local newSkillId = skillInfo.parameter[1]
    if not newSkillId then
        return
    end

    local skillEntity = battleBaseData:getSkillEntityByElement(elementType, side)
    if skillEntity then
        local skillId = skillEntity:getSkillId()
        battleBaseData:changeSkillId(elementType, newSkillId, side)
        local actionTeam = battleBaseData:getTeamBySide(side)
        if not actionTeam then
            return
        end
        local unitEntity = actionTeam:getAllMembers()[elementType]
        if unitEntity then
            unitEntity:changeSkillId(skillId, newSkillId)
            for effectType, effect in pairs(skillEntity:getSkillRoundAdd()) do -- 技能回合数
                unitEntity:addSkillRound(newSkillId, effect)
            end

            for effectType, effect in pairs(skillEntity:getSkillEffecuNumAdd()) do -- 技能效果
                unitEntity:addSkillParams(newSkillId, effect)
            end

            for effectType, effect in pairs(skillEntity:getSkillRatioAdd()) do -- 技能效果概率
                unitEntity:addSkillRatio(newSkillId, effect)
            end
        end
    end
end

local _addEliminationRange = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.boardrange then
        return
    end

    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    if entity then
        entity:addBoardRange(skillInfo.boardrange)
    end
end

local _canLinkAnyElement = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType then
        return
    end

    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    if entity then
        entity:setIgnoreElementType(true)
    end
end

local _addLinkAtkp = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.effect then
        return
    end

    local actionTeam = battleBaseData:getTeamBySide(side)
    if not actionTeam then
        return
    end

    local unitEntity = actionTeam:getAllMembers()[elementType]
    if not unitEntity then
        return
    end

    for _, effect in ipairs(skillInfo.effect) do
        local entity = battleBaseData:getSkillEntityByElement(elementType, side)
        if entity then
            entity:addLinkEffect(effect, unitEntity, skillInfo.obj)
        end
    end
end

local _changeElementType = function(skillId, skillInfo, battleBaseData, battleController, value, side, isSnapshot)
    if isSnapshot then
        return
    end

    if not skillInfo.boardrange or not skillInfo.parameter then
        return
    end

    local elementType = skillInfo.parameter[1]
    local count = skillInfo.boardrange[1] and skillInfo.boardrange[1].range
    if not elementType or not count then
        return
    end

    battleController:changeElementType(count, elementType)
end

local _addAttr = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    if not skillInfo.attr then
        return
    end

    if not value then
        value = math.random(skillInfo.attr.minnum, skillInfo.attr.maxnum)
    end
    battleController:addHeroAttr(skillInfo.attr.type, value, side)
end

local _unlockSkill = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    if not skillInfo.skill_position then
        return
    end

    battleBaseData:unlockSkillEntity(skillInfo.skill_position, side)
end

local _addSkillEffectParams = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.parameter then
        return
    end
    local index = skillInfo.parameter[1]
    local value = skillInfo.parameter[2]
    if not index or not value then
        return
    end

    local effect
    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    if entity and entity:getEffect() then
        local effectCfg = entity:getEffect()[index]
        if effectCfg then
            effect = GFunc.getTable(effectCfg)
            effect.num = value
        end
    end

    if not effect then
        return
    end

    local skillEntity = battleBaseData:getSkillEntityByElement(elementType, side)
    if skillEntity then
        local skillId = skillEntity:getSkillId()
        skillEntity:addSkillEffecuNumAdd(effect)
        local actionTeam = battleBaseData:getTeamBySide(side)
        if not actionTeam then
            return
        end
        if actionTeam:getAllMembers()[elementType] then
            actionTeam:getAllMembers()[elementType]:addSkillParams(skillId, effect)
        end
    end
end

local _addSkillRound = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.parameter then
        return
    end

    local index = skillInfo.parameter[1]
    local value = skillInfo.parameter[2]
    if not index or not value then
        return
    end

    local effect
    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    if entity and entity:getEffect() then
        local effectCfg = entity:getEffect()[index]
        if effectCfg then
            effect = GFunc.getTable(effectCfg)
            effect.round = value
        end
    end

    if not effect then
        return
    end

    local skillEntity = battleBaseData:getSkillEntityByElement(elementType, side)
    if skillEntity then
        local skillId = skillEntity:getSkillId()
        skillEntity:addSkillRoundAdd(effect)
        local actionTeam = battleBaseData:getTeamBySide(side)
        if not actionTeam then
            return
        end
        if actionTeam:getAllMembers()[elementType] then
            actionTeam:getAllMembers()[elementType]:addSkillRound(skillId, effect)
        end
    end
end

local _addSkillEffect = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    if not skillInfo.effect then
        return
    end

    local effects = GFunc.getTable(skillInfo.effect)
    if not effects then
        return
    end

    local actionTeam = battleController:getCurActionTeam(side)
    for _, effect in ipairs(effects) do
        local target
        if skillInfo.obj == BattleConst.SIDE_DEF then
            target = battleController:getOtherSideTeam(side):getMainUnit()
        elseif skillInfo.obj == BattleConst.SIDE_ATK then
            target = actionTeam:getMainUnit()
        elseif skillInfo.obj == BattleConst.SIDE_ATK_ALL then
            for matchtype, comp in pairs(actionTeam:getUnitComp()) do
                local buffEntity = BattleBuffEntity:create()
                buffEntity:init(effect, comp.unitEntity)
                buffEntity:setTargetSide(skillInfo.obj)
                comp:takeEffect(buffEntity, comp)
            end
            return
        else
            local matchType = BattleConst.SIDE_OBJ_TO_MATCH_TYPE[skillInfo.obj]
            if matchType then
                target = actionTeam:getUnitComp()[matchType]
            end
        end
        if not target then
            return
        end
        local buffEntity = BattleBuffEntity:create()
        buffEntity:init(effect, actionTeam:getMainUnit().unitEntity)
        buffEntity:setTargetSide(skillInfo.obj)

        actionTeam:getMainUnit():takeEffect(buffEntity, target)
    end
end

local _addSkillInInfluenceAtkp = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.effect then
        return
    end

    local actionTeam = battleBaseData:getTeamBySide(side)
    if not actionTeam then
        return
    end

    local unitEntity = actionTeam:getAllMembers()[elementType]
    if not unitEntity then
        return
    end

    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    for _, effect in ipairs(skillInfo.effect) do
        entity:addInInfluenceEffect(effect, unitEntity, skillInfo.obj)
    end
end

local _addSkillAttackBeforeEffect = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.effect then
        return
    end

    local actionTeam = battleBaseData:getTeamBySide(side)
    if not actionTeam then
        return
    end

    local unitEntity = actionTeam:getAllMembers()[elementType]
    if not unitEntity then
        return
    end

    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    if entity then
        if skillInfo.cover_unlock then
            entity:removeSkillAttackBeforeEffect(skillInfo.cover_unlock)
        end
        for k, effect in ipairs(skillInfo.effect) do
            entity:addSkillAttackBeforeEffect(skillId, k, effect, unitEntity, skillInfo.obj)
        end
    end
end

local _addSkillElementCountEffect = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.effect then
        return
    end

    local actionTeam = battleBaseData:getTeamBySide(side)
    if not actionTeam then
        return
    end

    local unitEntity = actionTeam:getAllMembers()[elementType]
    if not unitEntity then
        return
    end

    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    if entity then
        if skillInfo.cover_unlock then
            entity:removeElementCountEffect(skillInfo.cover_unlock)
        end
        for k, effect in ipairs(skillInfo.effect) do
            entity:addElementCountEffect(skillId, k, effect, unitEntity, skillInfo.obj)
        end
    end
end

local _addLinkCountMoreEffect = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.effect or not skillInfo.parameter then
        return
    end

    local actionTeam = battleBaseData:getTeamBySide(side)
    if not actionTeam then
        return
    end

    local unitEntity = actionTeam:getAllMembers()[elementType]
    if not unitEntity then
        return
    end

    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    if entity then
        if skillInfo.cover_unlock then
            entity:removeLinkCountMoreEffects(skillInfo.cover_unlock)
        end
        for k, effect in ipairs(skillInfo.effect) do
            local paramsCount = skillInfo.parameter[1]
            if paramsCount then
                entity:addLinkCountMoreEffects(skillId, k, effect, unitEntity, skillInfo.obj, paramsCount)
            end
        end
    end
end

local _addLinkCountPowerEffect = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.effect or not skillInfo.parameter then
        return
    end

    local actionTeam = battleBaseData:getTeamBySide(side)
    if not actionTeam then
        return
    end

    local unitEntity = actionTeam:getAllMembers()[elementType]
    if not unitEntity then
        return
    end

    local entity = battleBaseData:getSkillEntityByElement(elementType, side)
    if entity then
        if skillInfo.cover_unlock then
            entity:removeLinkCountPowerEffects(skillInfo.cover_unlock)
        end
        for k, effect in ipairs(skillInfo.effect) do
            local paramsCount = skillInfo.parameter[k]
            if paramsCount then
                entity:addLinkCountPowerEffects(skillId, k, effect, unitEntity, skillInfo.obj, paramsCount)
            end
        end
    end
end

local _addSkillRatio = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.parameter then
        return
    end

    local index = skillInfo.parameter[1]
    local value = skillInfo.parameter[2]
    if not index or not value then
        return
    end

    local effect
    local skillEntity = battleBaseData:getSkillEntityByElement(elementType, side)
    if skillEntity and skillEntity:getEffect() then
        local effectCfg = skillEntity:getEffect()[index]
        if effectCfg then
            effect = GFunc.getTable(effectCfg)
            effect.ratio = value
        end
    end

    if not effect then
        return
    end

    if skillEntity then
        local skillId = skillEntity:getSkillId()
        skillEntity:addSkillRatioAdd(effect)
        local actionTeam = battleBaseData:getTeamBySide(side)
        if not actionTeam then
            return
        end
        if actionTeam:getAllMembers()[elementType] then
            actionTeam:getAllMembers()[elementType]:addSkillRatio(skillId, effect)
        end
    end
end

local _addSkillBreakEnergyMultiple = function(skillId, skillInfo, battleBaseData, battleController, value, side)
    local elementType = skillInfo.skill_position
    if not elementType or not skillInfo.parameter then
        return
    end

    local multiple = skillInfo.parameter[1]
    if not multiple then
        return
    end

    local skillEntity = battleBaseData:getSkillEntityByElement(elementType, side)

    if skillEntity then
        skillEntity:addSkillBreakEnergyMultiple(multiple)
    end
end

BattleRogueSkillHandle._effectOn = {
    [1] = _changeBaseSkill,                         -- 改变初始技能ID
    [2] = _addEliminationRange,                     -- 增加消除数量
    [3] = _addLinkAtkp,                             -- 增加链接伤害
    [4] = _canLinkAnyElement,                       -- 可与任何技能连接
    [5] = _addAttr,                                 -- 纯粹增加属性
    [6] = _unlockSkill,                             -- 技能增加释放次数
    [7] = _addSkillEffectParams,                    -- 增加技能效果参数（比如护盾的承伤增加）
    [8] = _addSkillRound,                           -- 增加技能效果持续回合（比如护盾从1回合改为2回合）
    [9] = _addSkillEffect,                          -- 获得技能效果
    [10] = _changeElementType,                      -- 将场上随机几个元素变为某元素
    [11] = _addSkillInInfluenceAtkp,                -- 技能消除的增加伤害
    [12] = _addSkillAttackBeforeEffect,             -- 技能触发前的技能效果
    [13] = _addSkillElementCountEffect,             -- 技能链接中每一个元素累加的技能效果
    [14] = _addLinkCountMoreEffect,                 -- 链接超过x元素获得一次技能效果
    [15] = _addLinkCountPowerEffect,                -- 链接超过x元素获得倍数技能效果
    [16] = _addSkillRatio,                          -- 增加技能效果概率
    [17] = _addSkillBreakEnergyMultiple,            -- 增加技能消除的元素的能量倍数
}

function BattleRogueSkillHandle.takeEffect(skillId, battleData, battleController, value, side, isSnapshot)
    local cfg = SKILL_ROGUE_CFG[skillId]
    if not cfg or not cfg.type then
        return
    end

    ---- 统一处理
    if cfg.method then
        local elementType = cfg.skill_position
        if elementType then
            local skillEntity = battleData:getSkillEntityByElement(elementType, side)
            if skillEntity and skillEntity:getMethond() and skillEntity:getMethond() < cfg.method then
                skillEntity:setMethond(cfg.method)
            end
        end
    end

	local func = BattleRogueSkillHandle._effectOn[cfg.type]
	if func then
        func(skillId, cfg, battleData, battleController, value, side, isSnapshot)
	end
end

return BattleRogueSkillHandle