local j={_canSafelyClose=true,_endThread=false,_isRunning=false,_blocks={};_scheduledBlock=nil,_hasScheduledBlockRun=true}local c=require(script.Parent.Logger)local L=game:GetService("\082\117\110\083\101\114\118\105\099\101")local function b()local c=tick()if not j._hasScheduledBlockRun and(j._scheduledBlock~=nil and j._scheduledBlock.deadline<=c)then j._hasScheduledBlockRun=true return j._scheduledBlock else return nil end end local function f()spawn(function()c:d("\083\116\097\114\116\105\110\103 \071\065 \116\104\114\101\097\100")while not j._endThread do j._canSafelyClose=false if#j._blocks~=0 then for j,L in pairs(j._blocks)do local b,f=pcall(L.block)if not b then c:e(f)end end j._blocks={}end local L=b()if L~=nil then local j,b=pcall(L.block)if not j then c:e(b)end end j._canSafelyClose=true wait(1)end c:d("\071\065 \116\104\114\101\097\100 \115\116\111\112\112\101\100")end)game:BindToClose(function()if L:IsStudio()then return end wait(1)if not j._canSafelyClose then repeat wait()until j._canSafelyClose end wait(3)end)end function j.scheduleTimer(L,j,c)if L._endThread then return end if not L._isRunning then L._isRunning=true f()end local b={block=c;deadline=tick()+j}if L._hasScheduledBlockRun then L._scheduledBlock=b L._hasScheduledBlockRun=false end end function j.performTaskOnGAThread(c,j)if c._endThread then return end if not c._isRunning then c._isRunning=true f()end local L={block=j}c._blocks[#c._blocks+1]=L end function j.stopThread(j)j._endThread=true end return j
local threading = {
	_canSafelyClose = true,
	_endThread = false,
	_isRunning = false,
	_blocks = {},
	_scheduledBlock = nil,
	_hasScheduledBlockRun = true,
}

local logger = require(script.Parent.Logger)
local RunService = game:GetService("RunService")

local function getScheduledBlock()
	local now = tick()

	if not threading._hasScheduledBlockRun and threading._scheduledBlock ~= nil and threading._scheduledBlock.deadline <= now then
		threading._hasScheduledBlockRun = true
		return threading._scheduledBlock
	else
		return nil
	end
end

local function run()

	spawn(function()
		logger:d("Starting GA thread")

		while not threading._endThread do
			threading._canSafelyClose = false

			if #threading._blocks ~= 0 then
				for _, b in pairs(threading._blocks) do
					local s, e = pcall(b.block)
					if not s then
						logger:e(e)
					end
				end

				threading._blocks = {}
			end

			local timedBlock = getScheduledBlock()
			if timedBlock ~= nil then
				local s, e = pcall(timedBlock.block)
				if not s then
					logger:e(e)
				end
			end

			threading._canSafelyClose = true
			wait(1)
		end

		logger:d("GA thread stopped")
	end)

	--Safely Close
	game:BindToClose(function()

		-- waiting bug fix to work inside studio
		if RunService:IsStudio() then
			return
		end

		--Give game.Players.PlayerRemoving time to to its thang
		wait(1)

		--Delay
		if not threading._canSafelyClose then
			repeat
				wait()
			until threading._canSafelyClose
		end

		wait(3)
	end)
end

function threading:scheduleTimer(interval, callback)
	if self._endThread then
		return
	end

	if not self._isRunning then
		self._isRunning = true
		run()
	end

	local timedBlock = {
		block = callback,
		deadline = tick() + interval,
	}

	if self._hasScheduledBlockRun then
		self._scheduledBlock = timedBlock
		self._hasScheduledBlockRun = false
	end
end

function threading:performTaskOnGAThread(callback)
	if self._endThread then
		return
	end

	if not self._isRunning then
		self._isRunning = true
		run()
	end

	local timedBlock = {
		block = callback,
	}

	self._blocks[#self._blocks + 1] = timedBlock
end

function threading:stopThread()
	self._endThread = true
end

return threading
