import fs from 'fs';
import path from 'path';
import util from 'util';

import ask from 'ask-sync';

try {
	var config = askConfigSettings();
	var rootDir = process.argv[2] || '.';
	var destPath = path.join(rootDir, 'config.js');
	if (confirmConfigSettings(config) &&
	    saveConfigSettings(config, destPath)) {
	    	console.log('Settings saved in "%s"', destPath);
	} else {
		console.log('Settings not saved');
	}
	console.log();
	console.log('Done');
} catch (e) {
	console.log('Fatal error: ' + e.message);
}

function askConfigSettings() {
	return ask({
		db: askDatabaseSettings,
		cors: askCorsSettings,
		oauth2: askOAuth2Settings,
		logging: askLoggingSettings,
		security: askSecuritySettings,
		server: askServerSettings,
	});
}

function showConfigSettings(config) {
	var contents = util.inspect(config, { depth: null });
	console.log('Settings:');
	console.log(contents);
}

function confirmConfigSettings(config) {
	showConfigSettings(config);
	console.log();
	var index = ask.string('Is this correct?', {
		values: ['y','n'], default: 'y'
	})();
	return index === 'y';
}

function saveConfigSettings(config, destPath) {
	var backupFile = destPath + '.old';
	if (fs.existsSync(destPath)) {
		if (!fs.existsSync(backupFile)) {
			fs.renameSync(destPath, backupFile);
		} else {
			console.log('"%s" file exists. Remove it and run setup again', backupFile);
			return false;
		}
	}

	var contents = '// Do not edit this file, changes will be overwritten\n\n';
	var object = util.inspect(config, { depth: null });
	contents += 'module.exports = exports = ' + object + ';\n';
	if (fs.existsSync(destPath))
		fs.renameSync(destPath, destPath + '.old');
	fs.writeFileSync(destPath, contents);
	return true;
}

function askDatabaseSettings() {
	console.log('Database Settings');
	console.log('-----------------');
	var settings = ask({
		mongo: askMongoDbParams,
	});
	console.log();
	return settings;
}

function askCorsSettings() {
	console.log('CORS Settings');
	console.log('-------------');
	var settings = ask({
		origin: ask.variant('Origin filter (js)', { default: '*' }),
	});
	console.log();
	return settings;
}

function askOAuth2Settings() {
	console.log('OAuth2 Settings');
	console.log('---------------');
	var settings = ask({
		client: {
			secret: {
				length: ask.number('Client secret length', { default: 30 }),
			},
		},
		token: {
			length: ask.number('Token length', { default: 30 }),
			resourceOwnerDuration: ask.number('Resource owner token duration (s)', { default: 24 * 60 * 60 }),
			removeExpiredInterval: ask.number('Remove expired tokens interval (s)', { default: 2 * 60 * 60 }),
		},
	});
	console.log();
	return settings;
}

function askLoggingSettings() {
	console.log('Logging Settings');
	console.log('----------------');
	var settings = ask({
		outputPath: ask.string('Log file', { default: './errors.log' }),
	});
	console.log();
	return settings;
}

function askSecuritySettings() {
	console.log('Security Settings');
	console.log('-----------------');
	var settings = ask({
		password: {
			minLength: ask.number('Password min length', { default: 8 }),
		},
		hash: {
			scrypt: {
				maxtime: ask.number('Scrypt max time', { default: 0.1 }),
				maxmem: ask.number('Scrypt max memory', { nullable: true }),
				maxmemfrac: ask.number('Scrypt max memory factor', { nullable: true }),
			},
		},
	});
	console.log();
	return settings;
}

function askServerSettings() {
	console.log('Server Settings');
	console.log('---------------');
	var settings = ask({
		port: ask.number('Port', { default: 8080 }),
	});
	console.log();
	return settings;
}

function askMongoDbParams() {
	var data = ask({
		host: ask.string('Host'),
		port: ask.number('Port', { nullable: true }),
		table: ask.string('Table name'),
	});
	return {
		url: data.port === undefined
		       ? 'mongodb://' + data.host + '/' + data.table
		       : 'mongodb://' + data.host + ':' + data.port + '/' + data.table
	};
}
