require("dotenv").config();

const path = require("path");
const VueLoaderPlugin = require("vue-loader/lib/plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const DotenvPlugin = require("dotenv-webpack");
const merge = require("webpack-merge");

const targetDir = path.normalize(path.join(__dirname, "dist"));

if (!process.env.NODE_ENV) {
  console.error("Please set NODE_ENV");
  process.exit(1);
}

const babelOpts = {
  presets: ["@babel/preset-env"],
};

const tsconfig = require("./tsconfig.json");
const pathAliases = Object.entries(tsconfig.compilerOptions.paths || []).reduce((aliases, pair) => {
  let alias = pair[0];
  if (alias.endsWith("/*")) alias = alias.slice(0, -2);

  let aliasPath = pair[1][0];
  if (aliasPath.endsWith("/*")) aliasPath = aliasPath.slice(0, -2);

  aliases[alias] = path.resolve(__dirname, aliasPath);
  return aliases;
}, {});

let config = {
  entry: "./src/main.ts",
  output: {
    filename: "[name].[hash].js",
    path: targetDir,
    publicPath: "/",
  },
  module: {
    rules: [
      // Vue / Babel / Typescript
      {
        test: /\.vue$/,
        use: ["vue-loader"],
      },
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "babel-loader",
            options: babelOpts,
          },
          {
            loader: "ts-loader",
            options: {
              appendTsSuffixTo: [/\.vue$/],
            },
          },
        ],
      },
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: babelOpts,
        },
      },
      {
        test: /\.js$/,
        use: ["source-map-loader"],
        enforce: "pre",
      },

      // Stylesheets
      {
        test: /\.p?css$/,
        use: [
          "vue-style-loader",
          {
            loader: "css-loader",
            options: {
              importLoaders: 1,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              ident: "postcss",
              plugins: (loader) => {
                const plugins = [
                  require("postcss-import")({
                    resolve(id, base, options) {
                      // Since WebStorm doesn't resolve imports from node_modules without a tilde (~) prefix,
                      // strip the tilde here to get the best of both worlds (webstorm support + postcss-import support)
                      if (id[0] === "~") id = id.slice(1);
                      // Call the original resolver after stripping the tilde
                      return require("postcss-import/lib/resolve-id")(id, base, options);
                    },
                  }),
                  require("postcss-nesting")(),
                  require("tailwindcss")(),
                ];

                if (process.env.NODE_ENV === "production") {
                  plugins.push(require("postcss-preset-env")(), require("cssnano")());
                }

                return plugins;
              },
            },
          },
        ],
      },

      // Images/files
      {
        test: /\.(png|jpg)$/i,
        use: {
          loader: "file-loader",
          options: {
            name: "[name]-[hash].[ext]",
          },
        },
      },

      // HTML
      {
        test: /\.html$/,
        use: [
          {
            loader: "html-loader",
            options: {
              root: path.resolve(__dirname, "src"),
              attrs: ["img:src", "link:href"],
              ...(process.env.NODE_ENV === "production" && {
                minimize: true,
                removeComments: true,
                collapseWhitespace: true,
              }),
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: "src/index.html",
      files: {
        css: ["./src/style/initial.pcss"],
        js: ["./src/main.ts"],
      },
    }),
    new DotenvPlugin(),
  ],
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".mjs", ".vue"],
    alias: pathAliases,
  },
};

if (process.env.NODE_ENV === "production") {
  config = merge(config, {
    mode: "production",
    devtool: "source-map",
  });
} else {
  config = merge(config, {
    mode: "development",
    devtool: "eval",
    devServer: {
      ...(process.env.DEV_HOST ? { host: process.env.DEV_HOST } : undefined),
      historyApiFallback: true,
      port: 1234,
    },
  });
}

module.exports = config;