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

const TS_LOADER_ID = 'ts-loader';

module.exports = function (options) {
  const { output, definePlugin = {}, devtool = false, vueVersion = 0 } = options;
  const context = path.resolve(__dirname, '../');

  const babelLoader = {
    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', 'chrome >= 53'],
            },
          },
        ],
        '@babel/preset-react',
      ],
      plugins: [
        '@babel/plugin-transform-class-properties',
        ['@babel/plugin-proposal-decorators', { legacy: true }],
        '@babel/plugin-proposal-export-default-from',
      ].filter(Boolean),
    },
  };
  const typescriptLoader = {
    loader: 'ts-loader',
    options: {
      compilerOptions: {
        target: 'ESNext',
        module: 'ESNext',
        esModuleInterop: true,
      },
      happyPackMode: true,
      transpileOnly: true,
    },
  };

  let plugins = [
    new HappyPack({
      id: TS_LOADER_ID,
      loaders: [babelLoader, typescriptLoader],
      threadPool: happyThreadPool,
    }),
    new HappyPack({
      id: 'babel',
      loaders: [babelLoader],
      threadPool: happyThreadPool,
    }),
    new HtmlWebpackPlugin({
      template: 'index.html',
      filename: 'index.html',
      cache: false,
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css',
    }),
    new webpack.DefinePlugin(
      Object.assign(
        {
          'process.env.compileTool': `'webpack'`,
        },
        definePlugin,
      ),
    ),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, '../assets'),
          to: '.',
          noErrorOnMissing: true,
        },
      ],
    }),
    new webpack.HashedModuleIdsPlugin({
      hashFunction: 'sha256',
      hashDigest: 'hex',
      hashDigestLength: 20,
    }),
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
    new webpack.NormalModuleReplacementPlugin(
      /@\/components\/(?!ui)(.*)|^@\/lib|^@\/configs|^@\/components$/, // 使用否定前瞻匹配除ui外的所有路径
      function (resource) {
        if (/lowcode\/(pages|components|lib|configs)/.test(resource.context)) {
          if (/\@\/lib\/(.*)/.test(resource.request)) {
            resource.request = resource.request.replace(/\@\/lib\/(.*)/, '@/lowcode/lib/$1');
          } else if (/\@\/configs\/(.*)/.test(resource.request)) {
            resource.request = resource.request.replace(/\@\/configs\/(.*)/, '@/lowcode/configs/$1');
          } else if (/\@\/components\/(.*)/.test(resource.request)) {
            resource.request = resource.request.replace(/\@\/components\/(.*)/, '@/lowcode/components/$1');
          } else if (resource.request === '@/components') {
            resource.request = '@/lowcode/components/index';
          }
        }
      },
    ),
    // new BundleAnalyzerPlugin(),
  ];
  if (vueVersion === 2) {
    const { VueLoaderPlugin } = require('vue-loader-for-vue2');
    plugins.push(new VueLoaderPlugin());
  } else if (vueVersion === 3) {
    plugins.push(new (require('veaury/webpack/VeauryVuePlugin'))());
    plugins.push(
      new webpack.DefinePlugin({
        __VUE_OPTIONS_API__: 'true',
        __VUE_PROD_DEVTOOLS__: 'false',
        __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false',
      }),
    );
  }

  const commonCSSLoaders = [
    MiniCssExtractPlugin.loader,
    {
      loader: 'css-loader',
      options: {
        modules: {
          auto: true,
          getLocalIdent: getCSSModuleLocalIdent,
        },
        importLoaders: 2,
      },
    },
  ];

  const rules = [
    {
      test: /\.tsx?$/,
      exclude:
        /node_modules\/(?!(@cloudbase\/weda-ui)|(@cloudbase\/lowcode-render)|(@cloudbase\/weda-client))|gsd-kbone-react/,
      use: [`happypack/loader?id=${TS_LOADER_ID}`],
    },
    {
      test: /\.(js|jsx)$/,
      exclude:
        /node_modules\/(?!(@cloudbase\/weda-ui)|(@cloudbase\/lowcode-render)|(@cloudbase\/weda-client)|(@tcwd\/vuera)|(@tcwd\/weapps-core)|(@react-spring)|(@react-hookz))|gsd-kbone-react/,
      use: ['happypack/loader?id=babel'],
    },
    {
      test: /node_modules\/@loadable\/component\/.*\.mjs$/,
      include: /node_modules/,
      type: 'javascript/auto',
    },
    {
      test: /\.(scss|sass)$/,
      use: [
        ...commonCSSLoaders,
        {
          loader: 'sass-loader',
          options: {
            implementation: require('sass'),
          },
        },
      ],
    },
    {
      test: /\.css$/,
      use: [...commonCSSLoaders],
    },
    {
      test: /\.less$/,
      use: [
        ...commonCSSLoaders,
        {
          loader: 'less-loader',
          options: {
            lessOptions: {
              modifyVars: themeVars,
              javascriptEnabled: true,
            },
          },
        },
      ],
    },
    {
      test: /\.(jpe?g|png|gif|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
      loader: 'base64-inline-loader',
    },
  ];

  if (vueVersion === 2) {
    rules.push({
      test: /\.vue$/,
      loader: require.resolve('vue-loader-for-vue2'),
    });
  }

  return {
    context,
    entry: './src/index.jsx',
    /**
     * 只要是构建都开启 production 以使用精简
     */
    mode: 'production',
    watch: false,
    output: {
      path: path.resolve(context, output.path),
      filename: '[name].[hash].bundle.js',
      chunkFilename: '[name].[contenthash].chunk.js',
      publicPath: output.publicPath,
      pathinfo: false,
    },
    externals: [
      {
        react: 'window.React',
        'react-dom': 'window.ReactDOM',
        mobx: 'window.mobx',
        '@cloudbase/js-sdk': 'window.cloudbase',
        '@cloudbase/weda-cloud-sdk/dist/h5': 'window.CloudSDK',
        '@cloudbase/weda-cloud-sdk': 'window.CloudSDK',
        '@cloudbase/weda-client': 'window.WedaClientSDK',
        '@zxing/library': 'window.ZXing',
        '@cloudbase/lowcode-render': 'window["weda-render"]',
      },
      // 函数
      function (context, request, callback) {
        const ScopeExternalsMap = {
          recharts: 'window.SHADN.RECHARTS',
          'react-hook-form': 'window.SHADN.ReactHookForm',
          'lucide-react': 'window.SHADN.LUCIDE',
          'date-fns': 'window.SHADN.DateFns',
          clsx: 'window.SHADN.CLSX',
          'tailwind-merge': 'window.SHADN.TailwindMerge',
        };

        if (/lowcode\//.test(context)) {
          if (ScopeExternalsMap[request]) {
            callback(null, ScopeExternalsMap[request]);
            return;
          } else if (request === '@/components/ui') {
            callback(null, 'window.SHADN.components');
            return;
          }
        }
        callback();
      },
    ],
    cache: {
      type: 'memory',
    },
    devtool: devtool,
    resolve: {
      extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.mjs', '.scss', '.css'],
      modules: [context, 'node_modules'],
      symlinks: false,
      cacheWithContext: false,
      alias: {
        '@': path.resolve(context, './src'),
        '@wdsrc': path.resolve(context, './src'),
      },
    },
    module: {
      rules,
    },
    plugins,
    optimization: {
      concatenateModules: true,
      noEmitOnErrors: true,
      splitChunks: {
        maxSize: 3000000,
        cacheGroups: {
          base: {
            test: /(react|react-dom|react-router|react-router-dom|mobx|mobx-react-lite|@cloudbase\/js-sdk)/,
            chunks: 'all',
            minSize: 500000,
            priority: 100, // 优先级
          },
          utils: {
            test: /(lodash|dayjs|axios|kbone-api)/,
            chunks: 'all',
            priority: 100, // 优先级
          },
          'async-commons': {
            chunks: 'async',
            minChunks: 2,
            priority: 20,
          },
          commons: {
            chunks: 'all',
            minChunks: 2,
            priority: 20,
          },
        },
      },
      minimizer: [
        new TerserPlugin({
          test: /\.js(\?.*)?$/i,
          cache: false,
          parallel: true,
          sourceMap: false,
          terserOptions: {
            safari10: true,
          },
        }),
      ],
    },
  };
};
