-- Teleport failure handling

function Queue._onTeleportFailure(player, status, message)
	Log.Error.Queue("Teleport Failed: %s (%s)", player.Name, message)

	-- Add this player to the latest queue given that they failed out of the previous one
	Queue._addToQueue(player)
end

function Queue._sendStatus(forcePlayer)
	local waitTime = tick() - _lastTeleport
	local playerCount = Queue._currentQueueCount()

	local status = {
		enabled = Queue._timeoutEnabled,
		waiting_for = Conf.min_queue_players - playerCount,
		max_players = Conf.max_queue_players,
		current_players = playerCount,
		time_remaining = math.max(0, Conf.queue_time_limit - (tick() - _lastTeleport)),
	}

	if forcePlayer then
		Broadcast.fireRemoteClient(forcePlayer, "QUEUE_STATUS", status)
	else
		for player, time in pairs(_currentQueue) do
			Broadcast.fireRemoteClient(player, "QUEUE_STATUS", status)
		end
	end
end

function Queue.new(gameStageHandler)
	local self = setmetatable({
		gameStageHandler = gameStageHandler,
	}, Queue)

	for _, weaponInstance in pairs(WeaponsFolder:GetChildren()) do
		weaponInstance:Clone().Parent = StarterPack
	end

	return self
end

function Queue:playerAdded(player)
	Log.Debug.Queue("Added player %s", player.Name)
	Queue._addToQueue(player)

	----
	-- find the humanoid, and detect when it dies
	player.CharacterAdded:Connect(function(character)
		local humanoid = character:FindFirstChild("Humanoid")

		if humanoid then
			local loading = nil

			humanoid.Died:Connect(function()
				if not loading then
					loading = true
					wait(3)
					Util.loadCharacter(player)
				end
			end)
		end
	end)

	--
	Util.loadCharacter(player)
end

function Queue:playerRemoving(player)
	Log.Debug.Queue("Removed player %s", player.Name)
	Queue._removeFromQueue(player)
end

function Queue:initialize()
	Log.Warn.Queue("STARTING")

	self.requestConn = Broadcast.registerHandler("QUEUE_STATUS_REQUEST", function(player)
		Queue._sendStatus(player)
	end)

	if not WeaponsSystem.doingSetup and not WeaponsSystem.didSetup then
		WeaponsSystem.setup()
	end

	DamageHandler.setup()

	for _, player in ipairs(Players:GetPlayers()) do
		self:playerAdded(player)
	end

	TeleportService.TeleportInitFailed:Connect(Queue._onTeleportFailure)

	if not Conf.disable_queue then
		spawn(function()
			while true do
				local waitTime = tick() - _lastTeleport
				local currentCount = Queue._currentQueueCount()

				if not Queue._timeoutEnabled or waitTime < Conf.queue_time_limit or currentCount < Conf.min_queue_players then
					wait(1)

				else
					Log.Debug.Queue("Queue is progressing.  Buckle up for fun.  *MAXIMUM* fun...")

					Queue._teleportQueue()
				end
			end
		end)
	end

	Log.Warn.Queue("STARTED")
end

function Queue:destroy()
	Broadcast.unregisterHandler(self.requestConn)
end
