import { writeFile } from "fs/promises";
import { dirname, isAbsolute, relative, resolve } from "path";
import { fileURLToPath } from "url";
import exports, { Configuration } from "webpack";

const { WatchIgnorePlugin } = exports;

let dirName = fileURLToPath(new URL(".", import.meta.url));

let generator = (env: any, argv: any): Configuration[] =>
{
    return [
        {
            target: "web",
            mode: env.production ? "production" : "development",
            entry: {
                main: "./src/index.ts",
                ...(
                    env.production ?
                    {} :
                    {
                        "tests/main.test": "./src/tests/main.test.ts"
                    })
            },
            output: {
                filename: "[name].js",
                path: resolve(dirName, "lib"),
                devtoolModuleFilenameTemplate: (context: any) =>
                {
                    let path = context.absoluteResourcePath;

                    // For regular files, this statement is true.
                    if (isAbsolute(path))
                    {
                        return path;
                    }
                    else
                    {
                        return `webpack://${context.namespace}/${context.resourcePath}${context.loaders === "" ? "" : `?${context.loaders}`}`;
                    }
                },
                libraryTarget: "module",
                chunkFormat: "module",
                environment: {
                    dynamicImport: true
                }
            },
            devtool: "source-map",
            resolve: {
                extensions: [
                    ".ts",
                    ".js"
                ],
                extensionAlias: {
                    ".js": [
                        ".js",
                        ".ts"
                    ],
                    ".mjs": [
                        ".mjs",
                        ".mts"
                    ],
                    ".cjs": [
                        ".cjs",
                        ".cts"
                    ]
                }
            },
            plugins: [
                new WatchIgnorePlugin(
                    {
                        paths: [
                            /\.d\.ts$/
                        ]
                    }),
                {
                    apply(compiler)
                    {
                        compiler.hooks.assetEmitted.tap(
                            {
                                name: "AdjustSourceMap"
                            },
                            async (file, { content, source, outputPath, compilation, targetPath }) =>
                            {
                                if (file.endsWith(".map"))
                                {
                                    try
                                    {
                                        let sourceMap = JSON.parse(content.toString());

                                        if (Array.isArray(sourceMap.sources))
                                        {
                                            sourceMap.sources = sourceMap.sources.map(
                                                (source: string) =>
                                                {
                                                    console.log(source);

                                                    // Prevent `webpack://` sources from being changed
                                                    if (isAbsolute(source))
                                                    {
                                                        // Change regular file paths to relative ones
                                                        return relative(dirname(targetPath), source);
                                                    }
                                                    else
                                                    {
                                                        return source;
                                                    }
                                                });

                                            // Overwrite old source map
                                            await writeFile(targetPath, JSON.stringify(sourceMap));
                                        }
                                    }
                                    catch {}
                                }
                            });
                    }
                }
            ],
            module: {
                rules: [
                    {
                        test: /\.([cm]?ts|tsx)$/,
                        exclude: /node_modules/,
                        use: [
                            {
                                loader: "ts-loader",
                                options: {
                                    configFile: resolve(dirName, "tsconfig.build.json"),
                                    projectReferences: true,
                                    compilerOptions: {
                                        outDir: resolve(dirName, "lib", "temp")
                                    }
                                }
                            }
                        ]
                    }
                ]
            },
            experiments: {
                outputModule: true
            }
        }
    ];
};

// eslint-disable-next-line import/no-default-export
export default generator;