local BattleConst = GConst.BattleConst
local SIDE_ATK = GConst.BattleConst.SIDE_ATK
local BATTLE_ROGUE_SKILL_HANDLE = require "app/module/battle/skill/battle_rogue_skill_handle"

local BattleSnapshotHelper = {}
local NEED_SAVE_SNAPSHOT_BATTLE_TYPE = {
    [BattleConst.BATTLE_TYPE.STAGE] = true,
    [BattleConst.BATTLE_TYPE.DAILY_CHALLENGE] = true,
}

function BattleSnapshotHelper:clearSnap(battleBaseController)
    if not NEED_SAVE_SNAPSHOT_BATTLE_TYPE[battleBaseController.battleType] then
        return
    end
    LocalData:saveBattleSnapshot({})
end

function BattleSnapshotHelper:snapshotBattleInfo(battleBaseController)
    -- 每一波开始时记录, 此时怪物为正常状态
    if not NEED_SAVE_SNAPSHOT_BATTLE_TYPE[battleBaseController.battleType] then
        return
    end

    battleBaseController.snapShotInfo = table.clearOrCreate(battleBaseController.snapShotInfo)
    -- 战斗
    battleBaseController.snapShotInfo.params = table.clearOrCreate(battleBaseController.snapShotInfo.params)            -- 战斗参数
    if battleBaseController.params then
        if battleBaseController.params.atkFormation then
            local formation = battleBaseController.params.atkFormation
            battleBaseController.snapShotInfo.params.atkFormation = table.clearOrCreate(battleBaseController.snapShotInfo.params.atkFormation)
            for matchType, heroEntity in pairs(formation) do
                battleBaseController.snapShotInfo.params.atkFormation[tostring(matchType)] = heroEntity:getCfgId()
            end
        end
        if battleBaseController.snapShotInfo.params.defFormation then
            battleBaseController.snapShotInfo.params.defFormation = nil
        end
    end
    battleBaseController.snapShotInfo.battleType = battleBaseController.battleType                                      -- 战斗类型
    battleBaseController.snapShotInfo.totalDurationTime = battleBaseController.totalDurationTime                        -- 总时间
    battleBaseController.snapShotInfo.eliminateTotalCount = battleBaseController.eliminateTotalCount                    -- 消除个数
    battleBaseController.snapShotInfo.maxLinkCount = battleBaseController.maxLinkCount                                  -- 最长链接数
    battleBaseController.snapShotInfo.realTime = battleBaseController.realTime                                          -- 真实时间
    battleBaseController.snapShotInfo.taskProgress = battleBaseController.taskProgress                                  -- 战斗任务数据
    battleBaseController.snapShotInfo.waveRoundCount = table.clearOrCreate(battleBaseController.snapShotInfo.waveRoundCount) -- 波次的回合数
    for k, v in pairs(battleBaseController.waveRoundCount) do
        battleBaseController.snapShotInfo.waveRoundCount[tostring(k)] = v
    end
    battleBaseController.snapShotInfo.lastRoundBreakedGridType = table.clearOrCreate(battleBaseController.snapShotInfo.lastRoundBreakedGridType) -- 上一回合破碎的格子类型
    for k, v in pairs(battleBaseController.lastRoundBreakedGridType) do
        battleBaseController.snapShotInfo.lastRoundBreakedGridType[tostring(k)] = v
    end
    battleBaseController.snapShotInfo.curBoardIndex = battleBaseController.curBoardIndex
    battleBaseController.snapShotInfo.chapterId = battleBaseController.chapterId                                        -- 当前战斗关卡
    battleBaseController.snapShotInfo.waveIndex = battleBaseController:getWaveIndex()                                        -- 当前波次
    battleBaseController.snapShotInfo.gotMysteryBoxIndexs = table.clearOrCreate(battleBaseController.snapShotInfo.gotMysteryBoxIndexs)  -- 神秘宝箱索引
    for k, v in pairs(battleBaseController.gotMysteryBoxIndexs) do
        battleBaseController.snapShotInfo.gotMysteryBoxIndexs[tostring(k)] = v
    end
    battleBaseController.snapShotInfo.time = battleBaseController.time                                                  -- 未暂停的战斗时间

    -- 棋盘
    local board = battleBaseController:snapshotBoard()
    battleBaseController.snapShotInfo.boardSnapInfo = {}
    for posId, info in pairs(board) do
        battleBaseController.snapShotInfo.boardSnapInfo[tostring(posId)] = info
    end

    local gridEdge = battleBaseController:snapshotGridEdge()
    battleBaseController.snapShotInfo.gridEdge = gridEdge

    -- 血量
    if battleBaseController.battleData.atkTeam:getMaxHp() <= 0 then
        battleBaseController.snapShotInfo.hpPercent = 0 -- 容错
    else
        battleBaseController.snapShotInfo.hpPercent = battleBaseController.battleData.atkTeam:getHpPercent()
    end

    -- 技能
    battleBaseController.snapShotInfo.atkSkillMap = table.clearOrCreate(battleBaseController.snapShotInfo.atkSkillMap)
    for skillId, info in pairs(battleBaseController.battleData:getSelectSkillMap(SIDE_ATK)) do
        battleBaseController.snapShotInfo.atkSkillMap[tostring(skillId)] = info
    end

    battleBaseController.snapShotInfo.atkSkillEnergy = table.clearOrCreate(battleBaseController.snapShotInfo.atkSkillEnergy)
    for elementType, skillEntity in pairs(battleBaseController.battleData:getSkillEntities(SIDE_ATK)) do
        battleBaseController.snapShotInfo.atkSkillEnergy[tostring(elementType)] = skillEntity:getEnergy()
    end

    -- BattleBaseData
    battleBaseController.snapShotInfo.battledataShopInfo = battleBaseController.battleData:getSnapshoptInfo()

    -- buff
    battleBaseController.snapShotInfo.atkBuff = table.clearOrCreate(battleBaseController.snapShotInfo.atkBuff)
    local buffList = battleBaseController.atkTeam:getBuffList()
    for index, buffEffect in pairs(buffList) do
        local buffEntity = buffEffect.buff
        if buffEntity and buffEntity:getNeedSave() then
            local saveBuffEffect = {
                type = buffEntity:getName(),
                num = buffEntity:getEffectNum(),
                round = buffEffect.round or 1,
                ratio = 10000,
            }
            table.insert(battleBaseController.snapShotInfo.atkBuff, saveBuffEffect)
        end
    end

    -- 战斗数据
    battleBaseController.snapShotInfo.heroReport = {}
    local members = battleBaseController.battleData:getAtkTeam():getAllMembers()
    for k, v in pairs(members) do
        local matchTypeStr = tostring(v:getMatchType())
        battleBaseController.snapShotInfo.heroReport[matchTypeStr] = {
            skill_cast = v:getActiveSkillReleaseCount(),
            damage = v:getDamageCount(),
        }
    end

    -- 快照时间
    battleBaseController.snapShotInfo.snapShotTime = Time:getServerTime()
    battleBaseController.snapShotInfo.currentVersion = Platform:getClientVersion()

    LocalData:saveBattleSnapshot(battleBaseController.snapShotInfo)
end

function BattleSnapshotHelper:dealSnapshotBattleBaseInfo(battleBaseController, snapInfo)
    if not snapInfo then
        return
    end

    if not NEED_SAVE_SNAPSHOT_BATTLE_TYPE[snapInfo.battleType] then
        return
    end

    local atkFormation = snapInfo.params.atkFormation
    snapInfo.params.atkFormation = {}
    for matchTypeStr, heroId in ipairs(atkFormation) do
        local matchType = tonumber(matchTypeStr)
        local heroEntity = DataManager.HeroData:getHeroById(heroId)
        if matchType and heroEntity then
            snapInfo.params.atkFormation[matchType] = heroEntity
        end
    end

    battleBaseController.params = snapInfo.params
    battleBaseController.battleType = snapInfo.battleType or GConst.BattleConst.BATTLE_TYPE.STAGE
    battleBaseController.totalDurationTime = snapInfo.totalDurationTime
    battleBaseController.eliminateTotalCount = snapInfo.eliminateTotalCount
    battleBaseController.maxLinkCount = snapInfo.maxLinkCount
    battleBaseController.realTime = snapInfo.realTime
    battleBaseController.taskProgress = snapInfo.taskProgress
    if snapInfo.waveRoundCount then
        for waveIndexStr, round in pairs(snapInfo.waveRoundCount) do
            local waveIndex = tonumber(waveIndexStr)
            if waveIndex then
                battleBaseController.waveRoundCount[waveIndex] = round
            end
        end
    end
    if snapInfo.lastRoundBreakedGridType then
        for gridtypeStr, v in pairs(snapInfo.lastRoundBreakedGridType) do
            local gridtype = tonumber(gridtypeStr)
            if gridtype then
                battleBaseController.lastRoundBreakedGridType[gridtype] = v
            end
        end
    end

    battleBaseController.chapterId = snapInfo.chapterId
    battleBaseController:setWaveIndex(snapInfo.waveIndex)
    battleBaseController.maxWaveIndex = battleBaseController:getMaxWave()

    if snapInfo.gotMysteryBoxIndexs then
        for indexStr, v in pairs(snapInfo.gotMysteryBoxIndexs) do
            local index = tonumber(indexStr)
            if index then
                battleBaseController.gotMysteryBoxIndexs[index] = v
            end
        end
    end
end

function BattleSnapshotHelper:dealSnapshotBattleExtraInfo(battleBaseController, snapshot)
    if not snapshot then
        return
    end
    if not NEED_SAVE_SNAPSHOT_BATTLE_TYPE[snapshot.battleType] then
        return
    end

    local atkSelecetSkillMap = snapshot.atkSkillMap
    if atkSelecetSkillMap then
        local skillPool = battleBaseController.battleData:getSkillPool(SIDE_ATK)
        if skillPool then
            for elementType, list in pairs(skillPool) do -- 先遍历一下未解锁的技能
                if not battleBaseController.battleData:isUnlockedSkillElementType(elementType, SIDE_ATK) then
                    local skillEntity = battleBaseController.battleData:getSkillEntityByElement(elementType, SIDE_ATK)
                    if skillEntity then
                        local skillId = skillEntity:getUnlockId()
                        local skillIdStr = tostring(skillId)
                        if skillId and atkSelecetSkillMap[skillIdStr] then
                            atkSelecetSkillMap[skillIdStr] = nil
                            battleBaseController:dealSelectSkill(skillId, nil, SIDE_ATK, true)
                        end
                    end
                end
            end
        end

        for skillIdStr, info in pairs(atkSelecetSkillMap) do
            local skillId = tonumber(skillIdStr)
            if skillId then
                if info.value and info.value > 0 then
                    battleBaseController.battleData:setSkillCount(skillId, info.value, SIDE_ATK, info.count)
                    BATTLE_ROGUE_SKILL_HANDLE.takeEffect(skillId, battleBaseController.battleData, battleBaseController, info.value, SIDE_ATK)

                    local skillEntities = battleBaseController:getSkillEntities(SIDE_ATK)
                    for _, entity in pairs(skillEntities) do
                        entity:gotUpSKill(skillId)
                    end
                else
                    if info.count then
                        for i = 1, info.count do
                            battleBaseController:dealSelectSkill(skillId, info.value, SIDE_ATK, true)
                        end
                    end
                end
            end
        end
    end

    local atkSkillEnergy = snapshot.atkSkillEnergy
    if atkSkillEnergy then
        local skillMap = battleBaseController.battleData:getSkillEntities(SIDE_ATK)
        for matchTypeStr, count in pairs(atkSkillEnergy) do
            local matchType = tonumber(matchTypeStr)
            if matchType and skillMap[matchType] then
                skillMap[matchType]:addEnergy(count)
            end
        end
    end

    if battleBaseController.battleUI then
        battleBaseController.battleUI:refreshSkill(nil, nil, SIDE_ATK)
    end

    -- buff
    local atkBuff = snapshot.atkBuff
    if atkBuff then
        local atkMainUnit = battleBaseController.atkTeam:getMainUnit()
        for _, saveBuffEffect in ipairs(atkBuff) do
            local BattleBuffEntity = require "app/userdata/battle/skill/battle_buff_entity"
            local buffEntity = BattleBuffEntity:create()
            buffEntity:init(saveBuffEffect, atkMainUnit.unitEntity)
            buffEntity:setTargetSide(atkMainUnit)
            buffEntity:setNeedSave(true)

            atkMainUnit:takeEffect(buffEntity, atkMainUnit)
        end
    end

    if snapshot.hpPercent then
        local atkTeamEntity = battleBaseController.battleData.atkTeam
        local hp = atkTeamEntity:getHp() * snapshot.hpPercent
        hp = math.floor(hp + 0.00000000001)
        if hp < 1 then
            hp = 1
        end
        atkTeamEntity:setAttrValue(BattleConst.ATTR_NAME.HP, hp)
        if battleBaseController.battleUI then
            battleBaseController.battleUI:refreshAtkHp(atkTeamEntity:getHp(), atkTeamEntity:getHpPercent())
        end
    end

    if snapshot.heroReport then
        local members = battleBaseController.battleData:getAtkTeam():getAllMembers()
        for matchTypeStr, v in pairs(snapshot.heroReport) do
            local matchType = tonumber(matchTypeStr)
            if members[matchType] then
                members[matchType]:setDamageCount(v.damage)
                members[matchType]:setActiveSkillReleaseCount(v.skill_cast)
            end
        end
    end
end

return BattleSnapshotHelper