// biome-ignore lint/correctness/noNodejsModules: this is backend side
import { parse, resolve } from "node:path";
import inject from "@rollup/plugin-inject";
import { glob } from "glob";
import { type AliasOptions, type UserConfig, defineConfig } from "vite";
import type { Rollup } from "vite";
import { viteStaticCopy } from "vite-plugin-static-copy";
import tsconfig from "./tsconfig.json";

const outDir = resolve(__dirname, "./staticfiles/generated/bundled");
const vendored = resolve(outDir, "vendored");
const nodeModules = resolve(__dirname, "node_modules");
const collectedFiles = glob.sync(
  "./!(static)/static/bundled/**/*?(-)index.?(m)[j|t]s?(x)",
);

/**
 * Grabs import aliases from tsconfig for #module: imports
 **/
function getAliases(): AliasOptions {
  const aliases: AliasOptions = {};
  for (const [key, value] of Object.entries(tsconfig.compilerOptions.paths)) {
    aliases[key] = resolve(__dirname, value[0]);
  }
  return aliases;
}

/**
 * Helper function that finds the relative path of an index.js/ts file in django static folders
 **/
function getRelativeAssetPath(path: string): string {
  let relativePath: string[] = [];
  const fullPath = parse(path);
  for (const dir of fullPath.dir.split("/").reverse()) {
    if (dir === "bundled") {
      break;
    }
    relativePath.push(dir);
  }
  // We collected folders in reverse order, we put them back in the original order
  relativePath = relativePath.reverse();
  relativePath.push(fullPath.name);
  return relativePath.join("/");
}

// biome-ignore lint/style/noDefaultExport: this is recommended by documentation
export default defineConfig((config: UserConfig) => {
  return {
    base: "/static/bundled/",
    appType: "custom",
    build: {
      outDir: outDir,
      manifest: true, // goes into .vite/manifest.json in the build folder
      modulePreload: false, // would require `import 'vite/modulepreload-polyfill'` to always be injected
      emptyOutDir: config.mode === "production", // Avoid rebuilding everything in dev mode
      rollupOptions: {
        input: collectedFiles,
        output: {
          // Mirror architecture of static folders in generated .js and .css
          entryFileNames: (chunkInfo: Rollup.PreRenderedChunk) => {
            if (chunkInfo.facadeModuleId !== null) {
              return `${getRelativeAssetPath(chunkInfo.facadeModuleId)}.[hash].js`;
            }
            return "[name].[hash].js";
          },
          assetFileNames: (chunkInfo: Rollup.PreRenderedAsset) => {
            if (
              chunkInfo.names?.length === 1 &&
              chunkInfo.originalFileNames?.length === 1 &&
              collectedFiles.includes(chunkInfo.originalFileNames[0])
            ) {
              return `${getRelativeAssetPath(chunkInfo.originalFileNames[0])}.[hash][extname]`;
            }
            return "[name].[hash][extname]";
          },
          chunkFileNames: "[name].[hash].js",
        },
      },
    },
    resolve: {
      alias: getAliases(),
    },

    plugins: [
      inject({
        // biome-ignore lint/style/useNamingConvention: that's how it's called
        Alpine: "alpinejs",
        htmx: "htmx.org",
      }),
      viteStaticCopy({
        targets: [
          {
            src: resolve(nodeModules, "jquery/dist/jquery.min.js"),
            dest: vendored,
          },
          {
            src: resolve(nodeModules, "jquery-ui/dist/jquery-ui.min.js"),
            dest: vendored,
          },
          {
            src: resolve(nodeModules, "jquery.shorten/src/jquery.shorten.min.js"),
            dest: vendored,
          },
        ],
      }),
    ],
    optimizeDeps: {
      include: ["jquery"],
    },
  } satisfies UserConfig;
});