local HeroEntity = require "app/userdata/hero/hero_entity"
local HeroData = class("HeroData", BaseData)

local HeroCfg = ConfigManager:getConfig("hero")
local HeroLevelCfg = ConfigManager:getConfig("hero_level")

function HeroData:ctor()
	self.heroes = {}
	self.data.activeCount = 0
	self.data.isDirty = false
	self.data.isPowerDirty = false
	self.matchActiveHeroMap = {}
	self.maxHeroLvOnInit = 0

	self.allAtkpAttr = {}
	self.allAtkpAttrByHero = {}
	self.allAtkpAttrByTalent = {}
end

function HeroData:clear()
	self.heroes = {}
end

function HeroData:init(data)
	self.heroes = {}
	if data then
		for id, heroInfo in pairs(data) do
			self:addHero(heroInfo)
			if self.maxHeroLvOnInit < heroInfo.level then
				self.maxHeroLvOnInit = heroInfo.level
			end
		end
	end

	for heroId, entity in pairs(self.heroes) do
		if entity and entity:isActived() then
			local matchType = entity:getMatchType()
			if not self.matchActiveHeroMap[matchType] then
				self.matchActiveHeroMap[matchType] = {}
			end
			self.matchActiveHeroMap[matchType][entity:getCfgId()] = true
		end
	end

	self:calcPower()
end

-- 是否是合法的英雄
function HeroData:isExistHeroById(id)
	if not id or id == 0 then
		return false
	end

	return HeroCfg[id] ~= nil
end

function HeroData:addHero(heroStruct)
	if self.heroes[heroStruct.id] then
		return
	end
	local entity = self:getEntity(heroStruct)

	self.heroes[heroStruct.id] = entity
	self.data.activeCount = self.data.activeCount + 1
end

function HeroData:getEntity(heroStruct)
	return HeroEntity:create(heroStruct.id, heroStruct.level, heroStruct.skin, heroStruct.star)
end

function HeroData:getHeroById(id)
	if not self:isExistHeroById(id) then
		return
	end
	if not self.heroes[id] then
		self.heroes[id] = self:getEntity({id = id, level = 0, skin = 0, star = 0})
	end
	return self.heroes[id]
end

function HeroData:getAllHeroes()
	return self.heroes
end

function HeroData:getActiveHeroCount()
	return self.data.activeCount
end

function HeroData:getHeroIsActive(id)
	local entity = self.heroes[id]
	if entity == nil then
		return false
	end
	return entity:isActived()
end


function HeroData:isInStageFormation(heroId)
	local cfg = HeroCfg[heroId]
	local slotId = cfg.position
	local curFormation = DataManager.FormationData:getStageFormation()
	if curFormation[slotId] ~= heroId then
		return false
	end
	return true
end


function HeroData:getHeroIsUnlock(id)
	local entity = self.heroes[id]
	if entity == nil then
		return false
	end
	return entity:isUnlock()
end

function HeroData:getUnlockHeroCount(elementType)
	local count = 0
	for id, entity in pairs(self.heroes) do
		if entity:isUnlock() and (not elementType or elementType == 0 or entity:getMatchType() == elementType) then
			count = count + 1
		end
	end
	return count
end

function HeroData:setHeroLv(id, lv)
	local entity = self:getHeroById(id)
	local activeBefore = true
	if not entity:isActived() then
		self.data.activeCount = self.data.activeCount + 1
		ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_NEW_HERO_GOT)
		ModuleManager.PlayerManager:checkUnlockAvatar(id)
		activeBefore = false
		BIReport:postFirstGetHero(self.data.activeCount)
	end
	local beforeLv = entity:getLv()
	entity:setLv(lv)
	if entity:isActived() then
		local matchType = entity:getMatchType()
		if not self.matchActiveHeroMap[matchType] then
			self.matchActiveHeroMap[matchType] = {}
		end
		self.matchActiveHeroMap[matchType][entity:getCfgId()] = true
	end

	if activeBefore then
		BIReport:postHeroOpt(id, BIReport.HERO_OPT_TYPE.LEVEL_UP)
	else
		BIReport:postHeroOpt(id, BIReport.HERO_OPT_TYPE.ACTIVE)
	end

	BIReport:postHeroLev(beforeLv, lv)
	BIReport:postFirstDayHeroLevel(id)
end

function HeroData:getHeroIsNew(id)
	local entity = self:getHeroById(id)
	return entity and entity:getIsNew() or false
end

function HeroData:getMatchActiveHeroMap()
	return self.matchActiveHeroMap
end

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

function HeroData:getRp()
	local formationMap = DataManager.FormationData:getStageFormation()
	if not formationMap then
		return false
	end
	local heroMap = {}
	for _, heroId in pairs(formationMap) do
		heroMap[heroId] = true
	end

	for id, entity in pairs(self.heroes) do
		if (heroMap[id] and entity:canLvUp()) or entity:canStarUp() then
			return true
		end
	end

	for _, heroId in pairs(formationMap) do
		if heroId > 0 then
			local cfg = HeroCfg[heroId]
			if DataManager.EquipData:hasEquipRedPoint(cfg.position) then
				return true
			end
		end
	end

	return false
end

function HeroData:getMaxHeroLvOnInit()
	return self.maxHeroLvOnInit
end

function HeroData:getAllHeroesBIStr()
	local str
	for heroId, entity in pairs(self:getAllHeroes()) do
		if str then
			str = str .. "|"
		else
			str = GConst.EMPTY_STRING
		end
		str = str .. heroId .. ":" .. entity:getLv()
	end
	return str
end

function HeroData:getMaxStarQlt5()
	local star = 0
	for k,v in pairs(self.heroes) do
		local qlt = v:getQlt()
		if qlt == 5 then
			star = math.max(star, v:getStar())
		end
	end
	return star
end

-- 获取所有英雄列表（等级>品质>id）
function HeroData:getAllHeroesSort(formationType, elementType)
	local formationMap
	if formationType then
		local formation = DataManager.FormationData:getFormation(formationType)
		formationMap = {}
		for _, heroId in pairs(formation) do
			formationMap[heroId] = true
		end
	end
	local result = {}
	for id, v in pairs(HeroCfg) do
		if (not elementType or elementType == 0 or elementType == v.position) and (not v.lock_show or self:getHeroIsActive(id)) then
			table.insert(result, {cfgId = id, sort = id, elementType = v.position})
		end
	end

	for _, info in ipairs(result) do
		local heroEntity = self:getHeroById(info.cfgId)
		local sort = info.cfgId -- id 预留6位
		sort = sort + (10 - info.elementType) * 1000000 -- 位置预留1位
		sort = sort + 10000000000 * heroEntity:getQlt() -- 品质1位
		sort = sort + 10000000 * heroEntity:getLv() -- 预留3位

		if formationMap and formationMap[info.cfgId] then --在布阵中
			sort = sort + 10000000000000
		end

		if not heroEntity:isActived() and heroEntity:canLvUp() then
			sort = sort + 1000000000000
		else
			if heroEntity:isUnlock() then
				sort = sort + 300000000000
				if heroEntity:isActived() then
					sort = sort + 400000000000
				else
					sort = sort + 300000000000
				end
			elseif DataManager.BagData.ItemData:getItemNumById(heroEntity:getFragmentId()) > 0 then
				sort = sort + 200000000000
			else
				sort = sort + 100000000000
			end
		end

		info.sort = sort
	end
	table.sort(result, function(a, b)
		return a.sort > b.sort
	end)

	return result
end

-- region 配置相关
function HeroData:getHeroConfig(id)
	if id then
		return HeroCfg[id]
	else
		return HeroCfg
	end
end

function HeroData:getHeroQlt(id)
	local cfg = self:getHeroConfig(id)
	if cfg then
		return cfg.qlt
	end
end

function HeroData:getHeroLevelConfig(lv)
	if lv then
		return HeroLevelCfg[lv]
	else
		return HeroLevelCfg
	end
end

-- 升级目前跟质量无关
function HeroData:getHeroLevelCost(lv, qlt)
    local cfg = self:getHeroLevelConfig(lv)
    if cfg then
        return cfg.cost
    end
end
-- endregion

-- region 升星相关
function HeroData:isStarOpen()
	return true
end

function HeroData:getStarById(id)
	local hero = self.heroes[id]
	if hero then
		return hero:getStar()
	end
	return 0
end

function HeroData:onHeroStarUp(id)
	local entity = self:getHeroById(id)
	if entity then
		entity:onHeroStarUp()
	end
	-- BIReport:postHeroLev(beforeLv, lv)
	-- BIReport:postFirstDayHeroLevel(id)
end
-- endregion

-- region 皮肤相关
function HeroData:isSkinOpen()
	return true
end
-- endregion

-- region 属性相关
function HeroData:setAllHeroesDitry()
	for k,v in pairs(self.heroes) do
		v:setAttrDirty()
	end
end

function HeroData:getAttrByMatchType(matchType, attrType)
	self.allAtkpAttr[matchType] = self.allAtkpAttr[matchType] or {}
	return self.allAtkpAttr[matchType][attrType] or 0
end

function HeroData:setHeroAttr(heroId, attr)
	self.allAtkpAttrByHero[heroId] = attr
	self:calcAttr()
	self:setAllHeroesDitry()
end

function HeroData:setTalentAttr(attr)
	self.allAtkpAttrByTalent = attr
	self:calcAttr()
	self:setAllHeroesDitry()
end

function HeroData:calcAttr()
	self.allAtkpAttr = {{}, {}, {}, {}, {}}
	for heroId, attrs in pairs(self.allAtkpAttrByHero) do
		for matchType, v in ipairs(self.allAtkpAttr) do
			for k, vv in pairs(attrs) do
				self.allAtkpAttr[matchType][k] = (self.allAtkpAttr[matchType][k] or 0) + vv
			end
		end
	end

	for k, v in pairs(self.allAtkpAttrByTalent) do
		for matchType = 1, 5 do
			self.allAtkpAttr[matchType] = self.allAtkpAttr[matchType] or {}
			self.allAtkpAttr[matchType][k] = (self.allAtkpAttr[matchType][k] or 0) + v
		end
	end
end

function HeroData:getAllStarAttr()
	local allAttr = {}
	for k,v in pairs(self.heroes) do
		local attr = v:getStarAttr()
		for k2,v2 in pairs(attr) do
			allAttr[k2] = (allAttr[k2] or 0) + v2
		end
	end
	return allAttr
end
-- endregion

--@region 战斗力
function HeroData:getShowPower()
	if self.curPower == nil then
		self:calcPower()
	end
	return self.curPower
end

function HeroData:getLastPower()
	return self.lastPower or 0
end

function HeroData:clearLastPower()
	self.lastPower = nil
end

-- 计算战斗力
function HeroData:calcPower()
	if self.lastPower then
		self.lastPower = self.curPower
	end

	local attrPower = 0
	local formation = DataManager.FormationData:getStageFormation()
	for _, heroId in pairs(formation) do
		local heroEntity = DataManager.HeroData:getHeroById(heroId)
		if heroEntity then
			attrPower = attrPower + heroEntity:getPower()
		end
	end

	-- -- 天赋战力
	-- local talentPower = DataManager.TalentData:getPower()
	-- -- 英雄战力
	-- local forcePower = DataManager.ForceData:getPower()
	-- -- 英雄皮肤战力
	-- local forceSkinPower = DataManager.ForceData:getSkinPower()
	-- -- 英雄装备战力
	-- local equipPower = DataManager.ForceEquipData:getPower()
	-- -- 领主时装战力
	-- local skinPower = DataManager.SkinData:getPower()
	-- -- 宝物战力
	-- local collectionPower = DataManager.CollectionData:getPower()
	-- -- 防线战力
	-- local defenseLinePower = DataManager.DefenseLineData:getPower()
	-- -- 防线皮肤战力
	-- local defenseLineSkinPower = DataManager.DefenseLineData:getSkinPower()
	-- -- 宠物战力
	-- local petPower = DataManager.PetData:getPower()
	-- -- 魔法书战力
	-- local magicBookPower = DataManager.MagicBookData:getPower()
	-- -- 魔法阵战力
	-- local magicCirclePower = DataManager.MagicCircleData:getPower()

	self.curPower = 0
	self.curPower = self.curPower + attrPower
	-- self.curPower = self.curPower + talentPower
	-- self.curPower = self.curPower + forcePower
	-- self.curPower = self.curPower + forceSkinPower
	-- self.curPower = self.curPower + equipPower
	-- self.curPower = self.curPower + skinPower
	-- self.curPower = self.curPower + collectionPower
	-- self.curPower = self.curPower + defenseLinePower
	-- self.curPower = self.curPower + defenseLineSkinPower
	-- self.curPower = self.curPower + petPower
	-- self.curPower = self.curPower + magicBookPower
	-- self.curPower = self.curPower + magicCirclePower

	-- if EDITOR_MODE and self:getIsSelf() then
	-- 	Logger.logHighlight("PlayerEntity 总战力:" .. self.curPower)
	-- 	Logger.logHighlight("PlayerEntity 属性战力:" .. attrPower)
	-- 	Logger.logHighlight("PlayerEntity 天赋战力:" .. talentPower)
	-- 	Logger.logHighlight("PlayerEntity 英雄战力:" .. forcePower)
	-- 	Logger.logHighlight("PlayerEntity 英雄皮肤战力:" .. forceSkinPower)
	-- 	Logger.logHighlight("PlayerEntity 英雄装备战力:" .. equipPower)
	-- 	Logger.logHighlight("PlayerEntity 领主时装战力:" .. skinPower)
	-- 	Logger.logHighlight("PlayerEntity 宝物战力:" .. collectionPower)
	-- 	Logger.logHighlight("PlayerEntity 防线战力:" .. defenseLinePower)
	-- 	Logger.logHighlight("PlayerEntity 防线皮肤战力:" .. defenseLineSkinPower)
	-- 	Logger.logHighlight("PlayerEntity 宠物战力:" .. petPower)
	-- 	Logger.logHighlight("PlayerEntity 魔法书战力:" .. magicBookPower)
	-- 	Logger.logHighlight("PlayerEntity 魔法阵战力:" .. magicCirclePower)
	-- end

	if not self.lastPower then
		self.lastPower = self.curPower
	end
	if self.lastPower ~= self.curPower then
		self:setPowerDirty()
	end
end

function HeroData:setPowerDirty()
	self.data.isPowerDirty = not self.data.isPowerDirty
end
--@endregion

return HeroData