const path = require('path');
const webpack = require('webpack');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const LoadablePlugin = require('@loadable/webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { rootDir, target, env, version, hmr, staticPath } = require('../helpers/const');

module.exports = {
  context: rootDir,

  name: 'client',
  mode: 'development',
  target: 'web',

  devtool: 'eval-source-map',

  watchOptions: {
    ignored: /node_modules/,
    aggregateTimeout: 250,
    poll: 500
  },

  entry: {
    main: [
      hmr ? 'webpack-hot-middleware/client?timeout=1000' : undefined,
      path.resolve(rootDir, './src/application/client/main.tsx')
    ].filter(Boolean)
  },

  output: {
    path: path.resolve(rootDir, './build/client', target),
    filename: '[name].js',
    chunkFilename: 'chunks/[id].js',
    assetModuleFilename: 'assets/[name].[hash:8][ext]',
    hotUpdateChunkFilename: 'hot/[id].[fullhash].hot-update.js',
    hotUpdateMainFilename: 'hot/[runtime].[fullhash].hot-update.json',
    publicPath: `${staticPath}/${target}/`,
    pathinfo: false
  },

  cache: {
    type: 'filesystem',
    buildDependencies: {
      configs: [__filename]
    }
  },

  optimization: {
    runtimeChunk: hmr ? 'single' : false,
    removeAvailableModules: false,
    removeEmptyChunks: false,
    splitChunks: false
  },

  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
    alias: {
      '@root': path.resolve(rootDir, './'),
      '@game': path.resolve(rootDir, './src'),
      '@server': path.resolve(rootDir, '../game-server/src'),
      '@api': path.resolve(rootDir, '../game-api/src'),
      '@map': path.resolve(rootDir, '../map/src'),
      '@core': path.resolve(rootDir, '../core/src'),

      '_service': path.resolve(rootDir, './src'),
      '_build': path.resolve(rootDir, './build'),

      'react': path.resolve(rootDir, './node_modules/react'),
      'react-dom': path.resolve(rootDir, './node_modules/react-dom'),
      '@loadable': path.resolve(rootDir, './node_modules/@loadable'),
      '@babel': path.resolve(rootDir, './node_modules/@babel'),
      'svg-sprite-loader': path.resolve(rootDir, './node_modules/svg-sprite-loader'),
      'events': path.resolve(rootDir, './node_modules/events')
    },
    fallback: {
      crypto: false,
      path: false,
      util: false
    }
  },

  externals: {
    'react': 'React',
    'react-dom': 'ReactDOM',
    'url': 'window',
    'util': 'window'
  },

  module: {
    noParse: (name) => /(?<!react-datepicker)\.min\.js$/.test(name),

    generator: {
      'asset': {
        publicPath: staticPath,
        outputPath: './'
      },
      'asset/resource': {
        publicPath: staticPath,
        outputPath: './'
      }
    },

    rules: [
      // JavaScript
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        type: 'javascript/auto'
      },
      // TypeScript
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true,
              plugins: [hmr ? 'react-refresh/babel' : undefined].filter(Boolean)
            }
          }
        ]
      },
      // CSS
      {
        test: /\.css$/,
        use: [
          // Creates `style` nodes from JS strings
          MiniCssExtractPlugin.loader,
          {
            // Translates CSS into CommonJS
            loader: 'css-loader',
            options: {
              sourceMap: true
            }
          }
        ]
      },
      // Sass
      {
        test: /\.s[ac]ss$/,
        use: [
          // Creates `style` nodes from JS strings
          MiniCssExtractPlugin.loader,
          {
            // Translates CSS into CommonJS
            loader: 'css-loader',
            options: {
              sourceMap: true
            }
          },
          {
            // Compiles Sass to CSS
            loader: 'sass-loader',
            options: {
              sourceMap: true,
              webpackImporter: true,
              warnRuleAsWarning: true
            }
          }
        ]
      },
      // Images
      {
        test: /\.(?:ico|gif|png|jpg|jpeg|svg)$/i,
        type: 'asset/resource'
      },
      {
        test: /\.svg$/,
        issuer: /\.(?:s[ac]|c)ss$/,
        type: 'asset'
      }
    ]
  },

  plugins: [
    new webpack.EnvironmentPlugin({
      NODE_ENV: env,
      STATIC_PATH: staticPath,
      APP_VERSION: version,
      PLATFORM: 'client',
      TARGET: target,
      API_HOST: 'localhost:3001',
      SERVER_MSGPACK: 0
    }),

    new LoadablePlugin({
      writeToDisk: true
    }),

    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: 'chunks/[id].css'
    }),

    hmr && new webpack.HotModuleReplacementPlugin(),
    hmr &&
      new ReactRefreshWebpackPlugin({
        overlay: {
          sockIntegration: 'whm'
        }
      }),

    new webpack.ProgressPlugin()
  ].filter(Boolean)
};
