// Require the core node modules.
var Bluebird = require( "bluebird" );
var chalk = require( "chalk" );


// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //


// Here, we have a series of asynchronous tasks that are required to aggregate some
// result. For the sake of the demo, let's assume that each one of the tasks has to be
// run in serial.
(function someWorkflow( userID ) {

	var promise = Bluebird
		// In this approach, we're still going to pass the running-aggregate down
		// through the promise chain; but, instead of passing it explicitly, we're
		// going to pass it down IMPLICITLY as the THIS binding for all the promise
		// handlers. What this means is that each promise handler can leverage its
		// own this-binding as the reduction.
		// --
		// NOTE: This is a feature of Bluebird, not promises in general.
		.bind({
			userID: userID,
			user: null,
			subscription: null,
			projects: null
		})
		.then( getUser )
		.then( getSubscription )
		.then( getProjects )
		.then(
			function handleResolve() {

				// When outputting the results, notice that we're using the THIS
				// binding as the implicitly-passed running-aggregate.
				console.log( chalk.magenta( "User ID:" ), this.user.id );
				console.log( chalk.magenta( "Subscription ID:" ), this.subscription.id );
				console.log( chalk.magenta( "Project Count:" ), this.projects.length );

			}
		)
		.catch(
			function handleReject( reason ) {

				// This method has access to the "reduction" via "this".

			}
		)
		.finally(
			function handleDone() {

				// This method has access to the "reduction" via "this".

			}
		)
	;

})( 47 ); // Self-executing function block.


// By using the IMPLICITLY-PASSED running aggregate, our workflow steps no longer need
// to be in same closure as the workflow itself. This means that we don't have to
// re-define the steps every time the workflow is executed; but, it does mean that each
// individual step has to be responsible for updating the implicit aggregate.

function getUser() {

	var promise = db_getUser( this.userID ).then(
		( result ) => {

			// Store the result into the running aggregate which is being implicitly
			// passed down through the promise chain.
			this.user = result;

		}
	);

	return( promise );

}

function getSubscription() {

	var promise = db_getSubscription( this.user.accountID ).then(
		( result ) => {

			// Store the result into the running aggregate which is being implicitly
			// passed down through the promise chain.
			this.subscription = result;

		}
	);

	return( promise );

}

function getProjects() {

	var promise = db_getProjects( this.user.id ).then(
		( result ) => {

			// Store the result into the running aggregate which is being implicitly
			// passed down through the promise chain.
			this.projects = result;

		}
	);

	return( promise );

}


// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //


// Mock database access for user.
function db_getUser( id ) {

	var user = {
		id: id,
		accountID: "AFC-9-3S",
		name: "Lisa"
	};

	return( Bluebird.resolve( user ) );

}


// Mock database access for subscription.
function db_getSubscription( accountID ) {

	var subscription = {
		id: 97,
		accountID: accountID,
		startedAt: "2016-02-14"
	};

	return( Bluebird.resolve( subscription ) );

}


// Mock database access for projects.
function db_getProjects( userID ) {

	var projects = [ "Project A", "Project B", "Project C" ];

	return( Bluebird.resolve( projects ) );

}