const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { version } = require('@newland/toubiz-widget/package.json');
const vueTemplateBabel = require('vue-template-babel-compiler');

const mode = process.env.NODE_ENV || 'development';
const prod = mode === 'production';

/*
 * Webpack base configuration.
 * This configuration is shared between
 * production builds and testing builds.
 */
module.exports = (enableMiniCssExtractPlugin) => {
    const config = {
        mode: prod ? 'production' : 'development',

        output: {
            filename: '[name].js',
            chunkFilename: '[name].[chunkhash].chunk.js',
        },

        optimization: {
            moduleIds: prod ? 'hashed' : false,
        },

        module: {
            rules: [
                {
                    test: /\.(js|jsx)$/,
                    exclude: /(node_modules(?!\/(@newland|@nimius|swiper|dom7)))/,
                    loader: 'babel-loader',
                    options: require('./babel.config'),
                },
                {
                    test: /\.vue$/,
                    loader: 'vue-loader',
                    options: {
                        compiler: vueTemplateBabel,
                    },
                },
                {
                    test: /\.(sass|scss|css|postcss)$/,
                    use: [
                        enableMiniCssExtractPlugin ? { loader: MiniCssExtractPlugin.loader, options: { sourceMap: !prod }} : { loader: 'vue-style-loader' },
                        { loader: 'css-loader', options: { importLoaders: 2, sourceMap: !prod }},
                        { loader: 'postcss-loader', options: {
                            sourceMap: !prod,
                                config: {
                                    path: path.resolve(__dirname, './postcss.config.js'),
                                },
                            }},
                        { loader: 'sass-loader', options: { sourceMap: !prod }},
                    ],
                },
                {
                    // Load certain file types as urls
                    test: /\.(png|jpe?g|gif|svg|woff2?|eos|ttf)$/,
                    use: 'file-loader',
                },
            ],
        },

        plugins: [
            // only use german locale for moment
            new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /moment/),
            new VueLoaderPlugin(),
            new webpack.DefinePlugin({
                'process.env.BUILD_MODE': JSON.stringify(mode),
                'process.env.TOUBIZ_BASE_URI': JSON.stringify(process.env.TOUBIZ_BASE_URI),
                'process.env.WIDGET_CONFIGURATION': JSON.stringify(process.env.WIDGET_CONFIGURATION),
                'process.env.TOUBIZ_WIDGET_VERSION': JSON.stringify(version),
            }),
            new webpack.optimize.MinChunkSizePlugin({ minChunkSize: 100000 }),
        ],

        resolve: {
            extensions: [ '.wasm', '.mjs', '.js', '.json', '.vue' ],
            modules: [
                // Force webpack to prefer node_modules from the package directory over ones from the project.
                path.resolve(__dirname, 'node_modules'),
                'node_modules',
            ],
            alias: {
                'vue$': 'vue/dist/vue.esm.js',
                '@components': path.resolve(__dirname, 'node_modules/@newland/toubiz-widget/src/components/'),
                '@mixins': path.resolve(__dirname, 'node_modules/@newland/toubiz-widget/src/mixins/'),
                '@utilities': path.resolve(__dirname, 'node_modules/@newland/toubiz-widget/src/utilities/'),
                '@store': path.resolve(__dirname, 'node_modules/@newland/toubiz-widget/src/store/'),

                // v-calendar style extraction in order to get them into the shadow DOM.
                // This is a it hacky. Refer to this issue for discussion of the current
                // v-calendar shadow dom situation:
                // https://github.com/nathanreyes/v-calendar/issues/606
                'v-calendar$': path.resolve(__dirname, 'node_modules/v-calendar/src/lib.js'),
                '@/utils': path.resolve(__dirname, 'node_modules/v-calendar/src/utils/'),
                '@/components': path.resolve(__dirname, 'node_modules/v-calendar/src/components/'),
                '../styles': path.resolve(__dirname, 'node_modules/@newland/toubiz-widget/src/vendor/v-calendar'),
            },
        },
    };

    if (enableMiniCssExtractPlugin) {
        // Groups all styles of components together into a single `component-styles` chunk.
        // Together with `MiniCssExtractPlugin` this will result in a `component-styles.css`
        // file that is automatically loaded.
        config.optimization = config.optimization || {};
        config.optimization.splitChunks = config.optimization.splitChunks || {};
        config.optimization.splitChunks.cacheGroups = config.optimization.splitChunks.cacheGroups || {};
        config.optimization.splitChunks.cacheGroups['component-styles'] = {
            name: `component-styles.${Math.random().toString(26).substr(2)}`,
            test: module => module.nameForCondition
                && /\.(s?css|vue)$/.test(module.nameForCondition())
                && !/^javascript/.test(module.type)
                && !/scoped=true/.test(module.request),
            minChunks: 1,
            enforce: true,
        };

        // All styles referenced in a entry chunk will be placed next to
        // the entry chunk with the same file name .css
        // The entry chunk main will produce main.css while the entry chunk
        // foo/bar will produce foo/bar.css.
        config.plugins.push(new MiniCssExtractPlugin({
            moduleFilename(chunk) {
                return `${chunk.entryModule.hash}.css`;
            },
        }));
    }
    return config;
};
