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 HappyPack = require('happypack');
const core = 7;
const happyThreadPool = HappyPack.ThreadPool({ size: core });
const BundleAnalyzerPlugin =
  require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const TS_LOADER_ID = 'ts-loader';

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,
            },
            // 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 WatchRunPlugin(),
    new HappyPack({
      id: TS_LOADER_ID,
      loaders: [
        BABEL_LOADER,
        {
          loader: 'ts-loader',
          options: {
            happyPackMode: true,
            transpileOnly: true,
          },
        },
      ],
      threadPool: happyThreadPool,
    }),
    new HappyPack({
      id: 'babel',
      loaders: [BABEL_LOADER],
      threadPool: happyThreadPool,
    }),
    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.HashedModuleIdsPlugin({
        hashFunction: 'sha256',
        hashDigest: 'hex',
        hashDigestLength: 20,
      }),
      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: 'source-map',
    resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.scss', '.css'],
      symlinks: false,
      cacheWithContext: false,
      alias: {
        '@': path.resolve(__dirname, '../src'),
      },
    },
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          exclude: /node_modules\/(?!@cloudbase\/(weda-ui|weda-client))/,
          use: [`happypack/loader?id=${TS_LOADER_ID}`],
        },
        {
          test: /\.(js|jsx)$/,
          use: ['happypack/loader?id=babel'],
          exclude: /node_modules\/(?!@cloudbase\/(weda-ui|weda-client))/,
        },
        {
          test: /\.(scss|sass)$/,
          use: [
            MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                modules: false,
                importLoaders: 2,
              },
            },
            {
              loader: 'postcss-loader',
              options: {
                postcssOptions: {
                  plugins: [
                    [
                      'postcss-pxtorem',
                      {
                        rootValue: 14,
                        propList: ['*'],
                        // todo
                        selectorBlackList: ['.weui-picker__indicator'],
                      },
                    ],
                  ],
                },
              },
            },
            {
              loader: 'sass-loader',
              options: {
                implementation: require('dart-sass'),
              },
            },
          ],
        },
        {
          test: /\.(css|less)$/,
          use: [
            MiniCssExtractPlugin.loader,
            {
              loader: 'css-loader',
              options: {
                modules: false,
                importLoaders: 2,
              },
            },
            {
              loader: 'postcss-loader',
              options: {
                postcssOptions: {
                  plugins: [
                    [
                      'postcss-pxtorem',
                      {
                        rootValue: 14,
                        propList: ['*'],
                        // todo
                        selectorBlackList: ['.weui-picker__indicator'],
                      },
                    ],
                  ],
                },
              },
            },
            {
              loader: '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: {
      noEmitOnErrors: true,
      removeEmptyChunks: true,
      usedExports: true,
      splitChunks: false,
      ...optimization,
      ...(isDevelopment
        ? {
            minimize: false,
            removeAvailableModules: false,
            concatenateModules: true,
          }
        : {
            minimizer: [
              new TerserPlugin({
                test: /\.js(\?.*)?$/i,
                cache: false,
                parallel: true,
                sourceMap: false,
              }),
            ],
          }),
    },
  };
};
