-- This function isn't supported in a testing environment
ServerSceneFramework.GetServerTimeNow = function()
	return workspace:GetServerTimeNow()
end

local hasBeenCalled = false

return function(stubs)
	if hasBeenCalled then
		error("Server Scene Framework has already been called")
		return
	end

	-- Used for testing only
	if stubs then
		for i, v in pairs(stubs) do
			ServerSceneFramework[i] = v
		end
	end

	-- Load Character Remote Event: Load a player's character if primary part isn't detected for new scene
	ServerSceneFramework.handleLoadCharacterRemoteEvent = ServerSceneFramework.LoadCharacterRemoteEventModule
	ServerSceneFramework.LoadCharacterRemoteEvent.OnServerEvent:Connect(
		ServerSceneFramework.handleLoadCharacterRemoteEvent
	)

	-- Load Scene: Loads a scene: Core functionality
	ServerSceneFramework.LoadScene = ServerSceneFramework.LoadSceneModule(ServerSceneFramework)

	-- Orchestrate Scene
	ServerSceneFramework.OrchestrateSceneConnection = ServerSceneFramework.OrchestrateSceneEvent.OnServerEvent:Connect(
		ServerSceneFramework.HandleOrchestrateEvent
	)

	-- Finished Loading Remote Event: Send Configs over for the current scene per player when they finish loading
	ServerSceneFramework.handleFinishedLoadingRemoteEvent = ServerSceneFramework.FinishedLoadingClientModule(
		ServerSceneFramework.SendSceneConfigForPlayer
	)
	ServerSceneFramework.FinishedLoadingRemoteEvent.OnServerEvent:Connect(
		ServerSceneFramework.handleFinishedLoadingRemoteEvent
	)

	-- Get Current Scene Environment: Returns the folder containing respective scene's workspace assets
	ServerSceneFramework.handleGetCurrentSceneEnvironment = ServerSceneFramework.GetCurrentSceneEnvironmentModule
	ServerSceneFramework.GetCurrentSceneEnvironment.OnInvoke = ServerSceneFramework.handleGetCurrentSceneEnvironment
	ServerSceneFramework.GetCurrentServerEnvironmentFromClient.OnServerInvoke =
		ServerSceneFramework.handleGetCurrentSceneEnvironment

	-- Is Loading Scene: Lets people know if SSF is loading a scene
	ServerSceneFramework.handleIsLoadingScene = ServerSceneFramework.IsLoadingSceneModule
	ServerSceneFramework.IsLoadingScene.OnInvoke = ServerSceneFramework.handleIsLoadingScene

	-- Load Scene From List Event: LoadScene, but from the UI when user has permissions
	ServerSceneFramework.handleLoadSceneFromListEvent = ServerSceneFramework.LoadSceneFromListEventModule(
		ServerSceneFramework
	)
	ServerSceneFramework.LoadSceneFromListEvent.OnServerEvent:Connect(ServerSceneFramework.handleLoadSceneFromListEvent)

	-- Load Scene Server: LoadScene programmatically from a server script
	ServerSceneFramework.handleLoadSceneServer = ServerSceneFramework.LoadSceneServerModule(ServerSceneFramework)
	ServerSceneFramework.LoadSceneServer.Event:Connect(ServerSceneFramework.handleLoadSceneServer)

	-- On Player Added: Loads the current scene, if any, for a new player
	ServerSceneFramework.OnPlayerAddedModule(ServerSceneFramework)

	-- Check Folder For Loaded Scenes: Checks the workspace folders for a potentially loaded scene from plugin
	ServerSceneFramework.CheckFolderForLoadedScenes = ServerSceneFramework.CheckFolderForLoadedScenesModule

	-- Find Client Folder: checks for a possibly loaded scene's client folder
	ServerSceneFramework.FindClientFolder = ServerSceneFramework.FindClientFolderModule

	-- Find Server Folder: checks for a possibly loaded scene's server folder
	ServerSceneFramework.FindServerFolder = ServerSceneFramework.FindServerFolderModule

	-- Similar to running on require
	ServerSceneFramework.InitModule(ServerSceneFramework)

	hasBeenCalled = true

	return ServerSceneFramework
end