local BattleTeamEntity = require "app/userdata/battle/team/battle_team_entity"
local BattleSkillEntity = require "app/userdata/battle/skill/battle_skill_entity"
local ATTR_NAME = GConst.BattleConst.ATTR_NAME
local BattleBaseData = class("BattleBaseData", BaseData)

local SKILL_CFG = ConfigManager:getConfig("skill")
local BattleConst = GConst.BattleConst
local BATTLE_GRID_ENTITY = require "app/userdata/battle/battle_grid_entity"
local BATTLE_BOARD_SKILL_ENTITY = require "app/userdata/battle/skill/battle_board_skill_entity"
local BATTLE_GRID_EDGE_ENTITY = require "app/userdata/battle/grid_edge_entity"

local DEFAULT_FACTOR = BattleConst.DEFAULT_FACTOR
local TIME_SPEED_LEVEL_0 = 0
local TIME_SPEED_LEVEL_1 = 1
local TIME_SPEED_LEVEL_2 = 2
local TIME_SPEED_LEVEL_3 = 3
local TIME_SPEED_LEVEL_SKILL = 100
local SIDE_ATK = BattleConst.SIDE_ATK
local SIDE_DEF = BattleConst.SIDE_DEF

----------------------------------按需重写的方法-------------------------------
function BattleBaseData:getRowCount()
    return BattleConst.PVP_ROW_COUNT
end

function BattleBaseData:getTimeScaleBase()
    if self.customTimeScaleBase then
        return self.customTimeScaleBase
    end
    return 1
end

function BattleBaseData:setTimeScaleBase(timeScale, needResetTimeScale)
    self.customTimeScaleBase = timeScale
    if needResetTimeScale then
        self.timeScale = BattleConst.TIME_SCALE.LEVEL_1 * self.customTimeScaleBase
    end
end
---------------------------------end按需重写的方法-------------------------------

function BattleBaseData:init(params, snapInfo)
    self:clear()
    self.battleLv = snapInfo and snapInfo.battleLv or 1
    self.curBattleExp = snapInfo and snapInfo.curBattleExp or 0
    self.needBattleExp = self:getLvNeedExp()
    self.addLvCount = snapInfo and snapInfo.addLvCount or 0
    self.commonSelectSkillCount = snapInfo and snapInfo.commonSelectSkillCount or 0
    self.timeScale = BattleConst.TIME_SCALE.LEVEL_1 * self:getTimeScaleBase()
    self.lockElementMap = {}
	self.data.timeSpeed = 1
    self.data.lvDirty = false
    self.adRefreshSkillCount = snapInfo and snapInfo.adRefreshSkillCount or 0
    self.refreshSkillCount = snapInfo and snapInfo.refreshSkillCount or 0
    BattleSkillEntity.sid = 0
    self.atkTeam = self:initTeam(SIDE_ATK, params.atkFormation)
    self.defTeam = self:initTeam(SIDE_DEF, params.defFormation)
    self:initRogueSkills(SIDE_ATK, params.atkFormation)
    self:initRogueSkills(SIDE_DEF, params.defFormation)
    self.atkFormation = params.atkFormation or {}
    self.defFormation = params.defFormation or {}
    self:setMaxBattleLv(nil)

    if snapInfo then
        if snapInfo.cacheSkillList then
            self.cacheSkillList = snapInfo.cacheSkillList
            self.cacheSkillCount = #self.cacheSkillList
        end
    end
end

function BattleBaseData:getSnapshoptInfo()
    return {
        battleLv = self.battleLv,
        curBattleExp = self.curBattleExp,
        addLvCount = self.addLvCount,
        commonSelectSkillCount = self.commonSelectSkillCount,
        adRefreshSkillCount = self.adRefreshSkillCount,
        refreshSkillCount = self.refreshSkillCount,
        cacheSkillList = self.cacheSkillList,
    }
end

function BattleBaseData:getTimeScale()
	return self.timeScale
end

function BattleBaseData:pauseBattle()
	self.cacheSpeed = self.data.timeSpeed
    self.cacheTimeScale = self.timeScale
	self:setTimeSpeed(TIME_SPEED_LEVEL_0)
end

function BattleBaseData:resumeBattle()
	if self.cacheSpeed == nil then
		return
	end
	if self.data.timeSpeed ~= TIME_SPEED_LEVEL_0 then
		return
	end
	self:setTimeSpeed(self.cacheSpeed or TIME_SPEED_LEVEL_1, self.cacheTimeScale)
end

function BattleBaseData:resetTimeSpeed()
    if self.cacheSpeed then -- 目前处于暂停状态
        self.cacheSpeed = TIME_SPEED_LEVEL_1
        return
    end
    if self.data.timeSpeed <= TIME_SPEED_LEVEL_1 then
        return
    end
    self:setTimeSpeed(TIME_SPEED_LEVEL_1)
end

function BattleBaseData:addTimeSpeed()
    if self.data.timeSpeed >= TIME_SPEED_LEVEL_3 then
        return
    end
    if self.cacheSpeed then -- 目前处于暂停状态
        if self.cacheSpeed < TIME_SPEED_LEVEL_3 then
            self.cacheSpeed = self.cacheSpeed + 1
        end
        return
    end
    local timeSpeed = self.data.timeSpeed + 1
    self:setTimeSpeed(timeSpeed)
end

function BattleBaseData:setSkillTimeSpeed(timeScale)
    self:setTimeSpeed(TIME_SPEED_LEVEL_SKILL, timeScale)
end

function BattleBaseData:setTimeSpeed(timeSpeed, timeScale)
	if timeSpeed == self.data.timeSpeed then
		return
	end
	if timeSpeed == TIME_SPEED_LEVEL_0 then
		self.timeScale = 0
	elseif timeSpeed == TIME_SPEED_LEVEL_1 then
		self.timeScale = BattleConst.TIME_SCALE.LEVEL_1
	elseif timeSpeed == TIME_SPEED_LEVEL_2 then
		self.timeScale = BattleConst.TIME_SCALE.LEVEL_2
    elseif timeSpeed == TIME_SPEED_LEVEL_3 then
		self.timeScale = BattleConst.TIME_SCALE.LEVEL_3
	else
		self.timeScale = timeScale or BattleConst.TIME_SCALE.LEVEL_1
	end
    self.timeScale = self.timeScale * self:getTimeScaleBase()
	self.data.timeSpeed = timeSpeed
end

function BattleBaseData:initRogueSkills(side, formation)
    if not self.skillPool then
        self.skillPool = {}
        self.skillMap = {}
    end
    if not self.skillPool[side] then
        self.skillPool[side] = {}
    end
    if not self.skillMap[side] then
        self.skillMap[side] = {}
    end

    if not formation then
        return
    end
    local skillmap = {}
    for matchType, heroEntity in pairs(formation) do
        local skillId = heroEntity:getBaseSkill()
        local cfg = SKILL_CFG[skillId]
        self.skillMap[side][cfg.position] = BATTLE_BOARD_SKILL_ENTITY:create(skillId, side)
        self.skillMap[side][cfg.position]:addUpSkills(heroEntity:getRogueSkillList())
        self.skillMap[side][cfg.position]:setUnlockId(heroEntity:getUnlockRogueId())
        for _, id in ipairs(heroEntity:getActiveRogueSkills()) do
            if not skillmap[id] then
                if not self.skillPool[side][cfg.position] then
                    self.skillPool[side][cfg.position] = {}
                end
                table.insert(self.skillPool[side][cfg.position], id)
                skillmap[id] = true
            end
        end
    end
end

function BattleBaseData:refreshBoard(board, boardEdge, blockIcon, snapshot)
    local r = 1
    local c = 1

    for i, info in ipairs(board) do
        if c > BattleConst.COLUMN_COUNT then
            c = c - BattleConst.COLUMN_COUNT
            r = r + 1
        end

        local posId = ModuleManager.BattleManager:getPosId(r, c)
        local data = {
            posId = posId,
            gridType = info[1] or BattleConst.GRID_TYPE.EMPTY,
            elementType = info[2] or BattleConst.ELEMENT_TYPE.RED
        }
        if not self.gridEntities then
            self.gridEntities = {}
        end
        if self.gridEntities[data.posId] then
            self.gridEntities[data.posId]:clear()
            self.gridEntities[data.posId]:setGridType(data.gridType)
            self.gridEntities[data.posId]:setElementType(data.elementType)
        else
            self.gridEntities[data.posId] = self:getNewGridEntity(data.posId, data.gridType, data.elementType)
        end
        self.gridEntities[data.posId]:determineIdleStatus()
        self.gridEntities[data.posId]:setObstacleIcon(blockIcon)
        c = c + 1
    end

    if not self.gridEdgeEntities then
        self.gridEdgeEntities = {}
    else
        for posId, info in pairs(self.gridEdgeEntities) do
            for direction, entity in pairs(info) do
                entity:setIsIdle(true)
            end
        end
    end
    if snapshot and snapshot.gridEdge then
        boardEdge = snapshot.gridEdge
    end

    if boardEdge then
        for _, info in pairs(boardEdge) do
            local initInfo = {
                posId = info.pos,
                edgeType = info.type,
                direction = info.direction,
                battleData = self
            }
            if not self.gridEdgeEntities[initInfo.posId] then
                self.gridEdgeEntities[initInfo.posId] = {}
            end
            if self.gridEdgeEntities[initInfo.posId][initInfo.direction] then
                self.gridEdgeEntities[initInfo.posId][initInfo.direction]:ctor(initInfo)
            else
                self.gridEdgeEntities[initInfo.posId][initInfo.direction] = self:getNewGridEdgeEntity(initInfo)
            end
        end
    end

    if snapshot and snapshot.boardSnapInfo then
        for posIdStr, snap in pairs(snapshot.boardSnapInfo) do
            local posId = tonumber(posIdStr)
            if self.gridEntities[posId] and snap then
                self.gridEntities[posId]:setInfoBySnapshop(snap)
            end
        end
    end
end

function BattleBaseData:getNewGridEntity(posId, gridType, elementType)
    local data = {
        posId = posId or 0,
        gridType = gridType or BattleConst.GRID_TYPE.EMPTY,
        elementType = elementType or BattleConst.ELEMENT_TYPE.RED,
        battleData = self
    }
    return BATTLE_GRID_ENTITY:create(data)
end

function BattleBaseData:getNewGridEdgeEntity(data)
    return BATTLE_GRID_EDGE_ENTITY:create(data)
end

function BattleBaseData:clear()
    self:clearGridSequence()
    self:clearCacheBoardSkill()

    self.gridEntities = {}
    self.gridEdgeEntities = {}
    self.skillMap = {}
    self.skillPool = {}
    self.selectSkillMap = {}
end

function BattleBaseData:getElementTypeMap()
    local elementTypeMap = {}
    if self.gridEntities then
        for posId, entity in pairs(self.gridEntities) do
            if entity:canLink() then
                local elementType = entity:getElementType()
                elementTypeMap[elementType] = (elementTypeMap[elementType] or 0) + 1
            end
        end
    end
    return elementTypeMap
end

function BattleBaseData:getGridSequence()
    return self.gridSequence
end

function BattleBaseData:alreadyInsertSequence(posId)
    return self.gridSequenceMap[posId] == true
end

function BattleBaseData:getIsVirtual()
    return self.isVirtual
end

function BattleBaseData:getSequenceHadSkill()
    for _, info in ipairs(self:getGridSequence()) do
        local entity = self.gridEntities[info.posId]
        if entity and entity:getSkillId() then
            return entity:getSkillId(), entity:getPosId()
        end
    end
    return
end

function BattleBaseData:insertGridSequence(posId, snapshot, isVirtual)
    if self:alreadyInsertSequence(posId) then
        return false
    end

    self.gridSequenceMap[posId] = true
    self.isVirtual = isVirtual
    table.insert(self.gridSequence, {posId = posId, snapshot = snapshot})
    return true
end

function BattleBaseData:removeGridSequence(posId)
    if not self:alreadyInsertSequence(posId) then
        return
    end

    local count = #self.gridSequence
    local lastPosId = self.gridSequence[count].posId
    local snapshot = self.gridSequence[count].snapshot
    if lastPosId ~= posId then
        return
    end

    table.remove(self.gridSequence, count)
    self.gridSequenceMap[lastPosId] = false
    return snapshot
end

function BattleBaseData:removeGridSequenceByIndex(index)
    local count = #self.gridSequence
    if count < index then
        return
    end

    local snapshot
    for i = count, index, -1 do
        local info = table.remove(self.gridSequence, i)
        self.gridSequenceMap[info.posId] = false
        snapshot = info.snapshot
    end

    return snapshot
end

function BattleBaseData:getFirstSequenceSnapshot()
    if not self.gridSequence[1] then
        return
    end

    local snapshot = self.gridSequence[1].snapshot
    return snapshot
end

function BattleBaseData:cacheSkillInfluenceGrids(grids)
    if not self.skillInfluenceGrids then
        self.skillInfluenceGrids = {}
    end
    for posId, info in pairs(grids) do
        self.skillInfluenceGrids[posId] = info
    end
end

function BattleBaseData:getSkillInfluenceGrids()
    return self.skillInfluenceGrids or {}
end

function BattleBaseData:clearSkillInfluenceGrids()
    local grids = self:getSkillInfluenceGrids()
    self.skillInfluenceGrids = {} -- 技能影响的格子
    return grids
end

function BattleBaseData:clearGridSequence()
    self.gridSequence = {} -- 格子队列
    self.gridSequenceMap = {} -- 格子队列对应的map，方面查找
    self.isVirtual = nil
    self:clearSkillInfluenceGrids()
end

function BattleBaseData:getGridEnties()
    return self.gridEntities or {}
end

function BattleBaseData:getGridEntity(posId)
    return self.gridEntities[posId]
end

function BattleBaseData:exchangeGridEntities(posId1, posId2)
    local e1 = self.gridEntities[posId1]
    local e2 = self.gridEntities[posId2]
    e1:setPosId(posId2)
    e2:setPosId(posId1)
    e2:setIsIdle(false)
    self.gridEntities[posId1] = e2
    self.gridEntities[posId2] = e1
end

function BattleBaseData:setGridEntitiesPosId(changeInfo)
    local map = {}
    for posId, targetPosId in pairs(changeInfo) do
        local entity = self.gridEntities[posId]
        entity:setPosId(targetPosId)
        map[targetPosId] = entity
    end

    for posId, entity in pairs(map)  do
        self.gridEntities[posId] = entity
    end
end

function BattleBaseData:setGridInfo(posId, gridInfo)
    local entity = self.gridEntities[posId]
    if not entity then
        return
    end

    if gridInfo.gridType then
        entity:setGridType(gridInfo.gridType)
    end

    if gridInfo.elementType then
        entity:setElementType(gridInfo.elementType)
    end

    entity:setSkilId() -- 清除skillId
    entity:determineIdleStatus()
end

function BattleBaseData:setInfoBySnapshop(posId, snapInfo)
    local entity = self.gridEntities[posId]
    if not entity then
        return
    end
    entity:setInfoBySnapshop(snapInfo)
end

function BattleBaseData:setGridType(posId, gridType, noDirty)
    local entity = self.gridEntities[posId]
    if not entity then
        return
    end
    entity:setGridType(gridType, noDirty)
    entity:determineIdleStatus()
end

function BattleBaseData:setGridDirty(posId)
    local entity = self.gridEntities[posId]
    if not entity then
        return
    end
    entity:setDirty()
end

function BattleBaseData:lockAllSkillGrid(lock, side)
    side = side or SIDE_ATK
    if not self.gridEntities then
        return
    end

    for posId, entity in pairs(self.gridEntities) do
        if entity:getSkillId() and (not entity:getSkillSide() or entity:getSkillSide() == side) then
            local gridType = GConst.BattleConst.GRID_TYPE.EMPTY
            if lock then
                gridType = GConst.BattleConst.GRID_TYPE.LOCK
            end
            self:setGridType(posId, gridType)
        end
    end
end

function BattleBaseData:getSkillEntities(side)
    side = side or SIDE_ATK
    if self.skillMap then
        return self.skillMap[side] or {}
    end
end

function BattleBaseData:getSkillEntityByElement(elementType, side)
    local skillMap = self:getSkillEntities(side)
    if not skillMap then
        return
    end
    return skillMap[elementType]
end

function BattleBaseData:getSkillEntityBySkillId(skillId, side)
    local skillMap = self:getSkillEntities(side)
    if not skillMap or not skillId then
        return
    end
    local cfg = SKILL_CFG[skillId]
    if not cfg then
        return
    end
    return skillMap[cfg.position]
end

function BattleBaseData:unlockSkillEntity(elementType, side)
    local skillMap = self:getSkillEntities(side)
    if skillMap and skillMap[elementType] then
        skillMap[elementType]:setUnlock()
    end
end

function BattleBaseData:isUnlockedSkillElementType(elementType, side)
    local skillMap = self:getSkillEntities(side)
    if not skillMap or not skillMap[elementType] then
        return false
    end
    return skillMap[elementType]:getUnlocked()
end

function BattleBaseData:addSkillEnergy(elementMap, side)
    local skillMap = self:getSkillEntities(side)
    if not skillMap then
        return
    end

    for elementType, entity in pairs(skillMap) do
        if entity:getUnlocked() then
            entity:addEnergy(elementMap[elementType] or 0)
        end
    end
end

function BattleBaseData:addSkillCount(skillId, value, side)
    side = side or SIDE_ATK
    if not self.selectSkillMap then
        self.selectSkillMap = {}
    end
    if not self.selectSkillMap[side] then
        self.selectSkillMap[side] = {}
    end
    if not self.selectSkillMap[side][skillId] then
        self.selectSkillMap[side][skillId] = {
            count = 0,
            value = 0
        }
    end
    self.selectSkillMap[side][skillId].count = self.selectSkillMap[side][skillId].count + 1
    if value then
        self.selectSkillMap[side][skillId].value = (self.selectSkillMap[side][skillId].value) + value
    end
end

function BattleBaseData:setSkillCount(skillId, value, side, count)
    side = side or SIDE_ATK
    if not self.selectSkillMap then
        self.selectSkillMap = {}
    end
    if not self.selectSkillMap[side] then
        self.selectSkillMap[side] = {}
    end
    if not self.selectSkillMap[side][skillId] then
        self.selectSkillMap[side][skillId] = {
            count = 0,
            value = 0
        }
    end
    self.selectSkillMap[side][skillId].count = count
    if value then
        self.selectSkillMap[side][skillId].value = value
    end
end

function BattleBaseData:getSkillCount(skillId, side)
    side = side or SIDE_ATK
    if self.selectSkillMap[side] and self.selectSkillMap[side][skillId] then
        return self.selectSkillMap[side][skillId].count
    end
    return 0
end

function BattleBaseData:getSelectSkillMap(side)
    side = side or SIDE_ATK
    return self.selectSkillMap and self.selectSkillMap[side] or {}
end

function BattleBaseData:getSkillPool(side)
    side = side or SIDE_ATK
    return self.skillPool and self.skillPool[side] or {}
end

function BattleBaseData:changeSkillId(elementType, newId, side)
    if not newId then
        return
    end

    local entity = self:getSkillEntityByElement(elementType, side)
    if entity then
        entity:refreshSkillId(newId)
    end
end

function BattleBaseData:cacheLockElement(elementType, status)
    self.lockElementMap[elementType] = status
end

function BattleBaseData:getCacheLockedElement(elementType)
    return self.lockElementMap[elementType]
end

function BattleBaseData:clearAllCacheLockElement()
    self.lockElementMap = table.clearOrCreate(self.lockElementMap)
end

function BattleBaseData:cacheBoardSkill()
    self.cacheSkillList = {}
    self.cacheSkillCount = 0
    local list
    local count = 0
    for posId, entity in pairs(self:getGridEnties()) do
        if entity:getSkillId() then
            if not list then
                list = {}
            end
            table.insert(list, {skillId = entity:getSkillId(), posId = posId})
            count = count + 1
        end
    end

    if list then
        if count > BattleConst.MAX_CACHE_SKILL_COUNT then
            count = BattleConst.MAX_CACHE_SKILL_COUNT
        end

        for i = 1, count do
            if not list[1] then
                break
            end
            local info = table.remove(list, math.random(1, #list))
            table.insert(self.cacheSkillList, info)
            self.cacheSkillCount = self.cacheSkillCount + 1
        end
    end
end

function BattleBaseData:getCacheBoardSkill()
    if not self.cacheSkillList then
        return self.cacheSkillList, 0
    end
    return self.cacheSkillList, self.cacheSkillCount
end

function BattleBaseData:clearCacheBoardSkill()
    self.cacheSkillList = {}
    self.cacheSkillCount = 0
end

function BattleBaseData:getBattleLv()
    return self.battleLv
end

function BattleBaseData:getBattleExp()
    return self.curBattleExp
end

function BattleBaseData:getBattleNeedExp()
    return self.needBattleExp
end

function BattleBaseData:getLvNeedExp(lv)
    lv = lv or self.battleLv
    local cfg = ConfigManager:getConfig("battle_exp")
    if not cfg[lv] then
        return cfg[ConfigManager:getConfigNum("battle_exp")].exp
    end
    return cfg[lv].exp
end

function BattleBaseData:setMaxBattleLv(maxLv)
    self.maxBattleLv = maxLv 
end

function BattleBaseData:addExp(exp)
    self.curBattleExp = self.curBattleExp + exp
    while self.curBattleExp >= self.needBattleExp do
        if self.maxBattleLv then -- 超过最大等级后跳出
            if self.maxBattleLv <= self.battleLv then
                break
            end
        end

        self.curBattleExp = self.curBattleExp - self.needBattleExp
        self.addLvCount = self.addLvCount + 1
        self.battleLv = self.battleLv + 1
        self.needBattleExp = self:getLvNeedExp()
    end
    self.data.lvDirty = not self.data.lvDirty
end

function BattleBaseData:useAddlvCount()
    if self.addLvCount <= 0 then
        self.addLvCount = 0
        return false
    end
    self.addLvCount = self.addLvCount - 1
    return true
end

function BattleBaseData:addBattleLvCount(count)
    self.addLvCount = self.addLvCount + count
    self.battleLv = self.battleLv + count
    self.data.lvDirty = not self.data.lvDirty
end

function BattleBaseData:addCommonSelectSkillCount(count)
    self.commonSelectSkillCount = self.commonSelectSkillCount + (count or 1)
end

function BattleBaseData:useCommonSelectSkillCount()
    if self.commonSelectSkillCount <= 0 then
        self.commonSelectSkillCount = 0
        return false
    end
    self.commonSelectSkillCount = self.commonSelectSkillCount - 1
    return true
end

function BattleBaseData:addRefreshSkillCount(isAd)
    if isAd then
        self.adRefreshSkillCount = self.adRefreshSkillCount + 1
    end
    self.refreshSkillCount = self.refreshSkillCount + 1
end

function BattleBaseData:getRefreshSkillCount()
    return self.refreshSkillCount
end

function BattleBaseData:getADRefreshSkillCount()
    return self.adRefreshSkillCount
end

function BattleBaseData:initTeam(side, formation)
    local data = nil
    data = self:initHeroData(formation)
    local team = BattleTeamEntity:create()
    team:init(side, data)
    return team
end

function BattleBaseData:getTeamBySide(side)
    if side == SIDE_ATK then
        return self.atkTeam
    else
        return self.defTeam
    end
end

function BattleBaseData:getAtkTeam()
    return self.atkTeam
end

function BattleBaseData:getDefTeam()
    return self.defTeam
end

function BattleBaseData:getHeroEntity(elementType, side)
    if side == SIDE_DEF then
        return self.defFormation[elementType]
    else
        return self.atkFormation[elementType]
    end
end

function BattleBaseData:initHeroData(formation)
    local units = {}
    if formation then
        local skillCfg = ConfigManager:getConfig("skill")
        for matchType, heroEntity in pairs(formation) do
            heroEntity:getAllAttr()
            local skillId = heroEntity:getBaseSkill()
            local hp = heroEntity:getHp() // DEFAULT_FACTOR
            local unitData = {
                id = heroEntity:getCfgId(),
                modelId = heroEntity:getModelId(),
                matchType = matchType,
                normalSkills = heroEntity:getHurtSkill(),
                -- assistingSkill = heroEntity:getAssistingSkill(),
                body = 2,       -- 英雄默认是中体型
                skin = heroEntity:getSkinId(),
                attr = {
                    hp = hp,
                    max_hp = hp,
                }
            }

            ---- 攻击力
            for matchType, attrName in pairs(GConst.MATCH_ATTACK_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName)
                local atkAddName = GConst.MATCH_ATTACK_ADD_NAME[matchType]
                if atkAddName then
                    unitData.attr[attrName] = unitData.attr[attrName] + heroEntity:getTotalAttrValue(atkAddName)
                end

                unitData.attr[attrName] = unitData.attr[attrName] // DEFAULT_FACTOR
            end

            ---- 暴击率
            for matchType, attrName in pairs(GConst.MATCH_CRIT_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName)
            end

            ---- 暴击伤害
            for matchType, attrName in pairs(GConst.MATCH_CRIT_TIME_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName)
            end

            ---- 治疗效果
            for matchType, attrName in pairs(GConst.MATCH_CURED_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName)
            end

            ---- 普攻增伤固定值
            for matchType, attrName in pairs(GConst.MATCH_NORMAL_HURT_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName) // DEFAULT_FACTOR
            end

            ---- 普攻增伤百分比
            for matchType, attrName in pairs(GConst.MATCH_NORMAL_HURTP_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName)
            end

            ---- 技能增伤固定值
            for matchType, attrName in pairs(GConst.MATCH_SKILL_HURT_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName) // DEFAULT_FACTOR
            end

            ---- 技能增伤百分比
            for matchType, attrName in pairs(GConst.MATCH_SKILL_HURTP_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName)
            end

            ---- 普攻\技能增伤百分比
            for matchType, attrName in pairs(GConst.MATCH_ALL_HURTP_NAME) do
                unitData.attr[attrName] = heroEntity:getTotalAttrValue(attrName)
            end

            local skillInfo = skillCfg[skillId]
            if skillInfo then
                if skillInfo.effect_type == 1 then -- 主动
                    unitData.activeSkills = {skillId}
                elseif skillInfo.effect_type == 2 then -- 被动
                    unitData.passiveSkills = {skillId}
                end
            end
            table.insert(units, unitData)
        end
    end
	local data = {
		units = units
	}
	return data
end

function BattleBaseData:addMonster(monsterId, newTeam, battleController)
    local monsterInfo = ConfigManager:getConfig("monster")[monsterId]
    local hp = monsterInfo.hp // DEFAULT_FACTOR
    local atk = monsterInfo.atk // DEFAULT_FACTOR
    if battleController then
        hp = hp * (DEFAULT_FACTOR + battleController:getMonsterHpAddition()) // DEFAULT_FACTOR
        atk = atk * (DEFAULT_FACTOR + battleController:getMonsterAtkAddition()) // DEFAULT_FACTOR
        local atkFixed = battleController:getMonsterAtkFixed()
        local hpFixed = battleController:getMonsterHpFixed()
        if atkFixed > 0 then
            atk = atkFixed // DEFAULT_FACTOR
        end
        if hpFixed > 0 then
            hp = hpFixed // DEFAULT_FACTOR
        end
    end
    local unitData = {
        id = monsterId,
        modelId = monsterInfo.model_id,
        matchType = 0,
        normalSkills = monsterInfo.hurt_skill,
        normalSkillCount = monsterInfo.atk_times or 0,
        activeSkills = monsterInfo.skill,
        passiveSkills = monsterInfo.passive_skill,
        assistingSkill = nil,
        isBoss = monsterInfo.is_boss,
        exp = monsterInfo.monster_exp or 0,
        body = monsterInfo.body,
        hpSkinHp = monsterInfo.monster_hp,
        hpSkinSkin = monsterInfo.monster_hp_skin,
        hpExp = monsterInfo.monster_hp_exp,
        attr = {
            hp = hp,
            max_hp = hp,
            atk = atk,
            atk_red = 0,
            atk_yellow = 0,
            atk_green = 0,
            atk_blue = 0,
            atk_purple = 0,
        }
    }
    if newTeam then
        self.defTeam:init(BattleConst.SIDE_DEF)
    end
    return self.defTeam:addUnit(unitData)
end

function BattleBaseData:getNormalAttackName(index)
    if self.normalAttackName == nil then
        self.normalAttackName = {}
    end
    local name = self.normalAttackName[index]
    if name == nil then
        name = string.format("attack%02d", index)
        self.normalAttackName[index] = name
    end
    return name
end

function BattleBaseData:getGridEdgeEntities()
    return self.gridEdgeEntities
end

function BattleBaseData:getGridEdgeEntity(posId, direction)
    if not self.gridEdgeEntities then
        return
    end
    if not self.gridEdgeEntities[posId] then
        return
    end
    return self.gridEdgeEntities[posId][direction]
end

function BattleBaseData:breakGridEdge(posId, direction)
    if not self.breakGridEdgeTag then
        self.breakGridEdgeTag = {}
    end
    if not self.breakGridEdgeTag[posId] then
        self.breakGridEdgeTag[posId] = {}
    end
    if self.breakGridEdgeTag[posId][direction] then -- 已经标记过了
        return
    end
    self.breakGridEdgeTag[posId][direction] = true

    if not self.gridEdgeEntities[posId] then
        return
    end
    if not self.gridEdgeEntities[posId][direction] then
        return
    end

    self.breakGridEdgeTagCount = (self.breakGridEdgeTagCount or 0) + 1
    local breakSfx = self.gridEdgeEntities[posId][direction]:getBreakSfx()
    self.gridEdgeEntities[posId][direction]:tryBreak()
    return true, breakSfx, self.breakGridEdgeTagCount, self.gridEdgeEntities[posId][direction]:getCell()
end

function BattleBaseData:getBreakGridEdgeTagCount()
    return self.breakGridEdgeTagCount
end

function BattleBaseData:clearBreakGridEdgeTag()
    self.breakGridEdgeTagCount = 0
    if not self.breakGridEdgeTag then
        return
    end
    for posId, info in pairs(self.breakGridEdgeTag) do
        self.breakGridEdgeTag[posId] = table.clearOrCreate(self.breakGridEdgeTag[posId])
    end
end

return BattleBaseData