'use strict';

const fs = require('fs');
const glob = require('glob');
const path = require('path');
const util = require('util');
const execSync = require('child_process').execSync;
const camelcase = require('camelcase');

function convertKeysToCamelCase(input) {
    let result = {};
    Object.keys(input).map((key, _) => {
        const value = input[key];
        if (value !== null && value.constructor == Object) {
            result[camelcase(key)] = convertKeysToCamelCase(value);
        } else {
            result[camelcase(key)] = value;
        }
    });
    return result;
}

function getVersion() {
    return execSync('git describe --always --dirty --long --tags').toString();
}

function getConfig() {
    const yaml = require('js-yaml');
    const merge = require('merge');
    const camelcaseKeys = require('camelcase-keys');

    function parseConfigFile(path) {
        let result = yaml.load(fs.readFileSync(path, 'utf-8'));
        return convertKeysToCamelCase(result);
    }

    let config = parseConfigFile('../config.yaml.dist');

    try {
        const localConfig = parseConfigFile('../config.yaml');
        config = merge.recursive(config, localConfig);
    } catch (e) {
        console.warn('Local config does not exist, ignoring');
    }

    delete config.secret;
    delete config.smtp;
    delete config.database;
    config.meta = {
        version: getVersion(),
        buildDate: new Date().toUTCString(),
    };

    return config;
}

function bundleHtml(config) {
    const minify = require('html-minifier').minify;
    const baseHtml = fs.readFileSync('./html/index.htm', 'utf-8');
    glob('./html/**/*.hbs', {}, (er, files) => {
        let templatesHtml = '';
        for (const file of files) {
            templatesHtml += util.format(
                '<template id=\'%s-template\'>%s</template>',
                path.basename(file, '.hbs').replace('_', '-'),
                fs.readFileSync(file));
        }

        const finalHtml = baseHtml
            .replace(/(<\/head>)/, templatesHtml + '$1')
            .replace(
                /(<title>)(.*)(<\/title>)/,
                util.format('$1%s$3', config.name));

        fs.writeFileSync(
            './public/index.htm',
            minify(
                finalHtml, {
                    removeComments: true,
                    collapseWhitespace: true,
                    conservativeCollapse: true}));
        console.info('Bundled HTML');
    });
}

function bundleCss() {
    const minify = require('csso').minify;
    glob('./css/**/*.css', {}, (er, files) => {
        let css = '';
        for (const file of files) {
            css += fs.readFileSync(file);
        }
        fs.writeFileSync('./public/bundle.min.css', minify(css));
        console.info('Bundled CSS');
    });
}

function bundleJs() {
    const browserify = require('browserify');
    const uglifyjs = require('uglify-js');
    glob('./js/**/*.js', {}, function(er, files) {
        const outputFile = fs.createWriteStream('./public/bundle.min.js');
        browserify().add(files).bundle().pipe(outputFile);
        outputFile.on('finish', function() {
            const result = uglifyjs.minify('./public/bundle.min.js');
            fs.writeFileSync('./public/bundle.min.js', result.code);
            console.info('Bundled JS');
        });
    });
}

function bundleConfig(config) {
    fs.writeFileSync(
        './js/.config.autogen.json', JSON.stringify(config));
}

function copyFile(source, target) {
    fs.createReadStream(source).pipe(fs.createWriteStream(target));
}

const config = getConfig();
bundleConfig(config);
bundleHtml(config);
bundleCss();
bundleJs();
copyFile('./img/favicon.png', './public/favicon.png');