import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import { globbySync } from 'globby';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import path from 'path';
import sass from 'sass';
import TsConfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
import VueLoaderPlugin from 'vue-loader/lib/plugin.js';
import VuetifyLoaderPlugin from 'vuetify-loader/lib/plugin.js';
import LiveReloadPlugin from 'webpack-livereload-plugin';

const isProd = process.env.NODE_ENV === 'production';
const __dirname = path.resolve();

const config = (name) => {
  const entry = globbySync('*/main.ts', {cwd: `src/${name}`})
    .reduce((prev, curr) => {
      prev[path.basename(path.dirname(curr))] = `./${curr}`;
      return prev;
    }, {});

  let plugins = [];
  if (!isProd) {
    plugins.push(
      new LiveReloadPlugin({
        port: 0,
        appendScriptTag: true,
      })
    );
  }
  plugins = plugins.concat(
    [
      new VueLoaderPlugin(),
      ...Object.keys(entry).map(
        (entryName) =>
          new HtmlWebpackPlugin({
            filename: `${entryName}.html`,
            chunks: [entryName],
            title: entryName,
            template: 'template.html',
          }),
      ),
      new ForkTsCheckerWebpackPlugin({
        typescript: {
          extensions: {
            vue: true,
          },
        },
      }),
    ]
  );
  if (isProd) {
    plugins.push(
      new MiniCssExtractPlugin({
        filename: 'css/[name].css',
        ignoreOrder: name === 'dashboard', // To ignore Vuetify issues, good idea or not?
      })
    );
  }
  if (name === 'dashboard') {
    plugins.push(
      new VuetifyLoaderPlugin(),
    );
  }

  return {
    context: path.resolve(__dirname, `src/${name}`),
    mode: isProd ? 'production' : 'development',
    target: 'web',
    // devtool: isProd ? undefined : 'cheap-source-map',
    entry,
    output: {
      path: path.resolve(__dirname, name),
      filename: 'js/[name].js',
    },
    resolve: {
      extensions: ['.js', '.ts', '.tsx', '.json'],
      alias: {
        // vue: 'vue/dist/vue.esm.js',
        vue: path.resolve(__dirname, 'node_modules/vue/dist/vue.esm.js'),
      },
      plugins: [
        new TsConfigPathsPlugin({
          configFile: 'tsconfig.browser.json',
        }),
      ],
    },
    module: {
      rules: [
        {
          test: /\.vue$/,
          loader: 'vue-loader',
        },
        {
          test: /\.css$/,
          exclude: /\.theme.css$/,
          use: [
            (isProd) ? MiniCssExtractPlugin.loader : 'vue-style-loader',
            {
              loader: 'css-loader',
              options: {
                esModule: false,
              },
            },
          ],
        },
        {
          test: /\.theme\.css$/,
          use: [
            {
              loader: 'style-loader',
              options: {
                injectType: 'lazyStyleTag',
              },
            },
            {
              loader: 'css-loader',
              options: {
                esModule: false,
              },
            },
          ]
        },
        {
          test: /\.s(c|a)ss$/,
          use: [
            (isProd) ? MiniCssExtractPlugin.loader : 'vue-style-loader',
            {
              loader: 'css-loader',
              options: {
                esModule: false,
              },
            },
            {
              loader: 'sass-loader',
              options: {
                implementation: sass,
              },
            },
          ],
        },
        {
          test: /\.(woff(2)?|ttf|eot)$/,
          type: 'asset/resource',
          generator: {
            filename: 'font/[name][ext]',
          },
        },
        {
          test: /\.svg?$/,
          type: 'asset/resource',
          generator: {
            filename: 'font/[name][ext]',
          },
          include: [
            path.resolve(__dirname, `src/${name}/_misc/fonts`),
          ],
        },
        {
          test: /\.(png|svg|gif)?$/,
          type: 'asset/resource',
          generator: {
            filename: 'img/[name]-[contenthash][ext]',
          },
          exclude: [
            path.resolve(__dirname, `src/${name}/_misc/fonts`),
          ],
        },
        {
          test: /\.tsx?$/,
          loader: 'ts-loader',
          options: {
            transpileOnly: true, // ForkTsCheckerWebpackPlugin will do type checking
            appendTsSuffixTo: [/\.vue$/],
          },
        },
        {
          test: /\.mp3?$/,
          type: 'asset/resource',
          generator: {
            filename: 'sfx/[name][ext]',
          },
        },
      ],
    },
    plugins,
    optimization: (isProd) ? {
      // v5 migration guide says to reconsider this, so maybe change in the future?
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          common: {
            minChunks: 2,
          },
          defaultVendors: false,
          default: false,
        },
      },
    } : undefined,
  };
}

export default [
  config('dashboard'),
  config('graphics'),
];
