const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const themeVars = require('./themeVars');
const core = 7;
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');

class WatchRunPlugin {
  apply(compiler) {
    compiler.hooks.watchRun.tap('WatchRun', (comp) => {
      const changedTimes = comp.watchFileSystem.watcher.mtimes;
      const changedFiles = Object.keys(changedTimes)
        .map((file) => `\n  ${file}`)
        .join('');
      if (changedFiles.length) {
        console.log('====================================');
        console.log('NEW BUILD FILES CHANGED:', changedFiles);
        console.log('====================================');
      }
    });
  }
}

module.exports = function (options) {
  const {
    context,
    entry,
    output,
    mode,
    watch,
    externals,
    htmlTemplatePath,
    definePlugin = {},
    optimization = {},
  } = options;
  const isDevelopment = mode !== 'production';
  const BABEL_LOADER = {
    loader: 'babel-loader',
    options: {
      compact: false,
      cacheDirectory: true,
      cwd: context,
      presets: [
        [
          '@babel/preset-env',
          {
            modules: false,
            targets: {
              esmodules: true,
              browsers: ['defaults', 'iOS >= 10', 'safari >= 10'],
            },
            // useBuiltIns: 'usage',
            // corejs: '2.6.12',
          },
        ],
        '@babel/preset-react',
      ],
      plugins: [
        [
          'babel-plugin-import',
          {
            libraryName: '@govcloud/gsd-kbone-react',
            libraryDirectory: 'lib/components',
            camel2DashComponentName: false,
          },
        ],
        '@babel/plugin-proposal-class-properties',
        ['@babel/plugin-proposal-decorators', { legacy: true }],
        '@babel/plugin-proposal-export-default-from',
        '@babel/plugin-proposal-export-namespace-from',
        '@babel/plugin-proposal-optional-chaining',
        '@babel/plugin-proposal-partial-application',
        ['@babel/plugin-proposal-pipeline-operator', { proposal: 'minimal' }],
      ].filter(Boolean),
    },
  };
  let plugins = [
    new NodePolyfillPlugin(),
    // new WatchRunPlugin()
    htmlTemplatePath
      ? new HtmlWebpackPlugin({
          template: htmlTemplatePath,
          filename: 'index.html',
          cache: false,
        })
      : null,
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css',
      ignoreOrder: true,
    }),
    new webpack.DefinePlugin(
      Object.assign(
        {
          'process.env.isMiniprogram': false, // 注入环境变量，用于业务代码判断
          'process.env.SSR': false,
          'process.env.compileTool': `'webpack'`,
        },
        definePlugin,
      ),
    ),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, '../assets'),
          to: '.',
          noErrorOnMissing: true,
        },
      ],
    }),
  ].filter((item) => !!item);
  if (!isDevelopment) {
    plugins = plugins.concat([
      new webpack.EnvironmentPlugin({
        SSR: false,
        WEBPACK_ENV: 'production',
      }),
      // new BundleAnalyzerPlugin(),
    ]);
  }
  return {
    context,
    entry,
    mode,
    watch,
    watchOptions: {
      ignored: [output.path],
    },
    output,
    externals,
    cache: {
      type: 'memory',
    },
    devtool: false,
    resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.scss', '.css'],
      symlinks: false,
      cacheWithContext: false,
      alias: {
        '@': path.resolve(__dirname, '../src'),
        lodash: 'lodash-es',
      },
    },
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          exclude: /node_modules\/(?!@cloudbase\/(weda-ui|weda-client))/,
          use: [
            {
              loader: require.resolve('thread-loader'),
              options: {
                workers: core,
              },
            },
            BABEL_LOADER,
            {
              loader: 'ts-loader',
              options: {
                happyPackMode: true,
                transpileOnly: true,
              },
            },
          ],
        },
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules\/(?!@cloudbase\/(weda-ui|weda-client))/,
          use: [
            {
              loader: require.resolve('thread-loader'),
              options: {
                workers: core,
              },
            },
            BABEL_LOADER,
          ],
        },
        {
          test: /\.(scss|sass)$/,
          use: [
            MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                modules: false,
                importLoaders: 2,
              },
            },
            {
              loader: 'sass-loader',
              options: {
                implementation: require('dart-sass'),
              },
            },
          ],
        },
        {
          test: /\.(css|less)$/,
          use: [
            MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                modules: false,
                importLoaders: 2,
              },
            },
            {
              loader: require.resolve('less-loader'),
              options: {
                lessOptions: {
                  modifyVars: themeVars,
                },
              },
            },
          ],
        },
        {
          test: /\.(jpe?g|png|gif|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
          loader: 'base64-inline-loader',
        },
      ],
    },
    plugins,
    optimization: {
      moduleIds: 'deterministic',
      emitOnErrors: false,
      removeEmptyChunks: true,
      usedExports: true,
      splitChunks: false,
      // splitChunks: {
      //   cacheGroups: {
      //     'extra-package': {
      //       name: 'extra-package',
      //       test: /(semver|searequire|less|postcss|postcss-pxtorem|xlsx|papaparse)/,
      //       chunks: 'all',
      //     },
      //   },
      // },
      ...optimization,
      ...(isDevelopment
        ? {
            minimize: false,
            removeAvailableModules: false,
            concatenateModules: true,
          }
        : {
            minimizer: [
              new TerserPlugin({
                test: /\.js(\?.*)?$/i,
                cache: false,
                parallel: true,
                sourceMap: true,
              }),
            ],
          }),
    },
  };
};
