--[=[
	Maps the input brios to the output observables
	@since 3.6.0
	@param project project (Brio<T> | T) -> Brio<U> | U
	@return (source: Observable<Brio<T> | T>) -> Observable<Brio<U>>
]=]

function RxBrioUtils.map(project)
	return Rx.map(function(...)
		local n = select("#", ...)
		local brios = {}
		local args

		if n == 1 then
			if Brio.isBrio(...) then
				table.insert(brios, (...))
				args = (...):GetPackedValues()
			else
				args = {[1] = ...}
			end
		else
			args = {}
			for index, item in pairs({...}) do
				if Brio.isBrio(item) then
					table.insert(brios, item)
					args[index] = item:GetValue() -- we lose data here, but I think this is fine
				else
					args[index] = item
				end
			end
			args.n = n
		end

		local results = table.pack(project(table.unpack(args, 1, args.n)))
		local transformedResults = {}
		for i=1, results.n do
			local item = results[i]
			if Brio.isBrio(item) then
				table.insert(brios, item) -- add all subsequent brios into this table...
				transformedResults[i] = item:GetValue()
			else
				transformedResults[i] = item
			end
		end

		return BrioUtils.first(brios, table.unpack(transformedResults, 1, transformedResults.n))
	end)
end

function RxBrioUtils._mapResult(brio)
	return function(...)
		local n = select("#", ...)
		if n == 0 then
			return BrioUtils.withOtherValues(brio)
		elseif n == 1 then
			if Brio.isBrio(...) then
				return BrioUtils.first({brio, (...)}, (...):GetValue())
			else
				return BrioUtils.withOtherValues(brio, ...)
			end
		else
			local brios = { brio }
			local args = {}

			for index, item in pairs({...}) do
				if Brio.isBrio(item) then
					table.insert(brios, item)
					args[index] = item:GetValue() -- we lose data here, but I think this is fine
				else
					args[index] = item
				end
			end

			return BrioUtils.first(brios, unpack(args, 1, n))
		end
	end
end
