--[[
	Returns a new promise that:
		* is resolved when all input promises resolve
		* is rejected if ANY input promises reject
]]

function Promise.all(...)
	local promises = {...}

	-- check if we've been given a list of promises, not just a variable number of promises
	if type(promises[1]) == "table" and promises[1]._type ~= "Promise" then
		-- we've been given a table of promises already
		promises = promises[1]
	end

	return Promise.new(function(resolve, reject)
		local isResolved = false
		local results = {}
		local totalCompleted = 0
		local function promiseCompleted(index, result)
			if isResolved then
				return
			end

			results[index] = result
			totalCompleted = totalCompleted + 1

			if totalCompleted == #promises then
				resolve(results)
				isResolved = true
			end
		end

		if #promises == 0 then
			resolve(results)
			isResolved = true
			return
		end

		for index, promise in ipairs(promises) do
			-- if a promise isn't resolved yet, add listeners for when it does
			if promise._status == Promise.Status.Started then
				promise:andThen(function(result)
					promiseCompleted(index, result)
				end):catch(function(reason)
					isResolved = true
					reject(reason)
				end)

			-- if a promise is already resolved, move on
			elseif promise._status == Promise.Status.Resolved then
				promiseCompleted(index, unpack(promise._value))

			-- if a promise is rejected, reject the whole chain
			else --if promise._status == Promise.Status.Rejected then
				isResolved = true
				reject(unpack(promise._value))
			end
		end
	end)
end
