import java.io.File;
import java.lang.module.ModuleFinder;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;

/** Bach's init program. */
class init {

  public static Path BIN = Path.of(".bach/bin");

  public static void main(String... args) throws Exception {
    var update = Files.isDirectory(BIN);
    if (update) {
      var module = ModuleFinder.of(BIN).find("com.github.sormuras.bach");
      if (module.isPresent()) Files.delete(Path.of(module.get().location().orElseThrow()));
    } else {
      Files.createDirectories(BIN);
    }

    var version = args.length == 0 ? "17-ea" : args[0];
    loadScript("bach").toFile().setExecutable(true);
    loadScript("bach.bat");
    loadScript("boot.java");
    loadScript("boot.jsh");
    loadScript("init.java");
    loadModule("com.github.sormuras.bach", version);

    var appendPathMessage =
        """

        Append `%s` to the PATH environment variable in order to call
        Bach's launch script without using that path prefix every time.
        """
            .formatted(BIN);
    var prefix = computePathPrefixToBachBinDirectory(() -> System.out.print(appendPathMessage));

    System.out.printf( // Next steps...
        """

        %sbach boot
          Launch a JShell session with Bach booted into it.
        %sbach --help
          Print Bach's help message.
        """,
        prefix, prefix);

    System.out.printf( // Updated/Initialized Bach ${VERSION} in ${DIRECTORY}.
        """

        %sd Bach %s in %s.
        """,
        update ? "Update" : "Initialize", version, Path.of("").toAbsolutePath());
  }

  static String computePathPrefixToBachBinDirectory(Runnable runnable) {
    var prefix = BIN.toString() + File.pathSeparator;
    var path = System.getenv("PATH");
    if (path == null) return prefix;
    var target = BIN.toString();
    var elements = List.of(path.split(File.pathSeparator));
    for (var element : elements) if (element.strip().equals(target)) return "";
    runnable.run();
    return prefix;
  }

  static Path loadScript(String name) throws Exception {
    var uri = "https://github.com/sormuras/bach/raw/main/.bach/bin/" + name;
    return copy(uri, name);
  }

  static void loadModule(String name, String version) throws Exception {
    var jar = name + "@" + version + ".jar";
    var uri = "https://github.com/sormuras/bach/releases/download/" + version + "/" + jar;
    copy(uri, jar);
  }

  static Path copy(String uri, String name) throws Exception {
    var file = BIN.resolve(name);
    try (var stream = new URL(uri).openStream()) {
      var size = Files.copy(stream, file, StandardCopyOption.REPLACE_EXISTING);
      System.out.printf("%,7d %s%n", size, file);
    }
    return file;
  }
}

@@ -627,16 +627,75 @@
 %0A    %7D%0A%0A
+    System.out.println(%22%22); // Load scripts and modules...%0A
     var 
@@ -1281,24 +1281,43 @@
 Message));%0A%0A
+    if (!update)%0A  
     System.o
@@ -1330,17 +1330,47 @@
 ntf( // 
-N
+On initialize, print possible n
 ext step
@@ -1371,19 +1371,19 @@
 t steps.
-..%0A
+%0A  
         
@@ -1391,24 +1391,26 @@
 %22%22%0A%0A        
+  
 %25sbach boot%0A
@@ -1409,16 +1409,18 @@
 ch boot%0A
+  
         
@@ -1475,24 +1475,26 @@
 it.%0A        
+  
 %25sbach --hel
@@ -1495,16 +1495,18 @@
  --help%0A
+  
         
@@ -1534,37 +1534,41 @@
 essage.%0A        
+  
 %22%22%22,%0A
+  
         prefix, 

Print next steps only on init [skip ci]