/* eslint no-console:0 */
'use strict';

// Prepare

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var isWindows = process && process.platform && process.platform.indexOf('win') === 0;

// Optional
var cliColor = null;
if (process) {
	try {
		cliColor = require('cli-color');
	} catch (e) {}
}

/**
Console Reporter for Joe.
Joe attaches and calls the methods of this classes instance.
@example
const joe = require('joe').addReporter(require('joe-reporter-console').create({color: false}))
// joe.suite(...)
@constructor
@class ConsoleReporter
@access public
*/

var ConsoleReporter = function () {
	_createClass(ConsoleReporter, null, [{
		key: 'create',

		/**
  Creates and returns new instance of the current class.
  @param {...*} args - The arguments to be forwarded along to the constructor.
  @return {Object} The new instance.
  @static
  @access public
  */
		value: function create() {
			for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
				args[_key] = arguments[_key];
			}

			return new (Function.prototype.bind.apply(this, [null].concat(args)))();
		}

		/**
  Set the configuration for our instance
  @param {Object} [config]
  @param {boolean} [config.color] - Enabled by default if not in the web browser, or `--no-colors` command line argument is missing
  @param {boolean} [config.utf8] - Enabled by default if not on Windows
  @param {string} [config.itemStart] - What to display when an item starts
  @param {string} [config.markFail] - What to display when an item fails
  @param {string} [config.markPass] - What to display when an item passes
  @param {string} [config.itemArrow] - What to join item names with
  @param {string} [config.summaryError] - What to display for error logs
  @param {string} [config.summaryPass] - What to display if all goes well
  @param {string} [config.summaryFail] - What to display if all went badly
  @chainable
  @returns {this}
  @access public
  */

	}]);

	function ConsoleReporter() {
		var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

		_classCallCheck(this, ConsoleReporter);

		this.errors = [];
		this.config = config;

		// Defaults
		if (this.config.color == null) this.config.color = (process && process.argv || []).indexOf('--no-colors') === -1;
		if (this.config.utf8 == null) this.config.utf8 = !isWindows;
		if (this.config.markFail == null) this.config.markFail = this.config.utf8 ? '✘' : 'ERR!';
		if (this.config.markPass == null) this.config.markPass = this.config.utf8 ? '✔' : 'OK  ';
		if (this.config.itemNames == null) this.config.itemNames = this.config.utf8 ? '$a ➞ $b' : '$a > $b';
		if (this.config.itemStart == null) this.config.itemStart = '$name';
		if (this.config.itemFinish == null) this.config.itemFinish = '$name $mark';
		if (this.config.summaryError == null) this.config.summaryError = '\nError #$index:\n$name\n$error';
		if (this.config.summaryPass == null) this.config.summaryPass = '\n$totalPassedTests/$totalTests tests ran successfully, everything passed';
		if (this.config.summaryFail == null) this.config.summaryFail = '\nFAILURE: $totalPassedTests/$totalTests tests ran successfully; $totalFailedTests failed, $totalIncompleteTests incomplete, $totalErrors errors';

		// Colors
		if (cliColor && this.config.color) {
			this.config.markFail = cliColor.red(this.config.markFail);
			this.config.markPass = cliColor.green(this.config.markPass);
			this.config.itemArrow = cliColor.black(this.config.itemArrow);
			this.config.summaryError = cliColor.red.underline(this.config.summaryError);
			this.config.summaryPass = cliColor.green.underline(this.config.summaryPass);
			this.config.summaryFail = cliColor.red.bold.underline(this.config.summaryFail);
		}
	}

	/**
 Fetches the combined name of an item, paired with its parents.
 @param {Suite|Test} item
 @returns {string}
 @access private
 */


	_createClass(ConsoleReporter, [{
		key: 'getItemName',
		value: function getItemName(item) {
			var _this = this;

			return item.names.filter(function (name) {
				return name !== 'global joe suite';
			}).reduce(function (a, b) {
				return _this.formatMessage(_this.config.itemNames, { a: a, b: b });
			});
		}

		/**
  Injects the options into the message, when the option key is prefixed by a $
  @param {string} message
  @param {Object} opts
  @returns {string}
  @access private
  */

	}, {
		key: 'formatMessage',
		value: function formatMessage(message, opts) {
			Object.keys(opts).forEach(function (key) {
				var value = opts[key];
				message = message.replace('$' + key, value);
			});
			return message;
		}

		/**
  Report that a suite has started.
  @param {Suite} suite
  @returns {this}
  @chainable
  @access protected
  */

	}, {
		key: 'startSuite',
		value: function startSuite(suite) {
			var format = this.config.itemStart;
			if (!format) return this;

			var name = this.getItemName(suite);
			if (!name) return this;

			var message = this.formatMessage(format, { name: name });
			if (!message) return this;

			console.log(message);
			return this;
		}

		/**
  Report that a suite has finished.
  @param {Suite} suite
  @param {Error} [err]
  @returns {this}
  @chainable
  @access protected
  */

	}, {
		key: 'finishSuite',
		value: function finishSuite(suite, err) {
			var format = this.config.itemFinish;
			if (!format) return this;

			var name = this.getItemName(suite);
			if (!name) return this;

			var mark = err ? this.config.markFail : this.config.markPass;
			var message = this.formatMessage(format, { name: name, mark: mark });
			if (!message) return this;

			console.log(message);
			return this;
		}

		/**
  Report that a test has started.
  @param {Test} test
  @returns {this}
  @chainable
  @access protected
  */

	}, {
		key: 'startTest',
		value: function startTest(test) {
			var format = this.config.itemStart;
			if (!format) return this;

			var name = this.getItemName(test);
			if (!name) return this;

			var message = this.formatMessage(format, { name: name });
			if (!message) return this;

			console.log(message);
			return this;
		}

		/**
  Report that a test has finished.
  @param {Test} test
  @param {Error} [err]
  @returns {this}
  @chainable
  @access protected
  */

	}, {
		key: 'finishTest',
		value: function finishTest(test, err) {
			var format = this.config.itemFinish;
			if (!format) return this;

			var name = this.getItemName(test);
			if (!name) return this;

			var mark = err ? this.config.markFail : this.config.markPass;
			var message = this.formatMessage(format, { name: name, mark: mark });
			if (!message) return this;

			console.log(message);

			return this;
		}

		/**
  Report the summary when joe exits.
  @param {number} exitCode
  @returns {this}
  @chainable
  @access protected
  */

	}, {
		key: 'exit',
		value: function exit(exitCode) {
			var _this2 = this;

			var totals = this.joe.getTotals();
			console.log(exitCode ? this.formatMessage(this.config.summaryFail, totals) : this.formatMessage(this.config.summaryPass, totals));
			this.joe.getErrorLogs().forEach(function (errorLog, index) {
				var suite = errorLog.suite,
				    test = errorLog.test,
				    name = errorLog.name,
				    err = errorLog.err;

				var item = test || suite;
				var message = _this2.formatMessage(_this2.config.summaryError, {
					index: index + 1,
					name: name || _this2.getItemName(item),
					error: err.stack || err.message || err
				});
				console.log(message);
			});
			return this;
		}
	}]);

	return ConsoleReporter;
}();

// Export


module.exports = ConsoleReporter;