--!native
--!nonstrict
--!optimize 2
-- Compiled with roblox-ts v2.3.0
local TS = _G[script]
local gcd = TS.import(script, script.Parent.Parent, "utilities", "gcd").gcd
local function getRandomRelativePrime(value, randomLibrary)
	if value == 1 then
		return 1
	end
	local newValue = randomLibrary:NextInteger(1, value - 1)
	if gcd(value, newValue) == 1 then
		return newValue
	end
	repeat
		do
			newValue = randomLibrary:NextInteger(1, value - 1)
		end
	until not (gcd(newValue, value) ~= 1)
	return newValue
end
--[[
	*
	 * ## LiveRandom
	 *
	 * Will loop through all of the numbers in range before repeating.
	 * Does not use any table nor any messy bash, just math. B)
	 *
	 * It first finds a co-prime integer to n between 1 and (n - 1) and constantly increments a running sum.
	 *
	 * - This is guaranteed to touch all of the integers.
	 *
	 * ### Complexity
	 *
	 * - **Storage:** `O(1)`
	 * - **Construction:** `O(log(n))`
	 * - **Get:** `O(1)`
	 *
	 * ### Example
	 *
	 * ```ts
	 * const randomLib = new LiveRandom(1, 10);
	 * print(randomLib.get())
	 * ```
	 
]]
local LiveRandom
do
	LiveRandom = setmetatable({}, {
		__tostring = function()
			return "LiveRandom"
		end,
	})
	LiveRandom.__index = LiveRandom
	function LiveRandom.new(...)
		local self = setmetatable({}, LiveRandom)
		return self:constructor(...) or self
	end
	function LiveRandom:constructor(min, max, seed)
		if seed == nil then
			seed = (os.clock() % 1) * 1e7
		end
		self.rigged = {}
		if max == nil then
			max, min = min, 1
		end
		local range = max - min + 1
		local randomLibrary = Random.new(seed)
		self.last = randomLibrary:NextInteger(1, range)
		self.offset = min - 1
		self.prime = getRandomRelativePrime(range, randomLibrary)
		self.range = range
	end
	function LiveRandom.instanceof(object)
		local _object = object
		local _condition = type(_object) == "table"
		if _condition then
			_condition = getmetatable(object) == LiveRandom
		end
		return _condition
	end
	function LiveRandom:peek()
		local rigged = self.rigged
		local top = rigged[#rigged]
		if top ~= nil then
			return top
		end
		local value = self.last + self.prime
		local range = self.range
		return (if value > range then value - range else value) + self.offset
	end
	function LiveRandom:rig(value)
		local _rigged = self.rigged
		local _value = value
		table.insert(_rigged, _value)
		return self
	end
	function LiveRandom:get()
		local range = self.range
		local rigged = self.rigged
		local _arg0 = #rigged - 1
		-- ▼ Array.unorderedRemove ▼
		local _index = _arg0 + 1
		local _length = #rigged
		local _value = rigged[_index]
		if _value ~= nil then
			rigged[_index] = rigged[_length]
			rigged[_length] = nil
		end
		-- ▲ Array.unorderedRemove ▲
		local riggedValue = _value
		if riggedValue ~= nil then
			return riggedValue
		end
		local value = self.last + self.prime
		local last = if value > range then value - range else value
		self.last = last
		return last + self.offset
	end
end
LiveRandom.__tostring = function()
	return "LiveRandom"
end
return {
	LiveRandom = LiveRandom,
}
