local DataManager = {
	initByServer = false
}

function DataManager:init()
	self.cdCallBack = {}
	self._cacheManager = {}
	self:initManager("GameSettingData", "app/userdata/game_setting/game_setting_data")
	self:initManager("PlayerData", "app/userdata/player/player_data")
	self:initManager("ChapterData", "app/userdata/chapter/chapter_data")
	self:initManager("DailyChallengeData", "app/userdata/daily_challenge/daily_challenge_data")
	self:initManager("DungeonData", "app/userdata/dungeon/dungeon_data")
	self:initManager("ArenaData", "app/userdata/arena/arena_data")
	self:initManager("CollectionData", "app/userdata/collection/collection_data")
	self:initManager("HeroData", "app/userdata/hero/hero_data")
	self:initManager("BagData", "app/userdata/bag/bag_data")
	self:initManager("EquipData", "app/userdata/equip/equip_data")
	self:initManager("SkinData", "app/userdata/skin/skin_data")
	self:initManager("BattleData", "app/userdata/battle/battle_data")
	self:initManager("BattlePVPData", "app/userdata/battle/battle_pvp_data")
	self:initManager("FormationData", "app/userdata/formation/formation_data")
	self:initManager("TutorialData", "app/userdata/tutorial/tutorial_data")
	self:initManager("MailData", "app/userdata/mail/mail_data")
	self:initManager("ActivityData", "app/userdata/activity/activity_data")
	self:initManager("GoldPigData", "app/userdata/activity/gold_pig/gold_pig_data")
	self:initManager("BountyData", "app/userdata/bounty/bounty_data")
	self:initManager("ArenaBountyData", "app/userdata/arena/arena_bounty_data")
	self:initManager("TaskData", "app/userdata/task/task_data")
	self:initManager("DailyTaskData", "app/userdata/task/daily_task_data")
	self:initManager("IdleData", "app/userdata/idle/idle_data")
	self:initManager("GrowthFundData", "app/userdata/fund/growth_fund_data")
	self:initManager("SevenDayData", "app/userdata/activity/seven_day/seven_day_data")
	self:initManager("ShopData", "app/userdata/shop/shop_data")
	self:initManager("SummonData", "app/userdata/summon/summon_data")
	self:initManager("FullMoonData", "app/userdata/activity/full_moon/full_moon_data")
	self:initManager("TournWaveData", "app/userdata/activity/tourn_wave/tourn_wave_data")
	self:initManager("TournArenaData", "app/userdata/activity/tourn_arena/tourn_arena_data")
	self:initManager("AIHelperData", "app/userdata/game_setting/ai_helper_data")
	self:initManager("HeroFundData", "app/userdata/activity/hero_fund/hero_fund_data")
	self:initManager("ActBossRushData", "app/userdata/activity/act_boss_rush/act_boss_rush_data")
	self:initManager("FourteenDayData", "app/userdata/activity/fourteen_day/fourteen_day_data")
	self:initManager("ActPvpData", "app/userdata/activity/act_pvp/act_pvp_data")
end

function DataManager:initManager(name, path)
	if self[name] then
		self._cacheManager[name] = self[name]
	end

	if (name == "BattleData" or name == "BattlePVPData") and self._cacheManager[name] then
	else
		self[name] = require(path):create()
	end
end

function DataManager:checkDataBind()
	local changeBindFunc = function(baseData, curBaseData)
		local data = baseData.data
        if data then
            local bindList = baseData.bindList
            if bindList then
                for fieldName, list in pairs(bindList) do
					for _, v in ipairs(list) do
						if v.binder.unBind then
							v.binder:unBind(baseData, fieldName)
						end

						if v.binder.bind then
							if baseData.data[fieldName] ~= curBaseData.data[fieldName] then
								v.binder:bind(curBaseData, fieldName, v.bindFunc, true)
							else
								v.binder:bind(curBaseData, fieldName, v.bindFunc)
							end
						end
					end
                end
            end
            baseData:clearBindAll()
        end
	end

    if self._cacheManager then -- 如果已经存在就检查一下绑定
		for name, baseData in pairs(self._cacheManager) do
			if name == "BagData" then
				changeBindFunc(baseData.ItemData, self[name].ItemData)
			else
				if baseData ~= self[name] then
					changeBindFunc(baseData, self[name])
				end
			end
		end
    end
end

function DataManager:clear()
	self.loginSuccess = false
	self.initWithServer = false
	if self.cacheTimer then
        SchedulerManager:unscheduleGlobal(self.cacheTimer)
        self.cacheTimer = nil
    end
	self.cdCallBack = {}
	self.PlayerData:clear()
	self.ChapterData:clear()
	self.DailyChallengeData:clear()
	self.DungeonData:clear()
	self.ArenaData:clear()
	self.CollectionData:clear()
	self.HeroData:clear()
	self.BagData:clear()
	self.EquipData:clear()
	self.SkinData:clear()
	self.FormationData:clear()
	self.ActivityData:clear()
	self.MailData:clear()
	self.GoldPigData:clear()
	self.BountyData:clear()
	self.ArenaBountyData:clear()
	self.DailyTaskData:clear()
	self.IdleData:clear()
	self.GrowthFundData:clear()
	self.SevenDayData:clear()
	self.ShopData:clear()
	self.SummonData:clear()
	self.FullMoonData:clear()
	self.TournWaveData:clear()
	self.TournArenaData:clear()
	-- 任务数据最后清理
	self.TaskData:clear()
	self.AIHelperData:clear()
	self.HeroFundData:clear()
	self.ActBossRushData:clear()
	self.FourteenDayData:clear()
	self.ActPvpData:clear()
	ModuleManager.TaskManager:clear()
	self:clearTryOpenFunc()
	self.activityBountyLevelMap = nil
end

function DataManager:initWithServerData(data)
	self:init()
	Time:setServerTimeZone(0)
	Time:updateServerTime(data.now_ts)
	Time:updateServerTimeToday(data.today_ts)

	if EDITOR_MODE then
		Logger.logHighlight("initWithServerData")
		Logger.printTable(data)
		Logger.logHighlight("注册时间 : " .. Time:formatTimeYMDHMS(GFunc.formatTimeStep(data.stat.register_ts)))
	end
	self.registerTs = data.stat and data.stat.register_ts or Time:getServerTime()
	self.registerTs = GFunc.formatTimeStep(self.registerTs or Time:getServerTime())
	self.todayFirstLogin = data.today_first_login
	self.PlayerData:init(data)
	self.ChapterData:init(data.chapter)
	self.DailyChallengeData:init(data.chapter_daily_challenge)
	self.DungeonData:initDungeonGold(data.chapter_gold_challenge)
	self.DungeonData:initDungeonShards(data.chapter_shards_challenge)
	self.FormationData:init(data.fight_info)
	self.EquipData:init(data.heroes_equips)
	self.EquipData:initGifts(data.act_weapon_armor_gift)
	self.SkinData:init(data.bag.skins)
	-- HeroData要在EquipData、SkinData之后初始化，依赖它们的属性数据
	self.HeroData:init(data.bag.heroes)
	self.BagData:init(data.bag)
	self.DungeonData:initDungeonWeapon(data.chapter_weapon_challenge)
	self.DungeonData:initDungeonArmor(data.chapter_armor_challenge)
	self.CollectionData:init(data.collection)
	self.TutorialData:init(data.guide)
	self.MailData:init(data.mail_info)
	self.GoldPigData:init(data.pig, true)
	self.BountyData:init(data.bounty)
	self.ArenaBountyData:init(data.arena_bounty)
	self.ArenaData:initGiftInfo(data.act_arena_gift, true)
	-- 任务要在BountyData之后初始化，依赖BountyData的数据
	self.DailyTaskData:init(data.task_daily)
	self.IdleData:init(data.idle)
	self.SevenDayData:init(data.seven_day)
	self.ShopData:initBase()
	self.ShopData:initActGift(data.act) -- 礼包购买信息
	self.ShopData:initMallDaily(data.mall_daily) -- 每日特惠
	self.ShopData:initCommonDailyGoldGift(data.mall_idle and data.mall_idle.ad_count) -- 常驻金币礼包
	self.ShopData:initGrowUpGift(data.act_grow_up_gift2) -- 成长礼包
	self.ShopData:initLevelUpGift(data.act_level_up_gift) -- 助力/金币礼包
	self.ShopData:initIntroductGift(data.act_introductory_gift) -- 入门礼包
	-- 活动要在礼包后初始化
	self.ActivityData:init()
	-- 商店礼包都初始化完了后检查一下每日红点
	self.ShopData:checkShopDiscountRedPoint()
	self.ShopData:checkLoginPopInfo() -- 需要写在shopdata所有初始化之后
	self.SummonData:init(data.summon, true)
	self.AIHelperData:init(nil, true)
	-- 成长基金要在ShopData和PlayerDataBagData还有之后初始化，依赖这些数据
	if data.fund then
		self.GrowthFundData:init(data.fund.funds)
	end
	self.HeroFundData:init(data.hero_fund)
	self.FourteenDayData:init(data.fourteen_bounty)

	-- 任务数据最后初始化,依赖其他模块的数据
	self.TaskData:init()
	self:scheduleGlobal()
	self:checkDataBind()
	ModuleManager.ArenaManager:reqArenaInfo()

	self:dealOpenActivity(data.activities)
	-- 写在最后，防止某些数据还未初始化，就被bi访问报错
	self.initWithServer = true
end

-- 是否首次登录
function DataManager:getIsFirstLogin()
	local nowTime = Time:getServerTime()
	local offset = nowTime - (self.registerTs or 0)
	if math.abs(offset) <= 10 and self:getIsTodayFirstLogin() then -- 允许误差
		return true
	end
	return false
end

-- 是否在新号24小时内
function DataManager:getIsInCreate24Hour()
	local nowTime = Time:getServerTime()
	local passTime = nowTime - (self.registerTs or 0)
	return passTime < 86400
end

function DataManager:getRegisterTs()
	return self.registerTs or 0
end

function DataManager:getIsTodayFirstLogin()
	return self.todayFirstLogin or false
end

function DataManager:getIsInitWithServer()
	return self.initWithServer
end

function DataManager:registerDataCd(dataName)
	if not dataName then
		return
	end
	for k, v in ipairs(self.cdCallBack) do
		if v == dataName then
			return
		end
	end
	table.insert(self.cdCallBack, dataName)
end

function DataManager:unregisterDataCd(dataName)
	if not dataName then
		return
	end
	for k, v in ipairs(self.cdCallBack) do
		if v == dataName then
			table.remove(self.cdCallBack, k)
			break
		end
	end
end

function DataManager:registerCrossDayFunc(bindId, func)
	if not bindId or not func then
		return
	end

	if not self.crossDayCallbacks then
		self.crossDayCallbacks = {}
	end
	for i, info in ipairs(self.crossDayCallbacks) do
		if info.bindId == bindId then
			self.crossDayCallbacks[i].func = func
			self.crossDayCallbacks[i].open = true
			return
		end
	end

	table.insert(self.crossDayCallbacks,{
		bindId = bindId,
		func = func,
		open = true
	})
end

function DataManager:unregisterCrossDayFunc(bindId)
	if not bindId then
		return
	end

	if not self.crossDayCallbacks then
		return
	end
	for i, info in ipairs(self.crossDayCallbacks) do
		if info.bindId == bindId then
			self.crossDayCallbacks[i].open = false
			return
		end
	end
end

function DataManager:scheduleGlobal()
	if self.cacheTimer then
		return
	end

	self.crossDayTS = Time:getOverOfServerToday()
	self.cacheTimer = SchedulerManager:scheduleGlobal(function (inter)
		for k, v in ipairs(self.cdCallBack) do
			if self[v] and self[v].updateCd then
				self[v]:updateCd()
			end
		end

		if Time:getServerTime() > self.crossDayTS then
			self.crossDayTS = Time:getOverOfServerToday()
			if self.crossDayCallbacks then
				for i, info in ipairs(self.crossDayCallbacks) do
					if info.func and info.open then
						info.func()
					end
				end
			end
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_LOGIN_DAY)
		end
	end, 1)
end

function DataManager:tryOpenModules()
	if not self.tryOpenCallbacks then
		return
	end
	for k, v in pairs(self.tryOpenCallbacks) do
		v()
	end
end

function DataManager:registerTryOpenFunc(bindId, func)
	if not bindId or not func then
		return
	end
	if not self.tryOpenCallbacks then
		self.tryOpenCallbacks = {}
	end
	self.tryOpenCallbacks[bindId] = func
end

function DataManager:unregisterTryOpenFunc(bindId)
	if not bindId then
		return
	end
	if not self.tryOpenCallbacks then
		return
	end
	self.tryOpenCallbacks[bindId] = nil
end

function DataManager:clearTryOpenFunc()
	if not self.tryOpenCallbacks then
		return
	end
	for k, v in pairs(self.tryOpenCallbacks) do
		self.tryOpenCallbacks[k] = nil
	end
end

function DataManager:getSignInfo()
	local nowTime = Time:getServerTime()
	local lastSignTime = self.signInfo.latest_at // 1000
	local todayBeginTime = nowTime - nowTime % 86400
	local canSign = lastSignTime < todayBeginTime
	if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.SIGNIN) then
		canSign = false
	end
	return self.signInfo.count or 0, canSign, self.hasSigned
end

function DataManager:setSignCount(count)
	self.hasSigned = true
	self.signInfo.count = count
	self.signInfo.latest_at = Time:getServerTime() * 1000
	--Logger.logHighlight("签到成功次数："..count)
end

function DataManager:resetSignInInfo()
	self.hasSigned = false
end

function DataManager:setLoginSuccess(success)
	self.loginSuccess = success
end

function DataManager:getLoginSuccess()
	return self.loginSuccess
end

-- 获取建号时间
function DataManager:getCreatePlayerTime()
    return self.createPlayerTime or Time:getServerTime()
end

-- 记录sync了多少次数据，如果以后游戏中要回到登录界面，则此值应当被清除
function DataManager:markSyncDataCount()
	if not self.syncDataCount then
		self.syncDataCount = 1
	else
		self.syncDataCount = self.syncDataCount + 1
	end
end

function DataManager:getSyncDataCount()
	return self.syncDataCount or 0
end

function DataManager:needDealGm()
	return self:getSyncDataCount() >= 2
end

function DataManager:getManager(name, path)
	if self[name] then
		return self[name]
	end
	self[name] = require(path):create()
	return self[name]
end

---- 缓存一下活动战令
function DataManager:getActivityBountyLevelByActId(actId)
	if not self.activityBountyLevelMap then
		self.activityBountyLevelMap = {}
		local cfg = ConfigManager:getConfig("activity_bounty_level")
		for id, info in pairs(cfg) do
			if info.act_id then
				if not self.activityBountyLevelMap[info.act_id] then
					self.activityBountyLevelMap[info.act_id] = {}
				end
				table.insert(self.activityBountyLevelMap[info.act_id], id)
			end
		end
	end
	return self.activityBountyLevelMap[actId]
end

---- 缓存一下活动兑换商店
function DataManager:getActivityExchangeByActId(actId)
	if not self.activityExchangeMap then
		self.activityExchangeMap = {}
		local cfg = ConfigManager:getConfig("activity_exchange")
		for id, info in pairs(cfg) do
			if info.activity then
				if not self.activityExchangeMap[info.activity] then
					self.activityExchangeMap[info.activity] = {}
				end
				table.insert(self.activityExchangeMap[info.activity], id)
			end
		end
	end
	return self.activityExchangeMap[actId]
end

---- 缓存一下活动排行榜
function DataManager:getActivityRankByActId(actId)
	if not self.activityRankMap then
		self.activityRankMap = {}
		local cfg = ConfigManager:getConfig("activity_rank")
		for id, info in pairs(cfg) do
			if info.act_id then
				if not self.activityRankMap[info.act_id] then
					self.activityRankMap[info.act_id] = {}
				end
				table.insert(self.activityRankMap[info.act_id], id)
			end
		end
	end
	return self.activityRankMap[actId]
end

function DataManager:dealOpenActivity(activityInfo)
	local curTime = Time:getServerTime()
	if not activityInfo then
		return
	end

	local newActivityList = {}
	local map = {}
	for _, info in ipairs(activityInfo) do
		if info.type then
			if not map[info.type] then
				map[info.type] = info
			else
				if map[info.type].start_at > info.start_at then
					map[info.type] = info
				end
			end
		end
	end
	for actType, info in pairs(map) do
		table.insert(newActivityList, info)
	end

	local dealTypeMap = {}
	for _, info in ipairs(newActivityList) do
		local startTime = GFunc.formatTimeStep(info.start_at)
		if startTime <= curTime and curTime <= GFunc.formatTimeStep(info.end_at) then
			local reqFunc = DataManager.activityOpenFunc[info.type]
			if reqFunc and not dealTypeMap[info.type] then
				dealTypeMap[info.type] = true
				reqFunc(info)
			end
		elseif startTime > curTime then
			local waitOpenFunc = DataManager.waitOpenActivity[info.type]
			if waitOpenFunc and not dealTypeMap[info.type] then
				dealTypeMap[info.type] = true
				waitOpenFunc(info)
			end
		end
	end
end

DataManager.activityOpenFunc = {
	[2] = function(params)
		DataManager.ActBossRushData:setActivityInfo(params)
		ModuleManager.ActBossRushManager:reqActData()
	end,
	[3] = function(params)
		DataManager.ActPvpData:setActivityId(params.id)
		DataManager.ActPvpData:setActivityInfo(params)
		DataManager.ActPvpData:init({}) -- 默认初始化
		ModuleManager.ActPvpManager:reqActData()
	end,
	[4] = function(params)
		DataManager.FullMoonData:setActStatus(params)
		ModuleManager.FullMoonManager:reqActData()
		ModuleManager.FullMoonManager:initTimer()
	end,
	[5] = function(params)
		DataManager.TournWaveData:setActStatus(params)
		ModuleManager.TournWaveManager:reqActData()
		ModuleManager.TournWaveManager:initTimer()
	end,
	[6] = function(params)
		DataManager.TournArenaData:setActStatus(params)
		ModuleManager.TournArenaManager:reqActData()
		ModuleManager.TournArenaManager:initTimer()
	end,
}

DataManager.waitOpenActivity = {
	[2] = function(params)
		DataManager.ActBossRushData:init({activity_id = params.id}) -- 默认初始化
		DataManager.ActBossRushData:setActivityInfo(params)
	end,
	[3] = function(params)
		DataManager.ActPvpData:setActivityId(params.id)
		DataManager.ActPvpData:setActivityInfo(params)
		DataManager.ActPvpData:init({}) -- 默认初始化
	end,
	[4] = function(params)
		DataManager.FullMoonData:setActStatus(params)
		ModuleManager.FullMoonManager:initTimer()
	end,
	[5] = function(params)
		DataManager.TournWaveData:setActStatus(params)
		ModuleManager.TournWaveManager:initTimer()
	end,
	[6] = function(params)
		DataManager.TournArenaData:setActStatus(params)
		ModuleManager.TournArenaManager:initTimer()
	end,
}

return DataManager