local HeroEntity = class("HeroEntity", BaseData)
local ATTR_NAME = GConst.BattleConst.ATTR_NAME

function HeroEntity:ctor(cfgId, lv, skin)
	self.cfgId = cfgId
	self.data.isDirty = false
	self.data.lv = lv
	self.data.skin = skin
	self.config = ConfigManager:getConfig("hero")[self.cfgId]
	self.beginLv = self.config.begin_lv -- 初始等级

	self.baseAttrOriginal = {}
	self.equipAttr = {}
	self.skinAttr = {}
	self.runesAttr = {}
	self.allAttr = {}
end

function HeroEntity:initAttr()
	self:setTotalAttrValue(ATTR_NAME.HP, 0)
	self:setTotalAttrValue(ATTR_NAME.ATK, 0)
	self:setTotalAttrValue(ATTR_NAME.ATK_RED, 0)
	self:setTotalAttrValue(ATTR_NAME.ATK_YELLOW, 0)
	self:setTotalAttrValue(ATTR_NAME.ATK_GREEN, 0)
	self:setTotalAttrValue(ATTR_NAME.ATK_BLUE, 0)
	self:setTotalAttrValue(ATTR_NAME.ATK_PURPLE, 0)
	self:setEquipAttrValue(GConst.MATCH_HP_NAME[self:getMatchType()], 0)
	self:setEquipAttrValue(GConst.MATCH_ATTACK_NAME[self:getMatchType()], 0)
	self:setEquipAttrValue(GConst.MATCH_NORMAL_HURT_NAME[self:getMatchType()], 0)
	self:setEquipAttrValue(GConst.MATCH_SKILL_HURT_NAME[self:getMatchType()], 0)
	self:setEquipAttrValue(GConst.MATCH_CRIT_NAME[self:getMatchType()], 0)
	self:setEquipAttrValue(GConst.MATCH_CRIT_TIME_NAME[self:getMatchType()], 0)
	self:setEquipAttrValue(GConst.MATCH_NORMAL_HURTP_NAME[self:getMatchType()], 0)
	self:setEquipAttrValue(GConst.MATCH_SKILL_HURTP_NAME[self:getMatchType()], 0)
	self:setEquipAttrValue(GConst.MATCH_CURED_NAME[self:getMatchType()], 0)

	self:updateAllAttr()
end

function HeroEntity:onBaseAttrChange()
	self:updateBaseAttr()
	self:updateTotalAttr()
	self:setDirty()
end

function HeroEntity:onEquipAttrChange()
	self:updateEquipAttr()
	self:updateTotalAttr()
	self:setDirty()
end

function HeroEntity:onSkinAttrChange()
	self:updateSkinAttr()
	self:updateTotalAttr()
	self:setDirty()
end

function HeroEntity:onRunesAttrChange()
	self:updateRunesAttr()
	self:updateTotalAttr()
	self:setDirty()
end

function HeroEntity:setDirty()
	self.data.isDirty = not self.data.isDirty
end

function HeroEntity:getAllAttr()
	return self.allAttr
end

-- 更新所有属性
function HeroEntity:updateAllAttr()
	self:updateBaseAttr()
	self:updateEquipAttr()
	self:updateSkinAttr()
	self:updateRunesAttr()
	self:updateTotalAttr()
end

-- 更新英雄基础属性
function HeroEntity:updateBaseAttr()
	self.baseAttrOriginal[ATTR_NAME.HP] = self:getCfgHp()
	self.baseAttrOriginal[ATTR_NAME.ATK_RED] = 0
	self.baseAttrOriginal[ATTR_NAME.ATK_YELLOW] = 0
	self.baseAttrOriginal[ATTR_NAME.ATK_GREEN] = 0
	self.baseAttrOriginal[ATTR_NAME.ATK_BLUE] = 0
	self.baseAttrOriginal[ATTR_NAME.ATK_PURPLE] = 0
	self.baseAttrOriginal[GConst.MATCH_ATTACK_NAME[self.config.position]] = self:getCfgAtk()
end

-- 更新装备属性
function HeroEntity:updateEquipAttr()
	self.equipAttr = {}

	local hp,atk,normalHurt,skillHurt,critPer,critHurtPer,normalHurtPer,skillHurtPer,healPer = 0

	local addArmorAttrPer = true
	for partName, partType in pairs(GConst.EquipConst.PART_TYPE) do
		local equipEntity = self:getEquips(partType)
		if equipEntity then
			-- 基础值
			hp = equipEntity:getHp()
			atk = equipEntity:getAttack()
			normalHurt = equipEntity:getNormalHurt()
			skillHurt = equipEntity:getSkillHurt()
			-- 属性值
			critPer = 0
			critHurtPer = 0
			normalHurtPer = 0
			skillHurtPer = 0
			healPer = 0
			if partType == GConst.EquipConst.PART_TYPE.WEAPON or addArmorAttrPer then
				if partType ~= GConst.EquipConst.PART_TYPE.WEAPON then
					addArmorAttrPer = false-- 防具的属性只只用计算一次
				end

				critPer = equipEntity:getCritPercent()
				critHurtPer = equipEntity:getCritHurtPercent()
				normalHurtPer = equipEntity:getNormalHurtPercent()
				skillHurtPer = equipEntity:getSkillHurtPercent()
				healPer = equipEntity:getHealPercent()
			end
	
			self:addEquipAttrValue(GConst.MATCH_HP_NAME[self:getMatchType()], hp)
			self:addEquipAttrValue(GConst.MATCH_ATTACK_NAME[self:getMatchType()], atk)
			self:addEquipAttrValue(GConst.MATCH_NORMAL_HURT_NAME[self:getMatchType()], normalHurt)
			self:addEquipAttrValue(GConst.MATCH_SKILL_HURT_NAME[self:getMatchType()], skillHurt)
			self:addEquipAttrValue(GConst.MATCH_CRIT_NAME[self:getMatchType()], critPer)
			self:addEquipAttrValue(GConst.MATCH_CRIT_TIME_NAME[self:getMatchType()], critHurtPer)
			self:addEquipAttrValue(GConst.MATCH_NORMAL_HURTP_NAME[self:getMatchType()], normalHurtPer)
			self:addEquipAttrValue(GConst.MATCH_SKILL_HURTP_NAME[self:getMatchType()], skillHurtPer)
			self:addEquipAttrValue(GConst.MATCH_CURED_NAME[self:getMatchType()], healPer)
	
			-- if EDITOR_MODE then
			-- 	local printStr = ""
			-- 	printStr = printStr .. "更新装备数值："..self:getCfgId().."-".. partName .. "-" .. equipEntity:getLevel() .. "\n"
			-- 	printStr = printStr .. "生命：".. hp .. "\n"
			-- 	printStr = printStr .. "攻击力：".. atk .. "\n"
			-- 	printStr = printStr .. "普攻增伤：".. normalHurt .. "\n"
			-- 	printStr = printStr .. "技能增伤：".. skillHurt .. "\n"
			-- 	printStr = printStr .. "暴击率：".. critPer .. "\n"
			-- 	printStr = printStr .. "暴击伤害百分比：".. critHurtPer .. "\n"
			-- 	printStr = printStr .. "普攻增伤百分比：".. normalHurtPer .. "\n"
			-- 	printStr = printStr .. "技能增伤百分比：".. skillHurtPer .. "\n"
			-- 	printStr = printStr .. "治疗加成百分比：".. healPer .. "\n"
			-- 	Logger.logHighlight(printStr)
			-- end
		end
	end
end

function HeroEntity:setEquipAttrValue(name, value)
	self.equipAttr[name] = value
end

function HeroEntity:addEquipAttrValue(name, value)
	if self.equipAttr[name] == nil then
		self.equipAttr[name] = 0
	end
	self.equipAttr[name] = self.equipAttr[name] + value
end

-- 更新皮肤属性
function HeroEntity:updateSkinAttr()
	self.skinAttr = {}

	local hp = DataManager.SkinData:getHp(self)
	local atk = DataManager.SkinData:getAttack(self)
	local normalHurt = DataManager.SkinData:getNormalHurt(self)
	local skillHurt = DataManager.SkinData:getSkillHurt(self)
	local critPer = DataManager.SkinData:getCritPercent(self)
	local critHurtPer = DataManager.SkinData:getCritHurtPercent(self)
	local normalHurtPer = DataManager.SkinData:getNormalHurtPercent(self)
	local skillHurtPer = DataManager.SkinData:getSkillHurtPercent(self)
	local healPer = DataManager.SkinData:getHealPercent(self)

	self.skinAttr[GConst.MATCH_HP_NAME[self:getMatchType()]] = hp
	self.skinAttr[GConst.MATCH_ATTACK_NAME[self:getMatchType()]] = atk
	self.skinAttr[GConst.MATCH_NORMAL_HURT_NAME[self:getMatchType()]] = normalHurt
	self.skinAttr[GConst.MATCH_SKILL_HURT_NAME[self:getMatchType()]] = skillHurt
	self.skinAttr[GConst.MATCH_CRIT_NAME[self:getMatchType()]] = critPer
	self.skinAttr[GConst.MATCH_CRIT_TIME_NAME[self:getMatchType()]] = critHurtPer
	self.skinAttr[GConst.MATCH_NORMAL_HURTP_NAME[self:getMatchType()]] = normalHurtPer
	self.skinAttr[GConst.MATCH_SKILL_HURTP_NAME[self:getMatchType()]] = skillHurtPer
	self.skinAttr[GConst.MATCH_CURED_NAME[self:getMatchType()]] = healPer

	-- if EDITOR_MODE then
	-- 	local printStr = ""
	-- 	printStr = printStr .. "更新皮肤数值："..self:getCfgId() .. "\n"
	-- 	printStr = printStr .. "生命：".. hp .. "\n"
	-- 	printStr = printStr .. "攻击力：".. atk .. "\n"
	-- 	printStr = printStr .. "普攻增伤：".. normalHurt .. "\n"
	-- 	printStr = printStr .. "技能增伤：".. skillHurt .. "\n"
	-- 	printStr = printStr .. "暴击率：".. critPer .. "\n"
	-- 	printStr = printStr .. "暴击伤害百分比：".. critHurtPer .. "\n"
	-- 	printStr = printStr .. "普攻增伤百分比：".. normalHurtPer .. "\n"
	-- 	printStr = printStr .. "技能增伤百分比：".. skillHurtPer .. "\n"
	-- 	printStr = printStr .. "治疗加成百分比：".. healPer .. "\n"
	-- 	Logger.logHighlight(printStr)
	-- end
end

-- 更新符文属性
function HeroEntity:updateRunesAttr()
	self.runesAttr = {}

	local runesEntity = self:getRunes()
	if runesEntity == nil then
		return
	end

	local hp = runesEntity:getAttrValue(GConst.MATCH_HP_FIX_NAME[self:getMatchType()])
	local atk = runesEntity:getAttrValue(GConst.MATCH_ATTACK_NAME[self:getMatchType()])
	local normalHurt = runesEntity:getAttrValue(GConst.MATCH_NORMAL_HURT_NAME[self:getMatchType()])
	local skillHurt = runesEntity:getAttrValue(GConst.MATCH_SKILL_HURT_NAME[self:getMatchType()])
	local critPer = runesEntity:getAttrValue(GConst.MATCH_CRIT_NAME[self:getMatchType()])
	local critHurtPer = runesEntity:getAttrValue(GConst.MATCH_CRIT_TIME_NAME[self:getMatchType()])
	local normalHurtPer = runesEntity:getAttrValue(GConst.MATCH_NORMAL_HURTP_NAME[self:getMatchType()], true)
	local skillHurtPer = runesEntity:getAttrValue(GConst.MATCH_SKILL_HURTP_NAME[self:getMatchType()], true)
	local healPer = runesEntity:getAttrValue(GConst.MATCH_CURED_NAME[self:getMatchType()])
	local allHurtp = runesEntity:getAttrValue(GConst.MATCH_ALL_HURTP_NAME[self:getMatchType()])

	self.runesAttr[GConst.MATCH_HP_NAME[self:getMatchType()]] = hp
	self.runesAttr[GConst.MATCH_ATTACK_NAME[self:getMatchType()]] = atk
	self.runesAttr[GConst.MATCH_NORMAL_HURT_NAME[self:getMatchType()]] = normalHurt
	self.runesAttr[GConst.MATCH_SKILL_HURT_NAME[self:getMatchType()]] = skillHurt
	self.runesAttr[GConst.MATCH_CRIT_NAME[self:getMatchType()]] = critPer
	self.runesAttr[GConst.MATCH_CRIT_TIME_NAME[self:getMatchType()]] = critHurtPer
	self.runesAttr[GConst.MATCH_NORMAL_HURTP_NAME[self:getMatchType()]] = normalHurtPer
	self.runesAttr[GConst.MATCH_SKILL_HURTP_NAME[self:getMatchType()]] = skillHurtPer
	self.runesAttr[GConst.MATCH_CURED_NAME[self:getMatchType()]] = healPer
	self.runesAttr[GConst.MATCH_ALL_HURTP_NAME[self:getMatchType()]] = allHurtp

	-- if EDITOR_MODE then
	-- 	local printStr = ""
	-- 	printStr = printStr .. "更新符文数值："..self:getCfgId() .. "\n"
	-- 	printStr = printStr .. "生命：".. hp .. "\n"
	-- 	printStr = printStr .. "攻击力：".. atk .. "\n"
	-- 	printStr = printStr .. "普攻增伤：".. normalHurt .. "\n"
	-- 	printStr = printStr .. "技能增伤：".. skillHurt .. "\n"
	-- 	printStr = printStr .. "暴击率：".. critPer .. "\n"
	-- 	printStr = printStr .. "暴击伤害百分比：".. critHurtPer .. "\n"
	-- 	printStr = printStr .. "普攻增伤百分比：".. normalHurtPer .. "\n"
	-- 	printStr = printStr .. "技能增伤百分比：".. skillHurtPer .. "\n"
	-- 	printStr = printStr .. "治疗加成百分比：".. healPer .. "\n"
	-- 	printStr = printStr .. "所有伤害百分比：".. allHurtp .. "\n"
	-- 	Logger.logHighlight(printStr)
	-- end
end

-- 更新总属性
function HeroEntity:updateTotalAttr()
	self.allAttr = {}
	for k, v in pairs(self.baseAttrOriginal) do
		self:setTotalAttrValue(k, v)
	end
	for k, v in pairs(self.equipAttr) do
		self:addTotalAttrValue(k, v)
	end
	for k, v in pairs(self.skinAttr) do
		self:addTotalAttrValue(k, v)
	end
	for k, v in pairs(self.runesAttr) do
		self:addTotalAttrValue(k, v)
	end
end

function HeroEntity:setTotalAttrValue(name, value)
	-- Logger.logHighlight("set    "..name..":"..value)
	self.allAttr[name] = GFunc.encryptNumber(value or 0)
end

function HeroEntity:addTotalAttrValue(name, add)
	-- Logger.logHighlight("add    "..name..":"..add)
	local before = self:getTotalAttrValue(name)
	self.allAttr[name] = GFunc.encryptNumber(before + add or 0)
end

function HeroEntity:getTotalAttrValue(name)
	if table.nums(self.allAttr) <= 0 then
		self:initAttr()
	end

	if not self.allAttr[name] then
		return 0
	end
	-- Logger.logHighlight("get    "..name..":"..GFunc.decryptNumber(self.allAttr[name]))
	return GFunc.decryptNumber(self.allAttr[name])
end

function HeroEntity:setLv(lv, onlyChangeLv)
	if not lv then
		return
	end
	if self.data.lv == lv then
		return
	end
	self.data.lv = lv
	self:updateAllAttr()
	self:setDirty()

	if not onlyChangeLv then
		ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_HERO_LV_UP, lv)
		EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.HERO_UPGRADE_SUCCESS, self:getCfgId())
	end
end

function HeroEntity:getCfgId()
	return self.cfgId
end

function HeroEntity:getLv()
	return self.data.lv
end

-- 获取当前穿戴皮肤
function HeroEntity:getSkinId()
	if self.data.skin == nil or self.data.skin == 0 then
		return DataManager.SkinData:getOriginSkinId(self:getCfgId())
	end
	return self.data.skin
end

-- 穿戴皮肤
function HeroEntity:onChangeSkin(skinId)
    self.data.skin = skinId
    self:setDirty()
end

function HeroEntity:getQlt()
	return self.config.qlt
end

function HeroEntity:getBeginLv()
	return self.beginLv
end

function HeroEntity:getMatchType()
	return self.config.position
end

-- 英雄每级可领取图鉴点数
function HeroEntity:getCollectionPoint()
	return self.config.collection_point
end

function HeroEntity:getCfgHp(lv)
	lv = lv or self.data.lv
	if lv > self:getMaxLv() then
		lv = self:getMaxLv()
	end
	if self.config and self.config.hp then
		return self.config.hp[lv] or 0
	end

	return 0
end

function HeroEntity:getCfgAtk(lv)
	lv = lv or self.data.lv
	if lv > self:getMaxLv() then
		lv = self:getMaxLv()
	end
	if self.config and self.config.atk then
		return self.config.atk[lv] or 0
	end

	return 0
end

function HeroEntity:getUnlcokChapter()
	return self.config.unlock_chapter
end

function HeroEntity:getUnlockDan()
	return self.config.unlock_arena

end

function HeroEntity:getIsShowUnlcokChapter()
	return self.config.is_show == 1
end

function HeroEntity:getAtk()
	local atkName = GConst.MATCH_ATTACK_NAME[self:getMatchType()]
	local atkAddName = GConst.MATCH_ATTACK_ADD_NAME[self:getMatchType()]
	return self:getTotalAttrValue(atkName) + self:getTotalAttrValue(atkAddName)
end

function HeroEntity:getHp()
	local hpName = ATTR_NAME.HP
	local hpAddName = GConst.MATCH_HP_ADD_NAME[self:getMatchType()]
	return self:getTotalAttrValue(hpName) + self:getTotalAttrValue(hpAddName)
end

function HeroEntity:isMaxLv()
    return self.data.lv >= self:getMaxLv()
end

function HeroEntity:getMaxLv()
	if not self.maxLv then
		self.maxLv = ConfigManager:getConfigNum("hero_level")
	end
	return self.maxLv
end

function HeroEntity:canLvUp(showToast)
	if self:isMaxLv() then
		return false, GConst.HeroConst.CHECK_LV_UP_STATE.MAX_LV
	end

	local cost = self:getLvUpMaterials()
	if not cost then
		return false, GConst.HeroConst.CHECK_LV_UP_STATE.NO_COST
	end

	local fragmentCost = cost[1] or 0
	if not GFunc.checkCost(self:getFragmentId(), fragmentCost, showToast) then
		return false, GConst.HeroConst.CHECK_LV_UP_STATE.FRAGMENT_NOT_ENOUGH
	end
	local goldCost = cost[2] or 0
	if not GFunc.checkCost(GConst.ItemConst.ITEM_ID_GOLD, goldCost, showToast) then
		return false, GConst.HeroConst.CHECK_LV_UP_STATE.COIN_NOT_ENOUGH
	end

	return true, GConst.HeroConst.CHECK_LV_UP_STATE.SUCCESS
end

function HeroEntity:isUnlock()
	if self:isActived() then
		return true
	else
		if self:canLvUp() then
			return true
		end
	end

	local unlockChapter = self:getUnlcokChapter()
	if unlockChapter and unlockChapter <= DataManager.ChapterData:getMaxChapterId() then
		return true
	end
	local unlockDan = self:getUnlockDan()
	if unlockDan and unlockDan <= DataManager.ArenaData:getFormartMaxGrading() then
		return true
	end
	return false
end

function HeroEntity:isActived()
	return self.data.lv >= self:getBeginLv()
end

function HeroEntity:getLvUpMaterials()
	local lv = self.data.lv + 1
	if lv < self:getBeginLv() then
		lv = self:getBeginLv()
	end
	local nextLvInfo = ConfigManager:getConfig("hero_level")[lv]
	if not nextLvInfo then
		return
	end
	local fieldName = "cost_" .. self:getQlt()
	return nextLvInfo[fieldName]
end

function HeroEntity:getConfig()
	return self.config
end

function HeroEntity:getModelId()
	local skinModel = DataManager.SkinData:getModelId(self:getSkinId())
	return skinModel or self.config.model_id
end

function HeroEntity:getBaseSkill()
	return self.config.base_skill
end

function HeroEntity:getAssistingSkill()
	return self.config.support_skill
end

function HeroEntity:getHurtSkill()
	return self.config.hurt_skill
end

function HeroEntity:getFragmentId()
	return self.config.item_id
end

function HeroEntity:getIcon()
	return self.config.icon
end

function HeroEntity:getHurtNum()
	return self.config.hurt_num
end

function HeroEntity:getName()
	return ModuleManager.HeroManager:getHeroName(self:getCfgId())
end

function HeroEntity:getDesc()
	return ModuleManager.HeroManager:getHeroDesc(self:getCfgId())
end


function HeroEntity:getActiveRogueCount()
	local lvInfo = ConfigManager:getConfig("hero_level")[self.data.lv]
	if not lvInfo then
		return 0
	end
	return lvInfo.unlock_skill
end

function HeroEntity:getUnlockRogueId()
	return self.config.rouge_skill
end

function HeroEntity:getRogueSkillList()
	if not self.rogueSkillList then
		self.rogueSkillList = {}
		local count = 1
		while true do
			local id = self.config["rouge_skill_" .. count]
			if id then
				table.insert(self.rogueSkillList, id)
			else
				break
			end
			count = count + 1
		end
	end

	return self.rogueSkillList
end

function HeroEntity:getActiveRogueSkills()
	local list = {}
	for i = 1, self:getActiveRogueCount() do
		local id = self:getRogueSkillList()[i]
		if id then
			table.insert(list, id)
		else
			break
		end
	end

	return list
end

-- 获取总基础生命值（英雄+装备+皮肤）
function HeroEntity:getTotalBaseHp()
	local result = self:isActived() and self:getCfgHp() or self:getCfgHp(self:getBeginLv())
	-- 武器 + 防具
	for partName, partType in pairs(GConst.EquipConst.PART_TYPE) do
		local equipEntity = self:getEquips(partType)
		if equipEntity then
			result = result + equipEntity:getBaseHp()
		end
	end
	result = result + DataManager.SkinData:getBaseHp(self)

	local runesEntity = self:getRunes()
	if runesEntity then
		result = result + runesEntity:getAttrValue(GConst.MATCH_HP_FIX_NAME[self:getMatchType()], true)
	end

	return result
end

-- 获取总基础攻击值（英雄+装备+皮肤）
function HeroEntity:getTotalBaseAtk()
	local result = self:isActived() and self:getCfgAtk() or self:getCfgAtk(self:getBeginLv())
	-- local logStr = self:getCfgId() .. "总基础攻击值:\n英雄：" .. result
	-- 武器 + 防具
	for partName, partType in pairs(GConst.EquipConst.PART_TYPE) do
		local equipEntity = self:getEquips(partType)
		if equipEntity then
			-- logStr = logStr .. "\n" .. partName .. "：" .. equipEntity:getBaseAttack()
			result = result + equipEntity:getBaseAttack()
		end
	end
	-- logStr = logStr .. "\nSKIN：" .. DataManager.SkinData:getBaseAttack(self)
	result = result + DataManager.SkinData:getBaseAttack(self)
	local runesEntity = self:getRunes()
	if runesEntity then
		-- logStr = logStr .. "\nRUNES：" .. self:getRunes():getAttrValue(GConst.MATCH_ATTACK_NAME[self:getMatchType()], true)
		result = result + runesEntity:getAttrValue(GConst.MATCH_ATTACK_NAME[self:getMatchType()], true)
	end
	-- Logger.logHighlight(logStr)
	return result
end

-- {partType = EquipEntity}
function HeroEntity:setEquips(partType, equipEntities, notNowUpdate)
	if self.equipEntities == nil then
		self.equipEntities = {}
	end
	self.equipEntities[partType] = equipEntities

	if notNowUpdate then
		return
	end
	self:getTotalAttrValue() -- 防止报错
	self:onEquipAttrChange()
end

function HeroEntity:getEquips(partType)
	if self.equipEntities then
		return self.equipEntities[partType]
	end
	return nil
end

function HeroEntity:setSkins(skinIds)
	self.unlockSkins = skinIds
	self:getTotalAttrValue() -- 防止报错
	self:onSkinAttrChange()
end

function HeroEntity:getSkins()
	return self.unlockSkins
end

function HeroEntity:setRunes(runesEntity, notNowUpdate)
	self.runesEntity = runesEntity

	if notNowUpdate then
		return
	end
	self:getTotalAttrValue() -- 防止报错
	self:onRunesAttrChange()
end

function HeroEntity:getRunes()
	return self.runesEntity
end

return HeroEntity