-- Events
LoadSceneRemoteEventModule.RequestServerLoadCharacter = script.Parent.Parent.Events.SceneControl.LoadCharacter
LoadSceneRemoteEventModule.FinishedLoadingRemoteEvent = script.Parent.Parent.Events.SceneControl.FinishedLoading
LoadSceneRemoteEventModule.SceneLoaded = script.Parent.Parent.Events.ClientEvents.SceneLoaded

local doesPlayerHavePrimaryPart = function(Player)
	if Player.Character then
		return Player.Character.PrimaryPart
	end
	return false
end

LoadSceneRemoteEventModule.handleRespawnConnection = function(Scene, Player, taskLib)
	if
		not Scene
		or not Scene:FindFirstChild(enums.Scene.Environment)
		or not Scene.Environment:FindFirstChild(enums.Scene.PlayerSpawns)
	then
		return
	end
	while not doesPlayerHavePrimaryPart(Player) do
		taskLib.wait()
	end

	local Spawns = Scene.Environment.PlayerSpawns:GetChildren()
	Player.Character:SetPrimaryPartCFrame(Spawns[math.random(1, #Spawns)].CFrame)
end

LoadSceneRemoteEventModule.LoadSceneRemoteEventFn = function(SceneName, currentLoadSceneTime, taskLib)
	if currentLoadSceneTime < LoadSceneRemoteEventModule.lastCalledLoadSceneTime then
		warn("Attempted to load an older scene on the client: ", SceneName)
		return
	end

	if currentLoadSceneTime == LoadSceneRemoteEventModule.lastCalledLoadSceneTime then
		warn("Attempted to load a scene with same tick time. This should not be happening. Please contact devs")
		warn(SceneName)
		return
	end

	LoadSceneRemoteEventModule.lastCalledLoadSceneTime = currentLoadSceneTime

	local Scene = LoadSceneRemoteEventModule.GetSceneByName(SceneName)
	if not Scene then
		error("Scene not found: " .. SceneName)
	end

	if LoadSceneRemoteEventModule.RespawnConnection then
		LoadSceneRemoteEventModule.RespawnConnection:Disconnect()
		LoadSceneRemoteEventModule.RespawnConnection = nil
	end

	taskLib = if taskLib then taskLib else task
	while state.UnloadingScene do
		taskLib.wait()
	end

	if currentLoadSceneTime < LoadSceneRemoteEventModule.lastCalledLoadSceneTime then
		warn("No longer loading outdated scene: ", SceneName)
		return
	end

	local TempSceneFolder = Instance.new("Folder")
	TempSceneFolder.Name = SceneName
	TempSceneFolder.Parent = workspace:WaitForChild(enums.Scene.ScenesClient)
	LoadSceneRemoteEventModule.DefaultLoadScene(Scene.Environment, TempSceneFolder)

	state.CurrentSceneEnvironmentFolder = TempSceneFolder

	if currentLoadSceneTime < LoadSceneRemoteEventModule.lastCalledLoadSceneTime then
		warn("No longer loading outdated scene: ", SceneName)
		return
	end

	-- Reposition the character to the scene
	-- TODO: Make sure players aren't cframed into eachother
	local Spawns = Scene.Environment.PlayerSpawns:GetChildren()
	local spawnPart = Spawns[math.random(1, #Spawns)]
	local spawnOffset = CFrame.new(
		LoadSceneRemoteEventModule.rng:NextNumber(spawnPart.Size.X * -0.5, spawnPart.Size.X * 0.5),
		0,
		LoadSceneRemoteEventModule.rng:NextNumber(spawnPart.Size.Z * -0.5, spawnPart.Size.Z * 0.5)
	)

	local Player = LoadSceneRemoteEventModule.Player

	if doesPlayerHavePrimaryPart(Player) then
		Player.Character:SetPrimaryPartCFrame(spawnPart.CFrame * spawnOffset)
		Player.Character.PrimaryPart.Anchored = false
	else
		LoadSceneRemoteEventModule.RequestServerLoadCharacter:FireServer()
		while not doesPlayerHavePrimaryPart(Player) do
			taskLib.wait()
		end

		Player.Character:SetPrimaryPartCFrame(spawnPart.CFrame * spawnOffset)
		Player.Character.PrimaryPart.Anchored = false
	end

	if currentLoadSceneTime < LoadSceneRemoteEventModule.lastCalledLoadSceneTime then
		warn("No longer loading outdated scene: ", SceneName)
		return
	end

	LoadSceneRemoteEventModule.RespawnConnection = LoadSceneRemoteEventModule.Player.CharacterAdded:Connect(function()
		LoadSceneRemoteEventModule.handleRespawnConnection(Scene, Player, taskLib)
	end)

	-- Update the lighting
	if
		LoadSceneRemoteEventModule.RunService:IsStudio() and Lighting:GetAttribute(enums.Attribute.UseCurrentLighting)
	then
		warn("USING CURRENT LIGHTING. NOT USING SCENE LIGHTING")
	else
		LoadSceneRemoteEventModule.UpdateLightModule(Scene.Environment.Lighting)
	end

	LoadSceneRemoteEventModule.FinishedLoadingRemoteEvent:FireServer(Player)

	LoadSceneRemoteEventModule.SceneLoaded:Fire(SceneName)
end

return LoadSceneRemoteEventModule