local H={}H.__index=H function H.LoadProfileAsync(l,H,y,N)y=y or"\070\111\114\099\101\076\111\097\100"if l._profile_template==nil then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \080\114\111\102\105\108\101 \116\101\109\112\108\097\116\101 \110\111\116 \115\101\116 - \080\114\111\102\105\108\101\083\116\111\114\101\058\076\111\097\100\080\114\111\102\105\108\101\065\115\121\110\099\040\041 \108\111\099\107\101\100 \102\111\114 \116\104\105\115 \080\114\111\102\105\108\101\083\116\111\114\101")end if type(H)~="\115\116\114\105\110\103"then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \112\114\111\102\105\108\101\095\107\101\121 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103")elseif string.len(H)==0 then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \112\114\111\102\105\108\101\095\107\101\121")end if type(y)~="\102\117\110\099\116\105\111\110"and(y~="\070\111\114\099\101\076\111\097\100"and y~="\083\116\101\097\108")then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \110\111\116\095\114\101\108\101\097\115\101\100\095\104\097\110\100\108\101\114")end if ProfileService.ServiceLocked==true then return nil end WaitForPendingProfileStore(l)local b=N==UseMockTag for y,N in ipairs(ActiveProfileStores)do if N._profile_store_lookup==l._profile_store_lookup then local y=b==true and N._mock_loaded_profiles or N._loaded_profiles if y[H]~=nil then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \080\114\111\102\105\108\101 "..(IdentifyProfile(l._profile_store_name,l._profile_store_scope,H).." \105\115 \097\108\114\101\097\100\121 \108\111\097\100\101\100 \105\110 \116\104\105\115 \115\101\115\115\105\111\110"))end end end ActiveProfileLoadJobs=ActiveProfileLoadJobs+1 local v=y=="\070\111\114\099\101\076\111\097\100"local P=0 local t=v local I=false local z=y=="\083\116\101\097\108"while ProfileService.ServiceLocked==false do local N=b==true and l._mock_profile_load_jobs or l._profile_load_jobs local j,T local S=LoadIndex+1 LoadIndex=S local Q=N[H]if Q~=nil then Q[1]=S while Q[2]==nil do task.wait()end if Q[1]==S then j,T=table.unpack(Q[2])N[H]=nil else ActiveProfileLoadJobs=ActiveProfileLoadJobs-1 return nil end else Q={S,nil}N[H]=Q Q[2]=table.pack(StandardProfileUpdateAsyncDataStore(l,H,{ExistingProfileHandle=function(H)if ProfileService.ServiceLocked==false then local y=H.MetaData.ActiveSession local N=H.MetaData.ForceLoadSession if y==nil then H.MetaData.ActiveSession={PlaceId;JobId}H.MetaData.ForceLoadSession=nil elseif type(y)=="\116\097\098\108\101"then if IsThisSession(y)==false then local y=H.MetaData.LastUpdate if y~=nil then if os.time()-y>SETTINGS.AssumeDeadSessionLock then H.MetaData.ActiveSession={PlaceId,JobId}H.MetaData.ForceLoadSession=nil return end end if I==true or z==true then local y=false if N~=nil then y=IsThisSession(N)end if y==true or z==true then H.MetaData.ActiveSession={PlaceId;JobId}H.MetaData.ForceLoadSession=nil end elseif t==true then H.MetaData.ForceLoadSession={PlaceId;JobId}end else H.MetaData.ForceLoadSession=nil end end end end;MissingProfileHandle=function(H)H.Data=DeepCopyTable(l._profile_template)H.MetaData={ProfileCreateTime=os.time(),SessionLoadCount=0,ActiveSession={PlaceId;JobId},ForceLoadSession=nil;MetaTags={}}end,EditProfile=function(H)if ProfileService.ServiceLocked==false then local y=H.MetaData.ActiveSession if y~=nil and IsThisSession(y)==true then H.MetaData.SessionLoadCount=H.MetaData.SessionLoadCount+1 H.MetaData.LastUpdate=os.time()end end end},b))if Q[1]==S then j,T=table.unpack(Q[2])N[H]=nil else ActiveProfileLoadJobs=ActiveProfileLoadJobs-1 return nil end end if j~=nil and T~=nil then local N=j.MetaData.ActiveSession if type(N)=="\116\097\098\108\101"then if IsThisSession(N)==true then j.MetaData.MetaTagsLatest=DeepCopyTable(j.MetaData.MetaTags)local y={_updates_latest=j.GlobalUpdates;_pending_update_lock={};_pending_update_clear={},_new_active_update_listeners=Madwork.NewScriptSignal(),_new_locked_update_listeners=Madwork.NewScriptSignal();_profile=nil}setmetatable(y,GlobalUpdates)local N={Data=j.Data;MetaData=j.MetaData,MetaTagsUpdated=Madwork.NewScriptSignal();RobloxMetaData=j.RobloxMetaData or{};UserIds=j.UserIds or{};KeyInfo=T;KeyInfoUpdated=Madwork.NewScriptSignal(),GlobalUpdates=y,_profile_store=l,_profile_key=H;_release_listeners=Madwork.NewScriptSignal();_hop_ready_listeners=Madwork.NewScriptSignal();_hop_ready=false;_load_timestamp=os.clock(),_is_user_mock=b}setmetatable(N,Profile)y._profile=N if next(l._loaded_profiles)==nil and next(l._mock_loaded_profiles)==nil then table.insert(ActiveProfileStores,l)end if b==true then l._mock_loaded_profiles[H]=N else l._loaded_profiles[H]=N end AddProfileToAutoSave(N)if ProfileService.ServiceLocked==true then SaveProfileAsync(N,true)N=nil end ActiveProfileLoadJobs=ActiveProfileLoadJobs-1 return N else if v==true then local H=j.MetaData.ForceLoadSession local y=false if H~=nil then y=IsThisSession(H)end if y==true then if t==false then P=P+1 if P==SETTINGS.ForceLoadMaxSteps then I=true end end task.wait()else ActiveProfileLoadJobs=ActiveProfileLoadJobs-1 return nil end t=false elseif z==true then task.wait()else local b=y(N[1],N[2])if b=="\082\101\112\101\097\116"then task.wait()elseif b=="\067\097\110\099\101\108"then ActiveProfileLoadJobs=ActiveProfileLoadJobs-1 return nil elseif b=="\070\111\114\099\101\076\111\097\100"then v=true t=true task.wait()elseif b=="\083\116\101\097\108"then z=true task.wait()else error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \114\101\116\117\114\110 \102\114\111\109 \110\111\116\095\114\101\108\101\097\115\101\100\095\104\097\110\100\108\101\114 \040\""..(tostring(b)..("\"\041\040"..(type(b)..("\041\059"..("\n"..(IdentifyProfile(l._profile_store_name,l._profile_store_scope,H)..(" \084\114\097\099\101\098\097\099\107\058\n"..debug.traceback()))))))))end end end else ActiveProfileLoadJobs=ActiveProfileLoadJobs-1 return nil end else task.wait()end end ActiveProfileLoadJobs=ActiveProfileLoadJobs-1 return nil end function H.GlobalUpdateProfileAsync(l,H,y,N)if type(H)~="\115\116\114\105\110\103"or string.len(H)==0 then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \112\114\111\102\105\108\101\095\107\101\121")end if type(y)~="\102\117\110\099\116\105\111\110"then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \117\112\100\097\116\101\095\104\097\110\100\108\101\114")end if ProfileService.ServiceLocked==true then return nil end WaitForPendingProfileStore(l)while ProfileService.ServiceLocked==false do local b=StandardProfileUpdateAsyncDataStore(l,H,{ExistingProfileHandle=nil,MissingProfileHandle=nil,EditProfile=function(H)local N={_updates_latest=H.GlobalUpdates,_update_handler_mode=true}setmetatable(N,GlobalUpdates)y(N)end},N==UseMockTag)CustomWriteQueueMarkForCleanup(l._profile_store_lookup,H)if b~=nil then local H={_updates_latest=b.GlobalUpdates}setmetatable(H,GlobalUpdates)return H else task.wait()end end return nil end function H.ViewProfileAsync(l,H,y,N)if type(H)~="\115\116\114\105\110\103"or string.len(H)==0 then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \112\114\111\102\105\108\101\095\107\101\121")end if ProfileService.ServiceLocked==true then return nil end WaitForPendingProfileStore(l)if y~=nil and(N==UseMockTag or UseMockDataStore==true)then return nil end while ProfileService.ServiceLocked==false do local b,v=StandardProfileUpdateAsyncDataStore(l,H,{ExistingProfileHandle=nil;MissingProfileHandle=function(H)H.Data=DeepCopyTable(l._profile_template)H.MetaData={ProfileCreateTime=os.time(),SessionLoadCount=0,ActiveSession=nil;ForceLoadSession=nil,MetaTags={}}end;EditProfile=nil},N==UseMockTag,true,y)CustomWriteQueueMarkForCleanup(l._profile_store_lookup,H)if b~=nil then if v==nil then return nil end local y={_updates_latest=b.GlobalUpdates,_profile=nil}setmetatable(y,GlobalUpdates)local N={Data=b.Data;MetaData=b.MetaData;MetaTagsUpdated=Madwork.NewScriptSignal();RobloxMetaData=b.RobloxMetaData or{};UserIds=b.UserIds or{},KeyInfo=v;KeyInfoUpdated=Madwork.NewScriptSignal();GlobalUpdates=y;_profile_store=l,_profile_key=H;_view_mode=true;_load_timestamp=os.clock()}setmetatable(N,Profile)y._profile=N return N else task.wait()end end return nil end function H.ProfileVersionQuery(v,H,y,N,l,b)if type(H)~="\115\116\114\105\110\103"or string.len(H)==0 then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \112\114\111\102\105\108\101\095\107\101\121")end if ProfileService.ServiceLocked==true then return setmetatable({},ProfileVersionQuery)end WaitForPendingProfileStore(v)if b==UseMockTag or UseMockDataStore==true then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \058\080\114\111\102\105\108\101\086\101\114\115\105\111\110\081\117\101\114\121\040\041 \105\115 \110\111\116 \115\117\112\112\111\114\116\101\100 \105\110 \109\111\099\107 \109\111\100\101")end if y~=nil and(typeof(y)~="\069\110\117\109\073\116\101\109"or y.EnumType~=Enum.SortDirection)then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \115\111\114\116\095\100\105\114\101\099\116\105\111\110 \040"..(tostring(y).."\041"))end if N~=nil and(typeof(N)~="\068\097\116\101\084\105\109\101"and typeof(N)~="\110\117\109\098\101\114")then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \109\105\110\095\100\097\116\101 \040"..(tostring(N).."\041"))end if l~=nil and(typeof(l)~="\068\097\116\101\084\105\109\101"and typeof(l)~="\110\117\109\098\101\114")then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \109\097\120\095\100\097\116\101 \040"..(tostring(l).."\041"))end N=typeof(N)=="\068\097\116\101\084\105\109\101"and N.UnixTimestampMillis or N l=typeof(l)=="\068\097\116\101\084\105\109\101"and l.UnixTimestampMillis or l local P={_profile_store=v,_profile_key=H;_sort_direction=y,_min_date=N;_max_date=l,_query_pages=nil;_query_index=0;_query_failure=false;_is_query_yielded=false,_query_queue={}}setmetatable(P,ProfileVersionQuery)return P end function H.WipeProfileAsync(N,H,y)if type(H)~="\115\116\114\105\110\103"or string.len(H)==0 then error("\091\080\114\111\102\105\108\101\083\101\114\118\105\099\101\093\058 \073\110\118\097\108\105\100 \112\114\111\102\105\108\101\095\107\101\121")end if ProfileService.ServiceLocked==true then return false end WaitForPendingProfileStore(N)local l=false if y==UseMockTag then local y=UserMockDataStore[N._profile_store_lookup]if y~=nil then y[H]=nil end l=true task.wait()elseif UseMockDataStore==true then local y=MockDataStore[N._profile_store_lookup]if y~=nil then y[H]=nil end l=true task.wait()else l=pcall(function()N._global_data_store:RemoveAsync(H)end)end CustomWriteQueueMarkForCleanup(N._profile_store_lookup,H)return l end


local ProfileStore = {
	--[[
		Mock = {},
	
		_profile_store_name = "", -- [string] -- DataStore name
		_profile_store_scope = nil, -- [string] or [nil] -- DataStore scope
		_profile_store_lookup = "", -- [string] -- _profile_store_name .. "\0" .. (_profile_store_scope or "")
		
		_profile_template = {}, -- [table]
		_global_data_store = global_data_store, -- [GlobalDataStore] -- Object returned by DataStoreService:GetDataStore(_profile_store_name)
		
		_loaded_profiles = {[profile_key] = Profile, ...},
		_profile_load_jobs = {[profile_key] = {load_id, loaded_data}, ...},
		
		_mock_loaded_profiles = {[profile_key] = Profile, ...},
		_mock_profile_load_jobs = {[profile_key] = {load_id, loaded_data}, ...},
	--]]
}
ProfileStore.__index = ProfileStore

function ProfileStore:LoadProfileAsync(profile_key, not_released_handler, _use_mock) --> [Profile / nil] not_released_handler(place_id, game_job_id)

	not_released_handler = not_released_handler or "ForceLoad"

	if self._profile_template == nil then
		error("[ProfileService]: Profile template not set - ProfileStore:LoadProfileAsync() locked for this ProfileStore")
	end
	if type(profile_key) ~= "string" then
		error("[ProfileService]: profile_key must be a string")
	elseif string.len(profile_key) == 0 then
		error("[ProfileService]: Invalid profile_key")
	end
	if type(not_released_handler) ~= "function" and not_released_handler ~= "ForceLoad" and not_released_handler ~= "Steal" then
		error("[ProfileService]: Invalid not_released_handler")
	end

	if ProfileService.ServiceLocked == true then
		return nil
	end

	WaitForPendingProfileStore(self)

	local is_user_mock = _use_mock == UseMockTag

	-- Check if profile with profile_key isn't already loaded in this session:
	for _, profile_store in ipairs(ActiveProfileStores) do
		if profile_store._profile_store_lookup == self._profile_store_lookup then
			local loaded_profiles = is_user_mock == true and profile_store._mock_loaded_profiles or profile_store._loaded_profiles
			if loaded_profiles[profile_key] ~= nil then
				error("[ProfileService]: Profile " .. IdentifyProfile(self._profile_store_name, self._profile_store_scope, profile_key) .. " is already loaded in this session")
				-- Are you using Profile:Release() properly?
			end
		end
	end

	ActiveProfileLoadJobs = ActiveProfileLoadJobs + 1
	local force_load = not_released_handler == "ForceLoad"
	local force_load_steps = 0
	local request_force_load = force_load -- First step of ForceLoad
	local steal_session = false -- Second step of ForceLoad
	local aggressive_steal = not_released_handler == "Steal" -- Developer invoked steal
	while ProfileService.ServiceLocked == false do
		-- Load profile:
		-- SPECIAL CASE - If LoadProfileAsync is called for the same key before another LoadProfileAsync finishes,
		-- yoink the DataStore return for the new call. The older call will return nil. This would prevent very rare
		-- game breaking errors where a player rejoins the server super fast.
		local profile_load_jobs = is_user_mock == true and self._mock_profile_load_jobs or self._profile_load_jobs
		local loaded_data, key_info
		local load_id = LoadIndex + 1
		LoadIndex = load_id
		local profile_load_job = profile_load_jobs[profile_key] -- {load_id, {loaded_data, key_info} or nil}
		if profile_load_job ~= nil then
			profile_load_job[1] = load_id -- Yoink load job
			while profile_load_job[2] == nil do -- Wait for job to finish
				task.wait()
			end
			if profile_load_job[1] == load_id then -- Load job hasn't been double-yoinked
				loaded_data, key_info = table.unpack(profile_load_job[2])
				profile_load_jobs[profile_key] = nil
			else
				ActiveProfileLoadJobs = ActiveProfileLoadJobs - 1
				return nil
			end
		else
			profile_load_job = {load_id, nil}
			profile_load_jobs[profile_key] = profile_load_job
			profile_load_job[2] = table.pack(StandardProfileUpdateAsyncDataStore(
				self,
				profile_key,
				{
					ExistingProfileHandle = function(latest_data)
						if ProfileService.ServiceLocked == false then
							local active_session = latest_data.MetaData.ActiveSession
							local force_load_session = latest_data.MetaData.ForceLoadSession
							-- IsThisSession(active_session)
							if active_session == nil then
								latest_data.MetaData.ActiveSession = {PlaceId, JobId}
								latest_data.MetaData.ForceLoadSession = nil
							elseif type(active_session) == "table" then
								if IsThisSession(active_session) == false then
									local last_update = latest_data.MetaData.LastUpdate
									if last_update ~= nil then
										if os.time() - last_update > SETTINGS.AssumeDeadSessionLock then
											latest_data.MetaData.ActiveSession = {PlaceId, JobId}
											latest_data.MetaData.ForceLoadSession = nil
											return
										end
									end
									if steal_session == true or aggressive_steal == true then
										local force_load_uninterrupted = false
										if force_load_session ~= nil then
											force_load_uninterrupted = IsThisSession(force_load_session)
										end
										if force_load_uninterrupted == true or aggressive_steal == true then
											latest_data.MetaData.ActiveSession = {PlaceId, JobId}
											latest_data.MetaData.ForceLoadSession = nil
										end
									elseif request_force_load == true then
										latest_data.MetaData.ForceLoadSession = {PlaceId, JobId}
									end
								else
									latest_data.MetaData.ForceLoadSession = nil
								end
							end
						end
					end,
					MissingProfileHandle = function(latest_data)
						latest_data.Data = DeepCopyTable(self._profile_template)
						latest_data.MetaData = {
							ProfileCreateTime = os.time(),
							SessionLoadCount = 0,
							ActiveSession = {PlaceId, JobId},
							ForceLoadSession = nil,
							MetaTags = {},
						}
					end,
					EditProfile = function(latest_data)
						if ProfileService.ServiceLocked == false then
							local active_session = latest_data.MetaData.ActiveSession
							if active_session ~= nil and IsThisSession(active_session) == true then
								latest_data.MetaData.SessionLoadCount = latest_data.MetaData.SessionLoadCount + 1
								latest_data.MetaData.LastUpdate = os.time()
							end
						end
					end,
				},
				is_user_mock
			))
			if profile_load_job[1] == load_id then -- Load job hasn't been yoinked
				loaded_data, key_info = table.unpack(profile_load_job[2])
				profile_load_jobs[profile_key] = nil
			else
				ActiveProfileLoadJobs = ActiveProfileLoadJobs - 1
				return nil -- Load job yoinked
			end
		end
		-- Handle load_data:
		if loaded_data ~= nil and key_info ~= nil then
			local active_session = loaded_data.MetaData.ActiveSession
			if type(active_session) == "table" then
				if IsThisSession(active_session) == true then
					-- Special component in MetaTags:
					loaded_data.MetaData.MetaTagsLatest = DeepCopyTable(loaded_data.MetaData.MetaTags)
					-- Case #1: Profile is now taken by this session:
					-- Create Profile object:
					local global_updates_object = {
						_updates_latest = loaded_data.GlobalUpdates,
						_pending_update_lock = {},
						_pending_update_clear = {},

						_new_active_update_listeners = Madwork.NewScriptSignal(),
						_new_locked_update_listeners = Madwork.NewScriptSignal(),

						_profile = nil,
					}
					setmetatable(global_updates_object, GlobalUpdates)
					local profile = {
						Data = loaded_data.Data,
						MetaData = loaded_data.MetaData,
						MetaTagsUpdated = Madwork.NewScriptSignal(),

						RobloxMetaData = loaded_data.RobloxMetaData or {},
						UserIds = loaded_data.UserIds or {},
						KeyInfo = key_info,
						KeyInfoUpdated = Madwork.NewScriptSignal(),

						GlobalUpdates = global_updates_object,

						_profile_store = self,
						_profile_key = profile_key,

						_release_listeners = Madwork.NewScriptSignal(),
						_hop_ready_listeners = Madwork.NewScriptSignal(),
						_hop_ready = false,

						_load_timestamp = os.clock(),

						_is_user_mock = is_user_mock,
					}
					setmetatable(profile, Profile)
					global_updates_object._profile = profile
					-- Referencing Profile object in ProfileStore:
					if next(self._loaded_profiles) == nil and next(self._mock_loaded_profiles) == nil then -- ProfileStore object was inactive
						table.insert(ActiveProfileStores, self)
					end
					if is_user_mock == true then
						self._mock_loaded_profiles[profile_key] = profile
					else
						self._loaded_profiles[profile_key] = profile
					end
					-- Adding profile to AutoSaveList;
					AddProfileToAutoSave(profile)
					-- Special case - finished loading profile, but session is shutting down:
					if ProfileService.ServiceLocked == true then
						SaveProfileAsync(profile, true) -- Release profile and yield until the DataStore call is finished
						profile = nil -- nil will be returned by this call
					end
					-- Return Profile object:
					ActiveProfileLoadJobs = ActiveProfileLoadJobs - 1
					return profile
				else
					-- Case #2: Profile is taken by some other session:
					if force_load == true then
						local force_load_session = loaded_data.MetaData.ForceLoadSession
						local force_load_uninterrupted = false
						if force_load_session ~= nil then
							force_load_uninterrupted = IsThisSession(force_load_session)
						end
						if force_load_uninterrupted == true then
							if request_force_load == false then
								force_load_steps = force_load_steps + 1
								if force_load_steps == SETTINGS.ForceLoadMaxSteps then
									steal_session = true
								end
							end
							task.wait() -- Overload prevention
						else
							-- Another session tried to force load this profile:
							ActiveProfileLoadJobs = ActiveProfileLoadJobs - 1
							return nil
						end
						request_force_load = false -- Only request a force load once
					elseif aggressive_steal == true then
						task.wait() -- Overload prevention
					else
						local handler_result = not_released_handler(active_session[1], active_session[2])
						if handler_result == "Repeat" then
							task.wait() -- Overload prevention
						elseif handler_result == "Cancel" then
							ActiveProfileLoadJobs = ActiveProfileLoadJobs - 1
							return nil
						elseif handler_result == "ForceLoad" then
							force_load = true
							request_force_load = true
							task.wait() -- Overload prevention
						elseif handler_result == "Steal" then
							aggressive_steal = true
							task.wait() -- Overload prevention
						else
							error(
								"[ProfileService]: Invalid return from not_released_handler (\"" .. tostring(handler_result) .. "\")(" .. type(handler_result) .. ");" ..
									"\n" .. IdentifyProfile(self._profile_store_name, self._profile_store_scope, profile_key) ..
									" Traceback:\n" .. debug.traceback()
							)
						end
					end
				end
			else
				ActiveProfileLoadJobs = ActiveProfileLoadJobs - 1
				return nil -- In this scenario it is likely the ProfileService.ServiceLocked flag was raised
			end
		else
			task.wait() -- Overload prevention
		end
	end
	ActiveProfileLoadJobs = ActiveProfileLoadJobs - 1
	return nil -- If loop breaks return nothing
end

function ProfileStore:GlobalUpdateProfileAsync(profile_key, update_handler, _use_mock) --> [GlobalUpdates / nil] (update_handler(GlobalUpdates))
	if type(profile_key) ~= "string" or string.len(profile_key) == 0 then
		error("[ProfileService]: Invalid profile_key")
	end
	if type(update_handler) ~= "function" then
		error("[ProfileService]: Invalid update_handler")
	end

	if ProfileService.ServiceLocked == true then
		return nil
	end

	WaitForPendingProfileStore(self)

	while ProfileService.ServiceLocked == false do
		-- Updating profile:
		local loaded_data = StandardProfileUpdateAsyncDataStore(
			self,
			profile_key,
			{
				ExistingProfileHandle = nil,
				MissingProfileHandle = nil,
				EditProfile = function(latest_data)
					-- Running update_handler:
					local global_updates_object = {
						_updates_latest = latest_data.GlobalUpdates,
						_update_handler_mode = true,
					}
					setmetatable(global_updates_object, GlobalUpdates)
					update_handler(global_updates_object)
				end,
			},
			_use_mock == UseMockTag
		)
		CustomWriteQueueMarkForCleanup(self._profile_store_lookup, profile_key)
		-- Handling loaded_data:
		if loaded_data ~= nil then
			-- Return GlobalUpdates object (Update successful):
			local global_updates_object = {
				_updates_latest = loaded_data.GlobalUpdates,
			}
			setmetatable(global_updates_object, GlobalUpdates)
			return global_updates_object
		else
			task.wait() -- Overload prevention
		end
	end
	return nil -- Return nothing (Update unsuccessful)
end

function ProfileStore:ViewProfileAsync(profile_key, version, _use_mock) --> [Profile / nil]
	if type(profile_key) ~= "string" or string.len(profile_key) == 0 then
		error("[ProfileService]: Invalid profile_key")
	end

	if ProfileService.ServiceLocked == true then
		return nil
	end

	WaitForPendingProfileStore(self)

	if version ~= nil and (_use_mock == UseMockTag or UseMockDataStore == true) then
		return nil -- No version support in mock mode
	end

	while ProfileService.ServiceLocked == false do
		-- Load profile:
		local loaded_data, key_info = StandardProfileUpdateAsyncDataStore(
			self,
			profile_key,
			{
				ExistingProfileHandle = nil,
				MissingProfileHandle = function(latest_data)
					latest_data.Data = DeepCopyTable(self._profile_template)
					latest_data.MetaData = {
						ProfileCreateTime = os.time(),
						SessionLoadCount = 0,
						ActiveSession = nil,
						ForceLoadSession = nil,
						MetaTags = {},
					}
				end,
				EditProfile = nil,
			},
			_use_mock == UseMockTag,
			true, -- Use :GetAsync()
			version -- DataStore key version
		)
		CustomWriteQueueMarkForCleanup(self._profile_store_lookup, profile_key)
		-- Handle load_data:
		if loaded_data ~= nil then
			if key_info == nil then
				return nil -- Load was successful, but the key was empty - return no profile object
			end
			-- Create Profile object:
			local global_updates_object = {
				_updates_latest = loaded_data.GlobalUpdates, -- {0, {}}
				_profile = nil,
			}
			setmetatable(global_updates_object, GlobalUpdates)
			local profile = {
				Data = loaded_data.Data,
				MetaData = loaded_data.MetaData,
				MetaTagsUpdated = Madwork.NewScriptSignal(),

				RobloxMetaData = loaded_data.RobloxMetaData or {},
				UserIds = loaded_data.UserIds or {},
				KeyInfo = key_info,
				KeyInfoUpdated = Madwork.NewScriptSignal(),

				GlobalUpdates = global_updates_object,

				_profile_store = self,
				_profile_key = profile_key,

				_view_mode = true,

				_load_timestamp = os.clock(),
			}
			setmetatable(profile, Profile)
			global_updates_object._profile = profile
			-- Returning Profile object:
			return profile
		else
			task.wait() -- Overload prevention
		end
	end
	return nil -- If loop breaks return nothing
end

function ProfileStore:ProfileVersionQuery(profile_key, sort_direction, min_date, max_date, _use_mock) --> [ProfileVersionQuery]
	if type(profile_key) ~= "string" or string.len(profile_key) == 0 then
		error("[ProfileService]: Invalid profile_key")
	end

	if ProfileService.ServiceLocked == true then
		return setmetatable({}, ProfileVersionQuery) -- Silently fail :Next() requests
	end

	WaitForPendingProfileStore(self)

	if _use_mock == UseMockTag or UseMockDataStore == true then
		error("[ProfileService]: :ProfileVersionQuery() is not supported in mock mode")
	end

	-- Type check:
	if sort_direction ~= nil and (typeof(sort_direction) ~= "EnumItem"
		or sort_direction.EnumType ~= Enum.SortDirection) then
		error("[ProfileService]: Invalid sort_direction (" .. tostring(sort_direction) .. ")")
	end

	if min_date ~= nil and typeof(min_date) ~= "DateTime" and typeof(min_date) ~= "number" then
		error("[ProfileService]: Invalid min_date (" .. tostring(min_date) .. ")")
	end

	if max_date ~= nil and typeof(max_date) ~= "DateTime" and typeof(max_date) ~= "number" then
		error("[ProfileService]: Invalid max_date (" .. tostring(max_date) .. ")")
	end

	min_date = typeof(min_date) == "DateTime" and min_date.UnixTimestampMillis or min_date
	max_date = typeof(max_date) == "DateTime" and max_date.UnixTimestampMillis or max_date

	local profile_version_query = {
		_profile_store = self,
		_profile_key = profile_key,
		_sort_direction = sort_direction,
		_min_date = min_date,
		_max_date = max_date,

		_query_pages = nil,
		_query_index = 0,
		_query_failure = false,

		_is_query_yielded = false,
		_query_queue = {},
	}
	setmetatable(profile_version_query, ProfileVersionQuery)

	return profile_version_query

end

function ProfileStore:WipeProfileAsync(profile_key, _use_mock) --> is_wipe_successful [bool]
	if type(profile_key) ~= "string" or string.len(profile_key) == 0 then
		error("[ProfileService]: Invalid profile_key")
	end

	if ProfileService.ServiceLocked == true then
		return false
	end

	WaitForPendingProfileStore(self)

	local wipe_status = false

	if _use_mock == UseMockTag then -- Used when the profile is accessed through ProfileStore.Mock
		local mock_data_store = UserMockDataStore[self._profile_store_lookup]
		if mock_data_store ~= nil then
			mock_data_store[profile_key] = nil
		end
		wipe_status = true
		task.wait() -- Simulate API call yield
	elseif UseMockDataStore == true then -- Used when API access is disabled
		local mock_data_store = MockDataStore[self._profile_store_lookup]
		if mock_data_store ~= nil then
			mock_data_store[profile_key] = nil
		end
		wipe_status = true
		task.wait() -- Simulate API call yield
	else
		wipe_status = pcall(function()
			self._global_data_store:RemoveAsync(profile_key)
		end)
	end

	CustomWriteQueueMarkForCleanup(self._profile_store_lookup, profile_key)

	return wipe_status
end
