'use strict';

var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var winston = require('winston');
var async = require('async');
var path = require('path');
var fs = require('fs');
var nconf = require('nconf');
var _ = require('lodash');

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

var viewsPath = nconf.get('views_dir');

var Templates = module.exports;

function processImports(paths, templatePath, source, callback) {
	var regex = /<!-- IMPORT (.+?) -->/;

	var matches = source.match(regex);

	if (!matches) {
		return callback(null, source);
	}

	var partial = matches[1];
	if (paths[partial] && templatePath !== partial) {
		fs.readFile(paths[partial], 'utf8', function (err, partialSource) {
			if (err) {
				return callback(err);
			}

			source = source.replace(regex, partialSource);
			processImports(paths, templatePath, source, callback);
		});
	} else {
		winston.warn('[meta/templates] Partial not loaded: ' + matches[1]);
		source = source.replace(regex, '');

		processImports(paths, templatePath, source, callback);
	}
}
Templates.processImports = processImports;

var themeNamePattern = /^(@.*?\/)?nodebb-theme-.*$/;

function getTemplateDirs(activePlugins, callback) {
	var pluginTemplates = activePlugins.map(function (id) {
		if (themeNamePattern.test(id)) {
			return nconf.get('theme_templates_path');
		}
		if (!plugins.pluginsData[id]) {
			return '';
		}
		return path.join(__dirname, '../../node_modules/', id, plugins.pluginsData[id].templates || 'templates');
	}).filter(Boolean);

	var themeConfig = require(nconf.get('theme_config'));
	var theme = themeConfig.baseTheme;

	var themePath;
	var themeTemplates = [];
	while (theme) {
		themePath = path.join(nconf.get('themes_path'), theme);
		themeConfig = require(path.join(themePath, 'theme.json'));

		themeTemplates.push(path.join(themePath, themeConfig.templates || 'templates'));
		theme = themeConfig.baseTheme;
	}

	themeTemplates.push(nconf.get('base_templates_path'));
	themeTemplates = _.uniq(themeTemplates.reverse());

	var coreTemplatesPath = nconf.get('core_templates_path');

	var templateDirs = _.uniq([coreTemplatesPath].concat(themeTemplates, pluginTemplates));

	async.filter(templateDirs, file.exists, callback);
}

function getTemplateFiles(dirs, callback) {
	async.waterfall([
		function (cb) {
			async.map(dirs, function (dir, next) {
				file.walk(dir, function (err, files) {
					if (err) { return next(err); }

					files = files.filter(function (path) {
						return path.endsWith('.tpl');
					}).map(function (file) {
						return {
							name: path.relative(dir, file).replace(/\\/g, '/'),
							path: file,
						};
					});
					next(null, files);
				});
			}, cb);
		},
		function (buckets, cb) {
			var dict = {};
			buckets.forEach(function (files) {
				files.forEach(function (file) {
					dict[file.name] = file.path;
				});
			});

			cb(null, dict);
		},
	], callback);
}

function compile(callback) {
	callback = callback || function () {};

	async.waterfall([
		function (next) {
			rimraf(viewsPath, function (err) { next(err); });
		},
		function (next) {
			mkdirp(viewsPath, function (err) { next(err); });
		},
		function (next) {
			db.getSortedSetRange('plugins:active', 0, -1, next);
		},
		getTemplateDirs,
		getTemplateFiles,
		function (files, next) {
			async.each(Object.keys(files), function (name, next) {
				var filePath = files[name];

				async.waterfall([
					function (next) {
						fs.readFile(filePath, 'utf8', next);
					},
					function (source, next) {
						processImports(files, name, source, next);
					},
					function (source, next) {
						mkdirp(path.join(viewsPath, path.dirname(name)), function (err) {
							next(err, source);
						});
					},
					function (compiled, next) {
						fs.writeFile(path.join(viewsPath, name), compiled, next);
					},
				], next);
			}, next);
		},
		function (next) {
			winston.verbose('[meta/templates] Successfully compiled templates.');
			next();
		},
	], callback);
}
Templates.compile = compile;
