const path = require("path");
const fs = require("fs");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");

function readPages(dir) {
  const pageNums = fs
    .readdirSync(dir)
    .map(f => { const m = f.match(/^(\d+)\.html$/); return m ? parseInt(m[1], 10) : null; })
    .filter(n => n !== null)
    .sort((a, b) => a - b);

  return pageNums.map(n => {
    let content = fs.readFileSync(path.join(dir, `${n}.html`), "utf8");
    content = content.replace(/[ \t]*<link[^>]+>\n?/g, "").trim();
    return { n, content };
  });
}

function bookTemplate(title, logoText, dir) {
  const pages = readPages(dir);
  const data = JSON.stringify({ title, logoText, pages });
  return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>${title}</title>
  <link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600;700&family=Crimson+Text:ital,wght@0,400;0,600;1,400&family=Inconsolata:wght@400;600&display=swap" rel="stylesheet" />
  <link rel="stylesheet" href="/css/book-page.css" />
  <link rel="stylesheet" href="/css/book-layout.css" />
</head>
<body>
  <script>window.__BOOK_DATA__ = ${data};</script>
  <div id="root"></div>
</body>
</html>`;
}

module.exports = (env, argv) => {
  const isProd = argv.mode === "production";

  return {
    entry: {
      sheet: "./src/sheet-main.tsx",
      book: "./src/book.tsx",
    },
    output: {
      filename: isProd ? "[name].[contenthash].js" : "[name].js",
      path: path.resolve(__dirname, "dist"),
      clean: true,
      iife: false,
    },
    module: {
      rules: [
        {
          test: /\.(js|jsx|ts|tsx)$/,
          exclude: /node_modules/,
          use: {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-react", "@babel/preset-typescript"],
            },
          },
        },
        {
          test: /\.ya?ml$/,
          use: "yaml-loader",
        },
        {
          test: /\.css$/,
          use: [
            isProd ? MiniCssExtractPlugin.loader : "style-loader",
            "css-loader",
          ],
        },
      ],
    },
    resolve: {
      extensions: [".ts", ".tsx", ".js", ".jsx"],
    },
    plugins: [
      ...(isProd
        ? [new MiniCssExtractPlugin({ filename: "[name].[contenthash].css" })]
        : []),
      // Register book HTML source files as compilation dependencies so webpack
      // watches them in dev mode and triggers a rebuild when they change.
      {
        apply(compiler) {
          compiler.hooks.afterCompile.tap("WatchBookPages", (compilation) => {
            const bookDirs = [
              path.resolve(__dirname, "books/core"),
              path.resolve(__dirname, "books/natural-fantasy-atlas"),
            ];
            for (const dir of bookDirs) {
              try {
                fs.readdirSync(dir)
                  .filter(f => f.endsWith(".html") && f !== "index.html")
                  .forEach(f => compilation.fileDependencies.add(path.join(dir, f)));
              } catch (_) {}
            }
          });
        },
      },
      new HtmlWebpackPlugin({
        template: "./src/fabula-ultima-sheet.html",
        filename: "index.html",
        chunks: ["sheet"],
        scriptLoading: "blocking",
      }),
      new HtmlWebpackPlugin({
        templateContent: () => bookTemplate(
          "Fabula Ultima - Core Rulebook",
          "Core Rules",
          "./books/core"
        ),
        filename: "books/core/index.html",
        chunks: ["book"],
        scriptLoading: "blocking",
      }),
      new HtmlWebpackPlugin({
        templateContent: () => bookTemplate(
          "Fabula Ultima - Natural Fantasy Atlas",
          "Natural Fantasy Atlas",
          "./books/natural-fantasy-atlas"
        ),
        filename: "books/natural-fantasy-atlas/index.html",
        chunks: ["book"],
        scriptLoading: "blocking",
      }),
      new CopyWebpackPlugin({
        patterns: [
          {
            from: "books",
            to: "books",
            globOptions: { ignore: ["**/index.html"] },
          },
        ],
      }),
      new CopyWebpackPlugin({
        patterns: [
          {
            from: "css",
            to: "css",
            globOptions: { ignore: ["**/index.html"] },
          },
        ],
      }),
    ],
    optimization: {
      minimizer: ["...", new CssMinimizerPlugin()],
      splitChunks: {
        cacheGroups: {
          styles: {
            name: "styles",
            type: "css/mini-extract",
            chunks: "all",
            enforce: true,
          },
        },
      },
    },
    devServer: {
      static: [
        { directory: path.resolve(__dirname, "dist") },
        { directory: path.resolve(__dirname, "books"), publicPath: "/books" },
        { directory: path.resolve(__dirname, "css"), publicPath: "/css" },
      ],
      port: 8080,
      open: true,
      historyApiFallback: {
        rewrites: [
          { from: /^\/book$/, to: "/book/index.html" },
        ],
      },
    },
  };
};
