--[=[
	Takes a list of variables and uses them to compute an observable that
	will combine into any value. These variables can be any value, and if they
	can be converted into an Observable, they will be, which will be used to compute
	the value.

	```lua
	local verbState = Blend.State("hi")
	local nameState = Blend.State("alice")

	local computed = Blend.Computed(verbState, nameState, function(verb, name)
		return verb .. " " .. name
	end)

	maid:GiveTask(computed:Subscribe(function(sentence)
		print(sentence)
	end)) --> "hi alice"

	nameState.Value = "bob" --> "hi bob"
	verbState.Value = "bye" --> "bye bob"
	nameState.Value = "alice" --> "bye alice"
	```

	@param ... A series of convertable states, followed by a function at the end.
	@return Observable<T>
]=]

function Blend.Computed(...)
	local values = {...}
	local n = select("#", ...)
	local compute = values[n]

	assert(type(compute) == "function", "Bad compute")

	local args = {}
	for i=1, n - 1 do
		local observable = Blend.toPropertyObservable(values[i])
		if observable then
			args[i] = observable
		else
			args[i] = Rx.of(values[i])
		end
	end

	if #args == 0 then
		-- static value?
		return Observable.new(function(sub)
			sub:Fire(compute())
		end)
	elseif #args == 1 then
		return Rx.map(compute)(args[1])
	else
		return Rx.combineLatest(args)
			:Pipe({
				Rx.map(function(result)
					return compute(unpack(result, 1, n - 1))
				end);
			})
	end
end
