local CharacterFSMManager = require "app/module/character_fsm/character_fsm_manager"
local ModelObject = require "app/bf/unity/model_object"
local CharacterObject = require "app/bf/unity/character_object"
local WeaponObject = require "app/bf/unity/weapon_object"

local ModelManager = {
	heroCacheList = {},
	heroCacheMap = {}
}

local TypeOfGameObject = GConst.TYPEOF_UNITY_CLASS.GAME_OBJECT

local HERO_CACHE_SIZE = 10	-- 英雄缓存容量

function ModelManager:loadHeroAsync(id, parent, weaponAniName, weapon, callback)
	local path = "assets/prefabs/models/characters/" .. id .. ".prefab"
	ResourceManager:loadAsync(path, TypeOfGameObject, function(assetPath, prefab)
		if parent and parent:isDestroyed() then
			ResourceManager:destroyPrefab(prefab)
			ResourceManager:unload(assetPath)
			return
		end

		local characterObject = CharacterObject:create()
		characterObject:initWithPrefab(assetPath, prefab, id)
		characterObject:addUnloadCallback(function(obj)
			local modelPath = obj:getAssetPath()
			if self.heroCacheMap[modelPath] then
				ResourceManager:unload(modelPath)
			else
				if #self.heroCacheList >= HERO_CACHE_SIZE then
					local headPath = table.remove(self.heroCacheList, 1)
					ResourceManager:unload(headPath)
					self.heroCacheMap[headPath] = nil
				end
				self.heroCacheMap[modelPath] = true
				table.insert(self.heroCacheList, modelPath)
			end
		end)
		if parent then
			characterObject:setParent(parent, false)
		end

		local fsm = CharacterFSMManager:getFsm(characterObject)
		characterObject:setCharacterFSM(fsm)

		local nodeName = "hand_r_weapon"
		if weapon then
			for k, name in pairs(GConst.HeroConst.WEAPON_NODE) do
				local find = string.find(weapon, k)
				if find then
					local node = characterObject:getBoneByName(name)
					if node then
						nodeName = name
					end
					break
				end
			end
		end

		if weapon and characterObject:getBoneByName(nodeName) then
			ModelManager:loadWeaponAsync(weapon, characterObject:getBoneByName(nodeName), function(weaponObj)
				if weaponObj then
					characterObject:setWeaponInfo(weaponAniName, weaponObj)
				end
				characterObject:play("idle")

				if callback then
					callback(characterObject, weaponObj)
				end
			end)
		else
			characterObject:play("idle")

			if callback then
				callback(characterObject)
			end
		end
	end)
end

function ModelManager:loadWeaponAsync(weapon, parent, callback)
	local path = "assets/prefabs/models/weapon/" .. weapon .. ".prefab"
	ResourceManager:loadAsync(path, TypeOfGameObject, function(assetPath, prefab)
		if parent and parent:isDestroyed() then
			ResourceManager:destroyPrefab(prefab)
			ResourceManager:unload(assetPath)
			return
		end

		local modelObject = WeaponObject:create()
		modelObject:initWithPrefab(assetPath, prefab)
		modelObject:addUnloadCallback(function(obj)
			ResourceManager:unload(obj:getAssetPath())
		end)
		if parent then
			modelObject:setParent(parent, false)
		end

		if callback then
			callback(modelObject)
		end
	end)
end

function ModelManager:loadMonsterAsync(id, parent, callback)
	local path = "assets/prefabs/models/characters/" .. id .. ".prefab"
	ResourceManager:loadAsync(path, TypeOfGameObject, function(assetPath, prefab)
		if parent and parent:isDestroyed() then
			ResourceManager:destroyPrefab(prefab)
			ResourceManager:unload(assetPath)
			return
		end

		local characterObject = CharacterObject:create()
		characterObject:initWithPrefab(assetPath, prefab)
		characterObject:addUnloadCallback(function(obj)
			local modelPath = obj:getAssetPath()
			ResourceManager:unload(modelPath)
		end)
		if parent then
			characterObject:setParent(parent, false)
		end

		local fsm = CharacterFSMManager:getFsm(characterObject)
		characterObject:setCharacterFSM(fsm)

		if callback then
			callback(characterObject)
		end
	end)
end

function ModelManager:loadModelAsync(path, parent, callback)
	ResourceManager:loadAsync(path, TypeOfGameObject, function(assetPath, prefab)
		if parent and parent:isDestroyed() then
			ResourceManager:destroyPrefab(prefab)
			ResourceManager:unload(assetPath)
			return
		end

		local modelObject = ModelObject:create()
		modelObject:initWithPrefab(assetPath, prefab)
		modelObject:addUnloadCallback(function(obj)
			ResourceManager:unload(obj:getAssetPath())
		end)
		if parent then
			modelObject:setParent(parent, false)
		end

		if callback then
			callback(modelObject)
		end
	end)
end

function ModelManager:loadHeroShowAsync(id, parent, callback)
	local path = "assets/prefabs/models/characters_show/" .. id .. ".prefab"
	ResourceManager:loadAsync(path, TypeOfGameObject, function(assetPath, prefab)
		if parent and parent:isDestroyed() then
			ResourceManager:destroyPrefab(prefab)
			ResourceManager:unload(assetPath)
			return
		end

		local characterObject = CharacterObject:create()
		characterObject:initWithPrefab(assetPath, prefab, id)
		characterObject:addUnloadCallback(function(obj)
			ResourceManager:unload(obj:getAssetPath())
		end)
		if parent then
			characterObject:setParent(parent, false)
		end

		local fsm = CharacterFSMManager:getFsm(characterObject)
		characterObject:setCharacterFSM(fsm)

		if callback then
			callback(characterObject)
		end
	end)
end

function ModelManager:getHeroModelPathById(id)
	return "assets/prefabs/models/characters/" .. id .. ".prefab"
end

function ModelManager:markCache(path)
	if #self.heroCacheList >= HERO_CACHE_SIZE then
		return false
	end
	if self.heroCacheMap[path] == nil then
		self.heroCacheMap[path] = true
		table.insert(self.heroCacheList, path)
		return true
	end
	return false
end

function ModelManager:isCacheFull()
	return #self.heroCacheList >= HERO_CACHE_SIZE
end

function ModelManager:clearCache()
	for _, path in ipairs(self.heroCacheList) do
		ResourceManager:unload(path)
	end
	self.heroCacheList = {}
	self.heroCacheMap = {}
end

return ModelManager