// @ts-check
// cSpell:ignore glitchtip
// webpack.config.js
const childProcess = require("child_process");
const fs = require("fs");
const path = require("path");

const CopyPlugin = require("copy-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const webpack = require("webpack");

// @ts-ignore
const packageJSON = require("./package.json");

const isDevServer = process.env.WEBPACK_SERVE;

const dotEnvPath = path.resolve(
  process.cwd(),
  `.env${isDevServer ? `.local` : ""}`,
);
require("dotenv").config({
  path: dotEnvPath,
});

const WEBSOCKET_HOST =
  isDevServer && process.env.API_BASE_URL
    ? new URL(process.env.API_BASE_URL).host
    : process.env.WEBSOCKET_HOST || "";

const DOCS_URL = process.env.DOCS_URL
  ? new URL(process.env.DOCS_URL)
  : isDevServer
    ? "https://docs.browsertrix.com/"
    : "/docs/";

// Get git info for release version info

/**
 * @param {string} cmd
 * @param {string} defValue
 */
const execCommand = (cmd, defValue) => {
  try {
    return childProcess.execSync(cmd).toString().trim();
  } catch (e) {
    return defValue;
  }
};

// Local dev only
// Git branch and commit hash is used to add build info to error reporter when running locally
const gitBranch =
  process.env.GIT_BRANCH_NAME ||
  execCommand("git rev-parse --abbrev-ref HEAD", "unknown");

const commitHash =
  process.env.GIT_COMMIT_HASH ||
  execCommand("git rev-parse --short HEAD", "unknown");

const shoelaceAssetsSrcPath = path.resolve(
  __dirname,
  "node_modules/@shoelace-style/shoelace/dist/assets",
);
const shoelaceAssetsPublicPath = "shoelace/assets";

const version = (() => {
  if (process.env.VERSION) {
    return process.env.VERSION;
  }

  try {
    return fs.readFileSync("../version.txt", { encoding: "utf-8" }).trim();
  } catch (e) {
    /* empty */
  }

  return packageJSON.version;
})();

/** @type {import('webpack').Configuration} */
const main = {
  entry: "./src/index.ts",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: `js/[name]${isDevServer ? "" : ".[contenthash]"}.js`,
    publicPath: "/",
    hashFunction: "xxhash64",
  },

  module: {
    rules: [
      {
        test: /\.ts$/,
        include: path.resolve(__dirname, "src"),
        use: [
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                syntax: "postcss-lit",
                plugins: ["tailwindcss", "autoprefixer"],
              },
            },
          },
          {
            loader: "ts-loader",
            options: {
              onlyCompileBundledFiles: true,
              transpileOnly: true,
            },
          },
        ],
        exclude: /node_modules/,
      },
      {
        // Global styles and assets, like fonts and Shoelace,
        // that get added to document styles
        test: /\.css$/,
        include: [
          path.resolve(__dirname, "src"),
          path.resolve(__dirname, "node_modules/@shoelace-style/shoelace"),
        ],
        exclude: /\.stylesheet\.css$/,
        use: [
          "style-loader",
          { loader: "css-loader", options: { importLoaders: 1 } },
          "postcss-loader",
        ],
      },
      {
        // CSS loaded as raw string and used as a CSSStyleSheet
        test: /\.stylesheet\.css$/,
        type: "asset/source",
        include: [path.resolve(__dirname, "src")],
        use: ["postcss-loader"],
      },
      {
        test: /\.html$/,
        include: path.resolve(__dirname, "src"),
        loader: "html-loader",
      },
      {
        test: /\.(woff(2)?|ttf|svg|webp|avif)(\?v=\d+\.\d+\.\d+)?$/,
        include: path.resolve(__dirname, "src"),
        type: "asset/resource",
      },
    ],
  },

  resolve: {
    extensions: [".ts", ".js"],
    // @ts-ignore
    plugins: [new TsconfigPathsPlugin()],
  },

  plugins: [
    // Shim polyfill
    new webpack.ProvidePlugin({
      "Intl.DurationFormat": path.resolve(
        __dirname,
        "lib/intl-durationformat.js",
      ),
    }),

    new webpack.DefinePlugin({
      "window.process.env.WEBSOCKET_HOST": JSON.stringify(WEBSOCKET_HOST),
    }),

    new webpack.optimize.LimitChunkCountPlugin({
      maxChunks: 12,
    }),

    new ForkTsCheckerWebpackPlugin({
      typescript: {
        configOverwrite: {
          exclude: ["**/*.test.ts", "tests/**/*.ts", "playwright.config.ts"],
        },
      },
    }),

    new HtmlWebpackPlugin({
      template: "src/index.ejs",
      templateParameters: {
        glitchtip_dsn: process.env.GLITCHTIP_DSN || "",
        environment: isDevServer ? "development" : "production",
        docsUrl: DOCS_URL,
        version,
        gitBranch,
        commitHash,
      },
      // TODO this breaks shoelace forms, but seems HMR is broken anyway?
      // // Need to block during local development for HMR:
      // inject: isDevServer ? "head" : true,
      // scriptLoading: isDevServer ? "blocking" : "defer",
      inject: true,
      scriptLoading: "defer",
    }),

    new CopyPlugin({
      patterns: [
        // Copy Shoelace assets to dist/shoelace
        {
          from: shoelaceAssetsSrcPath,
          to: path.resolve(__dirname, "dist", shoelaceAssetsPublicPath),
        },
        // Copy custom icon library
        {
          from: path.resolve(__dirname, "src/assets/icons"),
          to: path.resolve(__dirname, "dist", "assets/icons"),
        },
        // Copy favicons to root
        {
          from: path.resolve(__dirname, "src/assets/favicons"),
          to: path.resolve(__dirname, "dist"),
        },
        // Copy app manifest
        {
          from: path.resolve(__dirname, "src/manifest.webmanifest"),
          to: path.resolve(__dirname, "dist"),
        },
      ],
    }),
    // @ts-ignore
    ...(process.env.BUNDLE_ANALYZER
      ? [new (require("webpack-bundle-analyzer").BundleAnalyzerPlugin)()]
      : []),
  ],
};

/** @type {import('webpack').Configuration} */
const vnc = {
  entry: "./node_modules/@novnc/novnc/core/rfb.js",
  experiments: { outputModule: true },
  output: {
    filename: "js/novnc.js",
    library: {
      type: "module",
    },
    hashFunction: "xxhash64",
  },
};
/** @type {[import('webpack').Configuration, import('webpack').Configuration]} */
module.exports = [main, vnc];
