// Injected by backend: maps normalized paths to temp storage hashes (or null)
const TEMP_SCRIPT_REFS = TEMP_SCRIPT_REFS_PLACEHOLDER;

const p = {
  name: "windmill-relative-resolver",
  async setup(build) {
    const { writeFileSync, readFileSync, mkdirSync } = await import("fs");
    const { dirname, resolve, join } = await import("node:path");

    const base_internal_url = "BASE_INTERNAL_URL".replace(
      "localhost",
      "127.0.0.1"
    );

    const w_id = "W_ID";
    const current_path = "CURRENT_PATH";
    const token = "TOKEN";

    const cdir = resolve("./");
    const cdirNoPrivate = cdir.replace(/^\/private/, ""); // for macos
    // On Windows, normalize path to POSIX format to match args.path from Bun's resolver
    const cdirPosix = cdir.replace(/\\/g, "/").replace(/^[a-zA-Z]:/, "");
    const filterResolve = new RegExp(
      `^(?!\\.\/main\\.ts)(?!\\.\/_wm_)(?!${cdir}\/main\\.ts)(?!${cdir}\/_wm_)(?!${cdirPosix}\/main\\.ts)(?!${cdirPosix}\/_wm_)(?!(?:/private)?${cdirNoPrivate}\/wrapper\\.mjs).*\\.ts$`
    );

    let cdirNodeModules = `${cdir}/node_modules/`;

    const filterLoad = new RegExp(`^${cdir}\/main\\.ts$`);
    const transpiler = new Bun.Transpiler({
      loader: "ts",
    });

    function replaceRelativeImports(code) {
      const imports = transpiler.scanImports(code);
      for (const imp of imports) {
        if (imp.kind == "import-statement") {
          if (
            (imp.path.startsWith(".") ||
              imp.path.startsWith("/u/") ||
              imp.path.startsWith("/f/")) &&
            !imp.path.endsWith(".ts")
          ) {
            code = code.replaceAll(imp.path, imp.path + ".ts");
          }
        }
      }
      return {
        contents: code,
      };
    }

    build.onLoad({ filter: filterLoad }, async (args) => {
      const code = readFileSync(args.path, "utf8");
      return replaceRelativeImports(code);
    });

    build.onLoad({ filter: /.*\.url$/ }, async (args) => {
      const url = readFileSync(args.path, "utf8");
      const req = await fetch(url, {
        method: "GET",
        headers: {
          Authorization: "Bearer " + token,
        },
      });
      if (!req.ok) {
        throw new Error(
          `Failed to find relative import at ${url}`,
          req.statusText
        );
      }
      const contents = await req.text();
      return {
        contents: replaceRelativeImports(contents).contents,
        loader: "tsx",
      };
    });

    build.onResolve({ filter: filterResolve }, (args) => {
      if (args.importer?.startsWith(cdirNodeModules)) {
        return undefined;
      }

      // Check if the import resolves to a local module file (written by write_module_files).
      // Only check relative paths — absolute/bare specifiers should fall through to the
      // remote resolver, matching the Windows loader pattern.
      if (args.path.startsWith(".")) {
        const localPath = resolve(cdir, args.path);
        try {
          readFileSync(localPath);
          return { path: localPath };
        } catch {}
      }

      const file_path =
        args.importer == "./main.ts" || args.importer == resolve("./main.ts")
          ? current_path
          : args.importer.replace(cdir + "/", "");

      const isRelative = !args.path.startsWith("/");
      const endExt = args.path.endsWith(".ts") ? "" : ".ts";
      const pathNoExt = args.path.replace(/\.ts$/, "");

      // Lookup temp script hash
      const normalized = (isRelative ? join(dirname(file_path), pathNoExt) : pathNoExt.slice(1)).replace(/\\/g, "/");
      const hash = TEMP_SCRIPT_REFS?.[normalized];

      const url = (isRelative
        ? `${base_internal_url}/api/w/${w_id}/scripts/raw_unpinned/p/${file_path}/../${args.path}${endExt}`
        : `${base_internal_url}/api/w/${w_id}/scripts/raw_unpinned/p/${args.path}${endExt}`
      ) + (hash ? `?temp_script_hash=${hash}` : "");
      const file = isRelative
        ? resolve("./" + file_path + "/../" + args.path + ".url")
        : resolve("./" + args.path + ".url");
      mkdirSync(dirname(file), { recursive: true });
      writeFileSync(file, url);
      return {
        path: file,
      };
    });
  },
};
