local LoginManager = class("LoginManager", BaseModule)

LoginManager.TRY_LOGIN_TIME = 5
LoginManager.SERVER_LIST = {}
LoginManager.selectIndex = 0

function LoginManager:showLoginUI()
	if not Platform:getIsPublishChannel() then
        self:showTestLoginUI()
        return
    end
	UIManager:showUI("app/module/login/login_ui")
end

function LoginManager:showTestLoginUI()
	UIManager:showUI("app/module/login/test_login_ui")
end

function LoginManager:showMaintenanceNoticeUI(content, openTime)
	local params = {
		content = content,
		openTime = openTime,
	}
	UIManager:showUI("app/module/login/maintenance_notice_ui", params)
end

---- 登录界面资源加载完毕后调用
function LoginManager:loginGame()
	ModuleManager.MaincityManager:firstEnterMainCity()
end

function LoginManager:updateServerTime(serverTime)
    self.serverTime = (serverTime or 0) // 1000
    self.differenceTime = -GFunc.getTickCount()
end

function LoginManager:getServerTime()
    if not self.serverTime then
        return os.time()
    end
    return self.serverTime + (self.differenceTime or 0) + GFunc.getTickCount()
end

function LoginManager:getClientInfo()
	local clientInfo = {}
	local bundleId = Platform:getIdentifier()
	local version = Platform:getClientVersion()
	local device = DeviceHelper:getDeviceModel()
	local deviceId = DeviceHelper:getDeviceId()
	local deviceOS = DeviceHelper:getOSVersion()
	local platform = Platform:getPlatform()
	local accountType = SDKManager.LOGIN_TYPE[LocalData:getInt(LocalData.KEYS.SDK_LOGIN_TYPE, SDKManager.BF_LOGIN_TYPE.GUEST)]
	local ip = LocalData:getLastLoginIp()
	local networkType = DeviceHelper:getNetworkType()
	local language = I18N:getLanguageAndArea()
	local timezone = SDKManager:getTimeZone()
	clientInfo.bundle_id = bundleId
	clientInfo.version = version
	clientInfo.device = device
	clientInfo.device_id = deviceId
	clientInfo.os_version = deviceOS
	clientInfo.platform = platform
	clientInfo.account_type = accountType
	clientInfo.ip = ip
	clientInfo.network_type = networkType
	clientInfo.language = language
	clientInfo.timezone = timezone
	return clientInfo
end

function LoginManager:initSocket()
	local isConnected = NetManager:isConnected(NetManager.MAIN_SOCKET_NAME)
	if EDITOR_MODE then
		Logger.logHighlight("LoginMgr:initSocket:%s", isConnected)
	end
	if not isConnected then
		NetManager:init(
			function()
				self:connectByChannel(
					function()
						if EDITOR_MODE then
							Logger.logHighlight("主链接链接成功")
						end
						self:_login()
					end
				)
			end
		)
	end
end

function LoginManager:connectByChannel(callback, socketName)
	socketName = socketName or NetManager.MAIN_SOCKET_NAME
	local domain
	local port
	if socketName == NetManager.MAIN_SOCKET_NAME then
		local gate = LocalData:getString(LocalData.KEYS.GATE)
		local arr = string.split(gate, ":")
		domain = arr[1]
		port = arr[2]
	else
		domain = NetManager:getChatDomain()
		port = NetManager:getChatPort()
	end
	NetManager:connect(domain, port, function()
		if callback then
			callback()
		end
	end, socketName)
end

function LoginManager:goToLoginScene()
	ModuleManager.BattleManager:clearOnExitScene()
	NetManager:closeAndClear()
	UIManager:backToLoginWithoutLogout()
	UIManager:clearUIPrefabCache()
	DataManager:clear()
end


function LoginManager:_login()
	LocalData:saveEmptySendQueue()

	local skipGuide = nil
	if EDITOR_MODE then
		-- skipGuide = LocalData:getSkipTutorial()
	end
	local clientInfo = self:getClientInfo()
	if EDITOR_MODE then
		print("LoginReq===============================xxxx1")
		for k, v in pairs(clientInfo) do
			print(k, " = ", v)
		end
		print("LoginReq===============================xxxx2")
	end
	local args = {
		client_info = clientInfo,
		skip_guide = skipGuide,
	}
	self:sendMessage(
        ProtoMsgType.FromMsgEnum.LoginReq,
        args,
		{},
        self.loginFinish,
		nil, false
    )
end

function LoginManager:loginFinish(data)
	if data.status == 0 then
		UIManager:clearUIPrefabCache() -- 先清理下缓存
		ConfigManager:preLoadConfig()
		ServerPushManager:initWhenLogin()
		DataManager:initWithServerData(data)

		local data = {}
		data.max_chapter = DataManager.ChapterData:getMaxChapterId()
		data.ads_num = DataManager.PlayerData:getAdCount()
		data.pay_money = DataManager.PlayerData:getTotalPayAmount()
		data.pay_count = DataManager.PlayerData:getPayCount()
		-- data.play_days = DataManager.PlayerData:getLoginDay()
		data.now_version = Platform:getClientVersion()
		data.player_level = DataManager.PlayerData:getLv()
		data.formation, data.formation_lv, data.formation_atk, data.formation_hp = DataManager.FormationData:getStageFormationBIStr()
		data.formation_lv = nil
		data.all_heroes = DataManager.HeroData:getAllHeroesBIStr()
		data.dungeon_progress = DataManager.DungeonData:getDungeonBIStr()
		data.game_version = DataManager.PlayerData:getGameVersion()
		data.is_internal = DataManager.PlayerData:getIsInternal()
		CS.ThinkingAnalytics.ThinkingAnalyticsAPI.UserSet(data)

		if EDITOR_MODE then
			Logger.logHighlight("氪金次数："..tostring(data.pay_count))
		end

		EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.LOGIN_REQ_SUCCESS)
		ModuleManager.MailManager:getMailList(true)
		DataManager:setLoginSuccess(true)
		BIReport:postGameLoginFinish()

		local info = LocalData:getLastLoginInfo()
		BIReport:postAccountLoginFinish(info.type)

		if DataManager:getIsFirstLogin() then
			BIReport:postLvEvent(0, 1)
		end
	else
		DataManager:setLoginSuccess(false)
		local info = LocalData:getLastLoginInfo()
		BIReport:postAccountLoginFailed(info.type, data.err_code)
		if data.err_code == GConst.ERROR_STR.ACCOUNT_BANNED then -- 封号
			local params = {
				content = I18N:getGlobalText(I18N.GlobalConst.SEIZED_DESC_1),
				boxType = GConst.MESSAGE_BOX_TYPE.MB_OK_CANCEL,
				okText = I18N:getGlobalText(I18N.GlobalConst.SEIZED_DESC_2),
				okFunc = function()
					ModuleManager.GameSettingManager:showSupport()
				end,
				cancelText = I18N:getGlobalText(I18N.GlobalConst.SEIZED_DESC_3),
				cancelFunc = function()
					ModuleManager.AccountManager:showDeleteUI(true)
				end
			}
			GFunc.showMessageBox(params)
		end
	end
end

function LoginManager:saveAuthArgs(isReconnect, name)
	local args = LocalData:getLastLoginInfo()
	if name then
		args.type = NetManager.LOGIN_TYPE.ANONYMOUS
		args.id = name
		args.token = nil
		LocalData:setLastLoginName(name)
		LocalData:setLastLoginInfo(args.type, args.id, args.token)
	end

	args.client_info = self:getClientInfo()
	args.reconnect = isReconnect
	-- local sendQueue = LocalData:getSendQueue()
	args.sync =
	{
		pip = GFunc.getArray()
	}

	-- if sendQueue and sendQueue[1] then
	-- 	local ProtoMsgDispatch = require "app/proto/proto_msg_dispatch"
	-- 	local pb = require "pb"
	-- 	for _, info in ipairs(sendQueue) do
	-- 		local curParams = info.params
	-- 		local needAd = false
	-- 		if info.msgName == ProtoMsgType.FromMsgEnum.PipedReq then
	-- 			local msgName = ProtoMsgDispatch:getReqMsgNameByMsgId(curParams.msg_id)
	-- 			if msgName then
	-- 				local fullMsgName = ProtoMsgDispatch:getMsgFullNameByMsgName(msgName)
	-- 				if fullMsgName then
	-- 					if curParams.data and type(curParams.data) == "table" then
	-- 						local ok, pbData = pcall(function()
	-- 							return pb.encode(fullMsgName, curParams.data)
	-- 						end)
	-- 						if ok then
	-- 							needAd = true
	-- 							curParams.data = pbData
	-- 						end
	-- 					end
	-- 				end
	-- 			end
	-- 		end
	-- 		if needAd then
	-- 			table.insert(args.sync.pip, curParams)
	-- 		end
	-- 	end
	-- end

	NetManager:saveAuthArgs(args)
end


function LoginManager:resetServerListStartTime()
	self.accountLoginSuccess = false
	self.connectStartTimes = os.clock()
	self.retryTimes = 0
end

function LoginManager:addServerListCallback(callback)
	self.loginCallback = callback
end

function LoginManager:removeAllLoginData()
	self.loginCallback = nil
	self.versionInfoStr = nil
	self.versionInfo = nil
	-- self.connectStartTimes = nil
	self.retryTimes = 0
end

function LoginManager:getIsNeedHotUpdate()
	local serverVersion = self.versionInfo.version
	local clientVersion = CS.BF.BFMain.Instance.GameLaunchMgr:GetCurrentVersion()
	if serverVersion == nil or serverVersion == "" or clientVersion == nil or clientVersion == "" then
		return true
	end
	return serverVersion ~= clientVersion
end

function LoginManager:showNewVersionFoundMessage()
	local params = {
		content = I18N:getGlobalText(I18N.GlobalConst.NEW_VERSION_FOUND),
		boxType = GConst.MESSAGE_BOX_TYPE.MB_OK,
		okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK),
		okFunc = function()
			local storeUrl = self.versionInfo.store_url
			if storeUrl == nil or storeUrl == "" then
				CS.UnityEngine.Application.Quit()
			else
				CS.UnityEngine.Application.OpenURL(storeUrl)
			end
		end,
	}
	GFunc.showMessageBox(params)
end

function LoginManager:getIsclientLessThanMinVersion()
	local minVersion = self.versionInfo.min_version
	local clientVersion = CS.BF.BFMain.Instance.GameLaunchMgr:GetCurrentVersion()
	if minVersion == nil or minVersion == "" or clientVersion == nil or clientVersion == "" then
		return true
	end
	if minVersion == clientVersion then
		return false
	end

	local update, bigVersion = GFunc.compareVersionThan(minVersion, clientVersion, false)

	return bigVersion or false
end

function LoginManager:checkServerOpen(isRelogin)
	local serverOpenTime = tonumber(self.versionInfo.open_at or 0)
	local clientTime = self:getServerTime()*1000
	if clientTime < serverOpenTime then -- 未开服
		self:showMaintenanceNoticeUI(self.versionInfo.notice, serverOpenTime)
		return
	end

	if EDITOR_MODE or GConst.SKIP_VERSION then
		CS.BF.BFMain.Instance.GameLaunchMgr.LaunchRequester:SetVersionInfo(self.versionInfoStr)
		if self.loginCallback and self.versionInfo then
			self.loginCallback(self.versionInfo.game_urls)
		end
	else
		-- 需要更新整包
		if self:getIsclientLessThanMinVersion() then
			if isRelogin then
				UIManager:showDisconnect()
			else
				self:showNewVersionFoundMessage()
			end
		elseif self:getIsNeedHotUpdate() then -- 需要热更新
			if isRelogin then
				UIManager:showDisconnect()
			else
				Game:destroyAll()
				CS.BF.BFMain.Instance.GameLaunchMgr:LaunchForRelogin(self.versionInfoStr)
			end
		else
			CS.BF.BFMain.Instance.GameLaunchMgr.LaunchRequester:SetVersionInfo(self.versionInfoStr)
			if self.loginCallback then
				self.loginCallback(self.versionInfo.game_urls)
			end
		end
	end
end

function LoginManager:getServerList(isRelogin)
	if self.accountLoginSuccess then
		if self.authSid then
			self:unscheduleGlobal(self.authSid)
			self.authSid = nil
		end
		return
	end
	self.loginCenterUrl = CS.BF.BFPlatform.GetLoginCenterURL()
	self.retryTimes = self.retryTimes + 1

	SDKManager:getServerList(function(isSuccess, data)
		if self.accountLoginSuccess then
			if self.authSid then
				self:unscheduleGlobal(self.authSid)
				self.authSid = nil
			end
			return
		end
		if isSuccess and data and data ~= "" then
			self.versionInfoStr = data
			local jsonData = json.decode(data or "")
			if not jsonData.game_urls[1] then -- 保证服务器列表中必须有一个服务器
				local params = {
					content = I18N:getGlobalText(I18N.GlobalConst.GET_SEVER_ERROR),
					okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK),
					noShowClose = true,
					okFunc = function()
						self:getServerList()
					end,
					boxType = GConst.MESSAGE_BOX_TYPE.MB_OK,
					top = true,
				}
				GFunc.showMessageBox(params)
				return
			end

			UIManager:hideToast()
			-- BIReport:postRequestVersionSuccess(self.loginCenterUrl, (os.clock() - self.connectStartTimes)*1000, self.retryTimes - 1)
			self.accountLoginSuccess = true
			if self.authSid then
				self:unscheduleGlobal(self.authSid)
				self.authSid = nil
			end

			local serverTime = (jsonData.now or 0)
			if serverTime > 0 then
				ModuleManager.LoginManager:updateServerTime(serverTime)
			end
			self.versionInfo = jsonData
			self:checkServerOpen(isRelogin)
		else
			-- BIReport:postRequestVersionFailed(self.loginCenterUrl, (os.clock() - self.connectStartTimes)*1000, self.retryTimes - 1)
			local params = {
				content = I18N:getGlobalText(I18N.GlobalConst.GET_SEVER_ERROR),
				okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK),
				noShowClose = true,
				okFunc = function()
					self:getServerList()
				end,
				boxType = GConst.MESSAGE_BOX_TYPE.MB_OK,
				top = true,
			}
			GFunc.showMessageBox(params)
		end
    end)

	if self.authSid then
		self:unscheduleGlobal(self.authSid)
	end
	self.authSid = self:performWithDelayGlobal(function()
		-- BIReport:postRequestVersionFailed(self.loginCenterUrl, (os.clock() - self.connectStartTimes)*1000, self.retryTimes - 1)
		local params = {
			content = I18N:getGlobalText(I18N.GlobalConst.GET_SEVER_ERROR),
			okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK),
			noShowClose = true,
			okFunc = function()
				self:getServerList()
			end,
			boxType = GConst.MESSAGE_BOX_TYPE.MB_OK,
			top = true,
		}
		GFunc.showMessageBox(params)
	end, 5)
end

function LoginManager:reloginOnReconnectRefuse()
	NetManager:closeAndClear()
	NetManager:tagAuthFailToLogin()
	self:resetServerListStartTime()
	self:addServerListCallback(function(serverList)
		if EDITOR_MODE then
			Logger.logHighlight("-------reloginOnReconnectRefuse-----serverList------------")
			Logger.printTable(serverList)
		end

		local gate = LocalData:getString(LocalData.KEYS.GATE)
		self:refreshServerList(serverList, gate, true)
		self:saveAuthArgs(false)
		self:initSocket()
	end)
	ModuleManager.LoginManager:getServerList(true)
end

function LoginManager:refreshServerList(serverList, lastGate, clearSelectIndex)
	if clearSelectIndex then
		self.selectIndex = nil
	end
	serverList = serverList or {}
	if not self.selectIndex or self.selectIndex <= 0 then
		self.selectIndex = 1
	else
		self.selectIndex = self.selectIndex + 1
	end
	if self.selectIndex > #serverList then
		self.selectIndex = 1
	end
	if lastGate then
		for index, info in ipairs(serverList) do
			if info.url == lastGate then
				self.selectIndex = index
				break
			end
		end
	end
	local defaultUrl = serverList[self.selectIndex].url
	LocalData:setString(LocalData.KEYS.GATE, defaultUrl)
	return serverList
end

return LoginManager