import * as esbuild from "npm:esbuild";
import { denoPlugins } from "jsr:@luca/esbuild-deno-loader";
import init, { minify } from "npm:@minify-html/wasm";
import { relative } from "jsr:@std/path@^1.0.8/relative";

await esbuild.build({
    plugins: [
        ...denoPlugins(),
    ],
    entryPoints: ["../shared/utils/index.ts"],
    outfile: "./public/js/shared.bundle.js",
    bundle: true,
    minify: true,
    format: "esm",
});
esbuild.stop();

const JS_FROM_DIR = "./src/js/";
const JS_TO_DIR = "./public/js/";
const JS_EXCLUDE = ".bundle.ts";
const watcherJS = Deno.watchFs(JS_FROM_DIR);

const cwd = Deno.cwd();

function getPublic(paths: string[]): string[] {
    return paths.map((path) =>
        path.replace(JS_FROM_DIR, JS_TO_DIR).replace(".ts", ".js")
    );
}

(async () => {
    for await (const event of watcherJS) {
        const paths = event.paths.filter((path) =>
            !path.endsWith(JS_EXCLUDE) &&
            (path.endsWith(".ts") || path.endsWith(".js"))
        );
        if (event.kind === "modify" || event.kind === "create") {
            await esbuild.build({
                plugins: [
                    ...denoPlugins(),
                ],
                entryPoints: paths,
                outbase: JS_FROM_DIR,
                outdir: JS_TO_DIR,
                bundle: false,
                minify: true,
                format: "esm",
            });
            esbuild.stop();

            for (
                const path of getPublic(paths)
            ) {
                try {
                    const content = await Deno.readTextFile(path);

                    const staticImportRegex =
                        /(import\s*[^'"]+from\s*['"])([^'"]+?)(\.ts)(['"])/g;

                    const dynamicImportRegex =
                        /(import\(\s*['"])([^'"]+?)(\.ts)(['"]\s*\))/g;

                    let updatedContent = content.replace(
                        staticImportRegex,
                        (_, p1, p2, p3, p4) => {
                            return `${p1}${p2}.js${p4}`;
                        },
                    );

                    updatedContent = updatedContent.replace(
                        dynamicImportRegex,
                        (_, p1, p2, p3, p4) => {
                            return `${p1}${p2}.js${p4}`;
                        },
                    );

                    await Deno.writeTextFile(path, updatedContent);
                } catch (e) {}
            }
        } else if (event.kind === "remove") {
            try {
                for (const path of getPublic(paths)) {
                    await Deno.remove(path);
                }
            } catch (e) {}
        }
    }
})();

const HTML_FROM_DIR = "./src/views/";
const HTML_TO_DIR = "./views/";

const watcherHTML = Deno.watchFs(HTML_FROM_DIR);

function minifyHTML(html: Uint8Array) {
    const data = minify(html, {
        keep_spaces_between_attributes: true,
        keep_comments: true,
        preserve_brace_template_syntax: true,
    });

    return data;
}

function getHTMLToPath(path: string) {
    return path.replace(HTML_FROM_DIR, HTML_TO_DIR);
}

(async () => {
    for await (const event of watcherHTML) {
        const paths = event.paths.filter((path) => path.endsWith(".html"));
        if (event.kind === "modify" || event.kind === "create") {
            try {
                for (const path of paths) {
                    const html = await Deno.readFile(path);

                    const data = minifyHTML(html);

                    await Deno.writeFile(getHTMLToPath(path), data);
                }
            } catch (_) {}
        } else if (event.kind === "remove") {
            try {
                for (const path of paths) {
                    await Deno.remove(getHTMLToPath(path));
                }
            } catch (_) {}
        }
    }
})();
