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("HeroDataOther", "app/userdata/hero/hero_data_other")
	self:initManager("BagData", "app/userdata/bag/bag_data")
	self:initManager("EquipData", "app/userdata/equip/equip_data")
	self:initManager("EquipDataOther", "app/userdata/equip/equip_data_other")
	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("ActTaskData", "app/userdata/activity/act_task_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("ShopData", "app/userdata/shop/shop_data")
	self:initManager("SummonData", "app/userdata/summon/summon_data")
	self:initManager("AIHelperData", "app/userdata/game_setting/ai_helper_data")
	self:initManager("TalentData", "app/userdata/talent/talent_data")
	self:initManager("GiftPopData", "app/userdata/gift_pop/gift_pop_data")
	self:initManager("PaymentData", "app/userdata/payment/payment_data")

	self:initManager("FundLevelData", "app/userdata/fund_level/fund_level_data")
	self:initManager("SignWeekData", "app/userdata/sign/sign_week_data")
	self:initManager("SignMonthData", "app/userdata/sign/sign_month_data")
	self:initManager("ChapterFundData", "app/userdata/chapter_fund/chapter_fund_data")
	self:initManager("ActSevenDayData", "app/userdata/activity/act_seven_day/act_seven_day_data")

	-- 冲刺活动
	self:initManager("ActTimeData", "app/userdata/activity/act_time_data")
	self:initManager("ActGiftData", "app/userdata/activity/act_gift_data")
	self:initManager("ActSprintData", "app/userdata/activity/act_sprint/act_sprint_data")
	self:initManager("ActSprintSummonDataAll", "app/userdata/activity/act_sprint/act_sprint_summon_data_all")
	-- 特权卡
	self:initManager("PrivilegeCardData", "app/userdata/privilege_card/privilege_card_data")
	-- 日常副本
	self:initManager("DungeonDailyData", "app/userdata/dungeon/dungeon_daily_data")
	self:initManager("DungeonRuneData", "app/userdata/dungeon/dungeon_rune_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 = {}
	for _, v in pairs(self._cacheManager) do
		v:clear()
	end
	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)
	self.loginCount = data.stat and data.stat.login_day_count or 1

	if EDITOR_MODE then
		Logger.logHighlight("initWithServerData")
		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.FormationData:init(data.formations)
	self.EquipData:init(data.equip)
	-- self.SkinData:init(data.bag.skins)
	self.TalentData:init(data.talent)
	-- HeroData要在EquipData、SkinData、TalentData之后初始化，依赖它们的属性数据
	self.HeroData:init(data.bag.heroes)
	self.BagData:init(data.bag)
	self.TutorialData:init(data.guide)
	self.MailData:init(data.mail_info)

	self.PaymentData:initData(data.stat)
    self.PaymentData:initActGift(data.gift)
	-- 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, data.task_achievement)
	self.IdleData:init(data.idle)
	self.ShopData:init()
	self.ShopData:refreshDailyShop(data.mall_daily_store)
	self.PrivilegeCardData:init(data.card)
	self.ShopData:refreshGoldShop(data.mall_gold)
	-- self.ShopData:refreshEmblemShop(data.mall_mythic_store)
	-- self.ShopData:initVit(data.energy_limit)
	-- self.ShopData:initThirdPayOrder(data.third_pay)
	-- self.ShopData:initThirdPayGiftOrder(data.third_pay)
	-- self.ShopData:initBase()
	-- self.ShopData:initActGift(data.act) -- 礼包购买信息
	-- self.ShopData:initMallDaily(data.mall_daily_store) -- 每日特惠
	-- 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.FundLevelData:initData(data.fund) -- levelGiftData要放到PaymentData后面，因为要处理数据
	self.ChapterFundData:initData(data.chapter_fund)
	self.SignWeekData:initData(data.sign)
	self.SignMonthData:initData(data.sign_30)
	-- 活动要在礼包后初始化
	self.ActTimeData:init(data.activities) -- 全活动时间, after PlayerData
	self.ActivityData:initExchangeData(data.activity_exchange)
	self.ActTaskData:initTaskData(data.activity_score_task, data.activity_task)
	self.ActSprintData:init(data.activity_rush_exchange)
	self.ActSevenDayData:initData(data.seven_day)
	-- self.ActSprintSummonDataAll:initTaskData(data.activity_score_task, data.activity_task)
	-- 副本
    self.DungeonData:init()
    self.DungeonDailyData:init(data.dungeon)
    self.DungeonRuneData:init(data.dungeon)

	-- 商店礼包都初始化完了后检查一下每日红点
	-- self.ShopData:checkShopDiscountRedPoint()
	-- self.ShopData:checkLoginPopInfo() -- 需要写在shopdata所有初始化之后
	self.SummonData:init(data.summon_data, data.summon_shop)
	self.AIHelperData:init(nil, true)

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

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

function DataManager:setAuthInfo(authInfo)
    self.authInfo = authInfo
end

function DataManager:getAuthInfo()
    return self.authInfo
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

	if EDITOR_MODE then
		Logger.logHighlight("==========================================================")
		Logger.logHighlight("本地显示日期：" .. Time:formatTimeYMD())
		Logger.logHighlight("当前时间戳：" .. Time:getServerTime())
		Logger.logHighlight("本日时间戳：" .. Time:getDayBeginTimeStamp() .. "-" .. Time:getDayOverTimeStamp())
		Logger.logHighlight("本周时间戳：" ..
		Time:getWeekBeginTimeStamp() .. "-" .. Time:getWeekOverTimeStamp() .. "   当前处于本周第" .. Time:getDayofWeek() .. "天")
		Logger.logHighlight("本月时间戳：" ..
		Time:getMonthBeginTimeStamp() ..
		"-" .. Time:getMonthOverTimeStamp() .. "   当前处于本月第" .. Time:getDayofMonth() .. "天")
		Logger.logHighlight("==========================================================")
	end

	self.crossDayTS = Time:getDayOverTimeStamp()
	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:getDayOverTimeStamp()
			self.weekOverTime = Time:getWeekOverTimeStamp()
			self.monthOverTime = Time:getMonthOverTimeStamp()
			self.loginCount = self.loginCount + 1
			-- 跨天先刷新活动时间
			DataManager.ActTimeData:refreshActTime(true)
			Logger.logHighlight("跨天===========================================================================")
			if self.crossDayCallbacks then
				for i, info in ipairs(self.crossDayCallbacks) do
					if info.func and info.open then
						info.func()
					end
				end
				-- DataManager.GiftPopData:activeLoginPopGift()
			end
			self:doCrossDay()
			-- 登录天数
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.LOGIN_NUM)
			self:tryOpenModules() -- 开服天数限制的
			EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.CROSS_DAY)
			-- 重置
			if self.timeEveryDayCallbacks then
				for k, v in ipairs(self.timeEveryDayCallbacks) do
					v.triggerToday = false
				end
			end
		end

		-- 每日特定时间消息
		if self.timeEveryDayCallbacks then
			local timeToday = Time:getDayBeginTimeStamp(Time:getServerTime() + 1)
			local passTime = Time:getServerTime() - timeToday
			for k, v in ipairs(self.timeEveryDayCallbacks) do
				if not v.triggerToday and v.func and v.open and passTime > v.time then
					v.triggerToday = true
					v.func()
				end
			end
		end
	end, 1)
end

function DataManager:doCrossDay()
    local delayTime = math.random(1, 10000) / 1000
    SchedulerManager:performWithDelayGlobal(function()
        ModuleManager.MaincityManager:reqPassDay()
    end, delayTime)
end

function DataManager:onCrossDay(info)
    -- if info.activities then
    -- 	self.ActTimeData:init(info.activities) -- 全活动时间, after PlayerData
    -- end
    if info.door then
    	self.DoorData:init(info.door)
    end
    if info.mall_daily_store then
        self.ShopData:refreshDailyShop(info.mall_daily_store)
    end
    if info.elemental_dungeon then
        self.ElementData:init(info.elemental_dungeon)
    end
    if info.dispatch then
        self.DispatchData:init(info.dispatch)
    end
end

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

    if not self.timeEveryDayCallbacks then
        self.timeEveryDayCallbacks = {}
    end

    local timeToday = Time:getDayBeginTimeStamp(Time:getServerTime() + 1)
    local passTime = Time:getServerTime() - timeToday

    for i, info in ipairs(self.timeEveryDayCallbacks) do
        if info.bindId == bindId then
            self.timeEveryDayCallbacks[i].func = func
            self.timeEveryDayCallbacks[i].time = time
            self.timeEveryDayCallbacks[i].triggerToday = passTime > time
            self.timeEveryDayCallbacks[i].open = true
            return
        end
    end

    table.insert(self.timeEveryDayCallbacks, {
        bindId = bindId,
        func = func,
        time = time,
        triggerToday = passTime > time,
        open = true
    })
end

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

    if not self.timeEveryDayCallbacks then
        return
    end
    for i, info in ipairs(self.timeEveryDayCallbacks) do
        if info.bindId == bindId then
            self.timeEveryDayCallbacks[i].open = false
            return
        end
    end
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:setLoginSuccess(success)
	self.loginSuccess = success
end

function DataManager:getLoginSuccess()
	return self.loginSuccess
end

-- 获取登录天数
function DataManager:getLoginCount()
    return self.loginCount or 1
end

return DataManager