'use strict';

var async = require('async');
var winston = require('winston');

var buildStart;

var valid = ['js', 'clientCSS', 'acpCSS', 'tpl', 'lang'];

exports.buildAll = function (callback) {
	exports.build(valid.join(','), callback);
};

exports.build = function build(targets, callback) {
	buildStart = Date.now();

	var db = require('../database');
	var meta = require('../meta');
	var plugins = require('../plugins');


	targets = (targets === true ? valid : targets.split(',').filter(function (target) {
		return valid.indexOf(target) !== -1;
	}));

	if (!targets) {
		winston.error('[build] No valid build targets found. Aborting.');
		return process.exit(0);
	}

	async.series([
		async.apply(db.init),
		async.apply(meta.themes.setupPaths),
		async.apply(plugins.prepareForBuild),
	], function (err) {
		if (err) {
			winston.error('[build] Encountered error preparing for build: ' + err.message);
			return process.exit(1);
		}

		exports.buildTargets(targets, callback);
	});
};

exports.buildTargets = function (targets, callback) {
	var cacheBuster = require('./cacheBuster');
	var meta = require('../meta');
	var numCpus = require('os').cpus().length;
	var strategy = (targets.length > 1 && numCpus > 1);

	buildStart = buildStart || Date.now();

	var step = function (startTime, target, next, err) {
		if (err) {
			winston.error('Build failed: ' + err.message);
			process.exit(1);
		}
		winston.info('[build] ' + target + ' => Completed in ' + ((Date.now() - startTime) / 1000) + 's');
		next();
	};

	if (strategy) {
		winston.verbose('[build] Utilising multiple cores/processes');
	} else {
		winston.verbose('[build] Utilising single-core');
	}

	async[strategy ? 'parallel' : 'series']([
		function (next) {
			if (targets.indexOf('js') !== -1) {
				winston.info('[build] Building javascript');
				var startTime = Date.now();
				async.series([
					meta.js.linkModules,
					meta.js.linkStatics,
					async.apply(meta.js.minify, 'nodebb.min.js'),
					async.apply(meta.js.minify, 'acp.min.js'),
				], step.bind(this, startTime, 'js', next));
			} else {
				setImmediate(next);
			}
		},
		function (next) {
			async.eachSeries(targets, function (target, next) {
				var startTime;
				switch(target) {
					case 'js':
						setImmediate(next);
						break;
					case 'clientCSS':
						winston.info('[build] Building client-side CSS');
						startTime = Date.now();
						meta.css.minify('client', step.bind(this, startTime, target, next));
						break;

					case 'acpCSS':
						winston.info('[build] Building admin control panel CSS');
						startTime = Date.now();
						meta.css.minify('admin', step.bind(this, startTime, target, next));
						break;

					case 'tpl':
						winston.info('[build] Building templates');
						startTime = Date.now();
						meta.templates.compile(step.bind(this, startTime, target, next));
						break;

					case 'lang':
						winston.info('[build] Building language files');
						startTime = Date.now();
						meta.languages.build(step.bind(this, startTime, target, next));
						break;

					default:
						winston.warn('[build] Unknown build target: \'' + target + '\'');
						setImmediate(next);
						break;
				}
			}, next);
		},
	], function (err) {
		if (err) {
			winston.error('[build] Encountered error during build step: ' + err.message);
			return process.exit(1);
		}

		cacheBuster.write(function (err) {
			if (err) {
				winston.error('[build] Failed to write `cache-buster.conf`: ' + err.message);
				return process.exit(1);
			}

			var time = (Date.now() - buildStart) / 1000;

			winston.info('[build] Asset compilation successful. Completed in ' + time + 's.');

			if (typeof callback === 'function') {
				callback();
			} else {
				process.exit(0);
			}
		});
	});
};