// eslint-disable
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ForkTSCheckerPlugin = require('fork-ts-checker-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

const pathResolve = (pth) => path.resolve(__dirname, pth)

const SRC = path.join(__dirname, 'src')
const PUBLIC = path.join(__dirname, 'public')
const DIST = path.join(__dirname, 'dist')

const defaultEnv = {
  production: false,
  port: 3000,
  analyze: false,
}

const babelLoader = {
  loader: require.resolve('babel-loader'),
  options: {
    cacheDirectory: true,
    babelrc: true,
    configFile: pathResolve('babel.config.json'),
  },
}

const tsRule = (env) => ({
  test: /\.ts(x?)$/,
  use: [
    babelLoader,
    {
      loader: require.resolve('ts-loader'),
      options: {
        transpileOnly: true,
        configFile: path.join(__dirname, 'tsconfig.json'),
      },
    },
  ],
})

const cssLoader = (env) => ({
  test: /\.css$/,
  use: [
    env.production
      ? MiniCssExtractPlugin.loader // injeta tags de link para os arquivos css no html
      : 'style-loader', // injeta o css processados diretamente no arquivo html
    {
      loader: 'css-loader',
      options: {
        modules: { localIdentName: '[name]_[local]_[hash:base64:5]' },
        sourceMap: !env.production,
        url: false,
      },
    },
    'postcss-loader', // cria uma AST dos arquivos .css para serem processados por plugins
  ],
})

const fileLoader = {
  include: /public/,
  exclude: /\.ejs$/,
  type: 'asset/resource',
  generator: {
    filename: (pathdata) =>
      pathdata.filename.endsWith('.ttf') || pathdata.filename.endsWith('.txt')
        ? 'fonts/[hash][ext]'
        : pathdata.filename.endsWith('.json')
        ? 'config.json'
        : 'images/[hash][ext]',
  },
}

const resolve = {
  alias: {
    '@agiliza/__mocks__': pathResolve('src/__mocks__'),
    '@agiliza/api': pathResolve('src/api'),
    '@agiliza/theme': pathResolve('src/theme'),
    '@agiliza/constants': pathResolve('src/constants'),
    '@agiliza/components': pathResolve('src/components'),
    '@agiliza/curio': pathResolve('src/curio'),
    '@agiliza/redux': pathResolve('src/redux'),
    '@agiliza/epics': pathResolve('src/epics'),
    '@agiliza/views': pathResolve('src/views'),
    '@agiliza/utils': pathResolve('src/utils'),
    '@agiliza/public': pathResolve('public'),
    '@material-ui/styles': path.resolve('.', 'node_modules', '@material-ui/styles'),
  }, // Modified paths, modify tsconfig.json "paths"
  extensions: ['.ts', '.tsx', '.js'],
}

const makeCommonPlugins = (env) => [
  new MiniCssExtractPlugin({
    chunkFilename: env.production ? 'styles/[id].[contenthash].css' : 'styles/[id].css',
    filename: env.production ? 'styles/[name].[contenthash].css' : 'styles/[name].css',
  }),
  new CleanWebpackPlugin(),
  new ForkTSCheckerPlugin({
    typescript: {
      configFile: path.join(__dirname, 'tsconfig.json'),
    },
    eslint: {
      files: './**/*.{ts,tsx}', // required - same as command `eslint ./src/**/*.{ts,tsx,js,jsx} --ext .ts,.tsx,.js,.jsx`
    },
  }),
  new webpack.ProvidePlugin({
    process: 'process/browser',
  }),
  new webpack.EnvironmentPlugin({
    PUBLIC_PATH: '/',
    NODE_ENV: env.production ? 'production' : 'development',
    PRODUCTION: env.production,
    APP_TITLE: 'Agiliza - Cliente',
  }),
  new HtmlWebpackPlugin({
    template: path.join(__dirname, 'public', 'index.ejs'),
    favicon: path.join(PUBLIC, 'images', 'favicon.png'),
    title: 'Agiliza - Cliente',
    inject: false,
  }),
  new webpack.DefinePlugin({
    VERSION: JSON.stringify(require('./package.json').version),
  }),
]

const makeDevPlugins = (env) => [...makeCommonPlugins(env)]

const makeProdPlugins = (env) => [
  ...makeCommonPlugins(env),
  new CopyWebpackPlugin({
    patterns: [
      {
        from: PUBLIC,
        to: DIST,
        globOptions: { ignore: ['**/*.ejs', '**/*.png'] },
      },
    ],
  }),
]

const output = (env) => ({
  chunkFilename: env.production ? 'js/chunks/[name].[chunkhash].js' : 'js/chunks/[name].js',
  filename: env.production ? 'js/[name].[contenthash].js' : 'js/[name].js',
  path: DIST,
  publicPath: '/',
})

const devServer = (env) => ({
  contentBase: PUBLIC,
  disableHostCheck: true,
  port: env.port,
  stats: {
    all: false,
    modules: true,
    maxModules: 0,
    errors: true,
    warnings: false,
    version: true,
    colors: true,
  },
  inline: true,
  host: '0.0.0.0',
  historyApiFallback: true,
})

module.exports = (env) => {
  env = { ...defaultEnv, ...env }
  return {
    context: SRC,
    mode: env.production ? 'production' : 'development',
    entry: ['./index.tsx'],
    devtool: env.production ? undefined : 'eval-cheap-module-source-map',
    devServer: devServer(env),
    module: {
      rules: [cssLoader(env), fileLoader, tsRule(env)],
    },
    plugins: env.production ? makeProdPlugins(env) : makeDevPlugins(env),
    resolve,
    output: output(env),
    optimization: {
      minimize: true,
      minimizer: [
        // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
        `...`,
        new CssMinimizerPlugin(),
      ],
    },
    experiments: {
      topLevelAwait: true,
    },
  }
}
