let webpack = require('webpack');
let Entry = require('./Entry');
let webpackRules = require('./webpack-rules');
let webpackPlugins = require('./webpack-plugins');
let webpackDefaultConfig = require('./webpack-default');

process.noDeprecation = true;

class WebpackConfig {
    /**
     * Create a new instance.
     */
    constructor() {
        this.webpackConfig = webpackDefaultConfig();
    }

    /**
     * Build the Webpack configuration object.
     */
    build() {
        this.buildEntry()
            .buildOutput()
            .buildRules()
            .buildPlugins()
            .buildResolving()
            .mergeCustomConfig();

        // We'll announce that the core config object has been
        // generated by Mix. At this point, any plugins may
        // hook in and modify the config as necessary.
        Mix.dispatch('configReady', this.webpackConfig);

        // Finally, we'll make one last announcement for the user
        // to hook into - using mix.override().
        Mix.dispatch('configReadyForUser', this.webpackConfig);

        return this.webpackConfig;
    }

    /**
     * Build the entry object.
     */
    buildEntry() {
        let entry = new Entry();

        if (!Mix.bundlingJavaScript) {
            entry.addDefault();
        }

        Mix.dispatch('loading-entry', entry);

        this.webpackConfig.entry = entry.get();

        return this;
    }

    /**
     * Build the output object.
     */
    buildOutput() {
        let http = process.argv.includes('--https') ? 'https' : 'http';

        if (Mix.isUsing('hmr')) {
            this.webpackConfig.devServer.host = Config.hmrOptions.host;
            this.webpackConfig.devServer.port = Config.hmrOptions.port;
        }

        this.webpackConfig.output = {
            path: Mix.isUsing('hmr') ? '/' : path.resolve(Config.publicPath),
            filename: '[name].js',
            chunkFilename: '[name].js',
            publicPath: Mix.isUsing('hmr')
                ? `${http}://${Config.hmrOptions.host}:${
                      Config.hmrOptions.port
                  }/`
                : '/'
        };

        return this;
    }

    /**
     * Build the rules array.
     */
    buildRules() {
        this.webpackConfig.module.rules = this.webpackConfig.module.rules.concat(
            webpackRules()
        );

        Mix.dispatch('loading-rules', this.webpackConfig.module.rules);

        return this;
    }

    /**
     * Build the plugins array.
     */
    buildPlugins() {
        this.webpackConfig.plugins = this.webpackConfig.plugins.concat(
            webpackPlugins()
        );

        Mix.dispatch('loading-plugins', this.webpackConfig.plugins);

        return this;
    }

    /**
     * Build the resolve object.
     */
    buildResolving() {
        this.webpackConfig.resolve = {
            extensions: ['*', '.wasm', '.mjs', '.js', '.jsx', '.json', '.vue'],

            alias: {
                vue$: 'vue/dist/vue.common.js'
            }
        };

        return this;
    }

    /**
     * Merge the user's custom Webpack configuration.
     */
    mergeCustomConfig() {
        if (Config.webpackConfig) {
            this.webpackConfig = require('webpack-merge').smart(
                this.webpackConfig,
                Config.webpackConfig
            );
        }
    }
}

module.exports = WebpackConfig;
