
const webpack = require('webpack');

exports.Compiler = class Compiler {
    constructor (configWebpackList) {
        if (!Array.isArray(configWebpackList)) {
            configWebpackList = [configWebpackList];
        }

        this.configs = configWebpackList;
    }

    // get hooks () {
    //   return this.compiler.hooks
    // }

    build (parallel = false) {
        if (parallel) {
            const compiler = webpack(this.configs);
            return new Promise((resolve, reject) => {
                compiler.run((err, stats) => {
                    if (err) reject(err);

                    printInfo(stats);

                    resolve();
                });
            });
        }
    
        return new Promise((resolve, reject) => {
            const configs = this.configs.slice();

            doCompile(webpack(configs.shift()));

            function doCompile (compiler) {
                compiler.run((err, stats) => {
                    if (err) reject(err);

                    printInfo(stats);

                    if (configs.length) {
                        doCompile(webpack(configs.shift()));

                        return;
                    }

                    resolve();
                });
            }
        });
    }

    watch (parallel = true, onChange) {
        if (typeof parallel === 'function') {
            onChange = parallel;

            parallel = true;
        }

        parallel = !!parallel;

        if (parallel) {
            const compiler = webpack(this.configs);

            compiler.watch({
                aggregateTimeout: 500
            }, (err, stats) => {
                if (err) throw err;

                printInfo(stats);
          
                typeof onChange === 'function' && onChange();
            });

            return;
        }
        
        const configs = this.configs;
        const watchers = [];
        const compilers = configs.map(c => webpack(c));

        doCompile(compilers[0]);

        function doCompile (compiler, idx = 0) {
            if (idx === 0) {
                watchers[idx] = compiler.watch({
                    aggregateTimeout: 500
                }, (err, stats) => {
                    if (err) throw err;

                    printInfo(stats);

                    if (configs.length !== idx + 1) {
                        doCompile(compilers[idx + 1], idx + 1);

                        return;
                    }

                    typeof onChange === 'function' && onChange();
                });

                return;
            }
            
            compiler.run((err, stats) => {
                if (err) throw err;

                printInfo(stats);

                if (configs.length !== idx + 1) {
                    doCompile(compilers[idx + 1], idx + 1);

                    return;
                }

                typeof onChange === 'function' && onChange();
            });
        }
    }
};

function printInfo (multi) {
    if (!multi.stats) {
        multi = {
            stats: [multi]
        };
    }

    multi.stats.forEach(stats => {
        process.stdout.write(stats.toString({
            colors: true,
            modules: false,
            children: false,
            chunks: false,
            chunkModules: false
        }) + '\n\n');
    });   
}