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

// Try calling the "database method" with various combinations of inputs. The key here
// is to notice that falsey values, such as "0", neither include the associated
// conditional SQL statements; and that the falsey value itself doesn't get included
// in the result (since the "embed" tag will ignore values that aren't strings).

header( "getUsers()", "Excluding all conditional statements." );
format( getUsers() );

header( "getUsers( 0 )", "Excluding all conditionals, but using a non-empty falsey." );
format( getUsers( 0 ) );

header( "getUsers( 4 )", "Including the user constraint." );
format( getUsers( 4 ) );

header( "getUsers( 4, 16, false )", "Including the user and team constraint, but not an active constraint." );
format( getUsers( 4, 16, false ) );

header( "getUsers( 4, 16, true )", "Including all conditional, nested statements." );
format( getUsers( 4, 16, true ) );


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


// I get the given users, filtered by the optional userID and teamID.
// --
// NOTE: Obviously, this function doesn't actually perform any query - for the demo,
// it is just constructing the SQL statement that would be used.
function getUsers( userID, teamID, ensureActiveMembership ) {

	var statement = embed`

		SELECT
			u.id,
			u.name,
			u.email
		FROM
			user u

		${ userID && teamID && embed`

			INNER JOIN
				team_membership tm
			ON
				(
						tm.userID = :userID
					AND
						tm.teamID = :teamID

					${ ensureActiveMembership && embed`

						AND
							tm.endedAt IS NULL

					`}
				)

		`}

		${ userID && ! teamID && embed`

			WHERE
				userID = :userID

		`}
		;

	`;

	return( statement );

}


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


// I construct the SQL statement by zipping the given template strings and values
// together. Only string values with non-space characters will be included in the
// result (so that falseys don't get included).
// --
// CAUTION: This function is intended to be used with a TAGGED TEMPLATE literal.
function embed() {

	var strings = arguments[ 0 ];
	var values = Array.prototype.slice.call( arguments, 1 );
	var results = [];

	for ( var i = 0 ; i < strings.length ; i++ ) {

		// Make sure the string part isn't just spaces and tabs.
		if ( isEmbeddable( strings[ i ] ) ) {

			results.push( strings[ i ] );

		}

		// Make sure the value is a String and more than just spaces and tabs.
		// --
		// NOTE: There may not be a value at this index; but, if we go beyond the bounds
		// of the value collection, the result will just be "undefined", which will be
		// omitted anyway by the isEmbeddable() check.
		if ( isEmbeddable( values[ i ] ) ) {

			results.push( values[ i ] );

		}

	}

	return( results.join( "" ) );

}


// I determine if the given value is a String that contains at least one non-space
// character (that is worth embedding).
function isEmbeddable( input ) {

	var isString = ( String( input ) === input );
	var hasContent = /\S/.test( input );

	return( isString && hasContent );

}


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


// I output the logging header.
function header( label, note ) {

	console.log( chalk.cyan.bold( label ) );
	console.log( chalk.cyan.bold( "-".repeat( label.length ) ) );
	console.log( chalk.dim( "Note:", note ) );

}


// I output the logging body.
function format( content ) {

	var formattedContent = content
		.replace( /^\t\t/gm, " " )
		.replace( /\t/g, " " )
		.replace( /(^[ \t]+)[\r\n]\s+/gm, "$1" )
	;

	console.log( formattedContent );

}