package build;

import com.github.sormuras.bach.Bach;
import com.github.sormuras.bach.BuildProgram;
import com.github.sormuras.bach.ProjectInfo;
import com.github.sormuras.bach.tool.Command;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.util.spi.ToolProvider;

public class BachBuilder implements BuildProgram {

  public static void main(String... args) {
    new BachBuilder().build(Bach.ofSystem(), args);
  }

  private static String version() {
    try {
      return Files.readString(Path.of("VERSION"));
    } catch (Exception exception) {
      throw new Error("Read VERSION failed: ", exception);
    }
  }

  public BachBuilder() {}

  @Override
  public void build(Bach bach, String... args) {
    var out = bach.printStream();
    var err = System.err;
    var version = args.length == 0 ? version() : args[0];
    var jarslug = args.length < 2 ? version : args[1];
    out.println("Build Bach " + version + " using Bach " + Bach.version());
    var info = getClass().getModule().getAnnotation(ProjectInfo.class);
    System.out.println(info);
    var start = Instant.now();
    try {
      new Simple(out, err, version, jarslug).run();
    } catch (Exception exception) {
      err.println(exception);
    } finally {
      out.printf("Build took %d milliseconds%n", Duration.between(start, Instant.now()).toMillis());
    }
  }

  @Override
  public String toString() {
    return "Bach's Build Program";
  }

  static class Simple {

    final PrintStream out;
    final PrintStream err;
    final String version;
    final String jarslug;

    final Path workspace = Path.of(".bach/workspace");

    Simple(PrintStream out, PrintStream err, String version, String jarslug) {
      this.out = out;
      this.err = err;
      this.version = version;
      this.jarslug = jarslug;
    }

    void run() throws Exception {
      var module = "com.github.sormuras.bach";
      var classes = workspace.resolve("classes/" + Runtime.version().feature());
      var modules = Files.createDirectories(workspace.resolve("modules"));
      var file = modules.resolve(module + "@" + jarslug + ".jar");

      run(
          Command.builder("javac")
              .with("--module", module)
              .with("--module-source-path", "./*/main/java")
              .with("--release", 16)
              .with("-g")
              .with("-parameters")
              .with("-Werror")
              .with("-Xlint")
              .with("-encoding", "UTF-8")
              .with("-d", classes)
              .build());

      run(
          Command.builder("jar")
              .with("--create")
              .with("--file", file)
              .with("--main-class", module + ".Main")
              .with("--module-version", version)
              .with("-C", classes.resolve(module), ".")
              .with("-C", Path.of(module, "main", "java"), ".")
              .build());

      var api = workspace.resolve("documentation/api");
      run(
          Command.builder("javadoc")
              .with("--module", module)
              .with("--module-source-path", "./*/main/java")
              .with("-windowtitle", "\uD83C\uDFBC Bach " + version)
              .with("-header", "\uD83C\uDFBC Bach " + version)
              .with("-use")
              .with("-linksource")
              .with("-notimestamp")
              .with("-Werror")
              .with("-Xdoclint")
              .with("-encoding", "UTF-8")
              .with("-quiet")
              .with("-d", api)
              .build());

      run(
          Command.builder("jar")
              .with("--create")
              .with("--file", api.getParent().resolve("bach-api-" + version + ".zip"))
              .with("--no-manifest")
              .with("-C", api, ".")
              .build());
    }

    void run(Command command) {
      out.printf("<< %s%n", command);
      var tool = ToolProvider.findFirst(command.name()).orElseThrow();
      var normal = new StringWriter();
      var errors = new StringWriter();
      var code = tool.run(new PrintWriter(normal), new PrintWriter(errors), command.args());

      if (!normal.getBuffer().isEmpty()) out.println(normal.toString().indent(3).stripTrailing());
      if (!errors.getBuffer().isEmpty()) err.println(errors);

      if (code != 0) throw new Error(tool.name() + " returned error code: " + code);
    }
  }
}

@@ -195,53 +195,46 @@
 ort 
-java.io.PrintStream;%0Aimport java.io.PrintWrit
+com.github.sormuras.bach.tool.ToolRunn
 er;%0A
@@ -248,28 +248,27 @@
 java.io.
-StringWriter
+PrintStream
 ;%0Aimport
@@ -343,16 +343,16 @@
 ration;%0A
+
 import j
@@ -372,43 +372,8 @@
 ant;
-%0Aimport java.util.spi.ToolProvider;
 %0A%0Apu
@@ -1719,16 +1719,64 @@
 space%22);
+%0A    final ToolRunner runner = new ToolRunner();
 %0A%0A    Si
@@ -4010,489 +4010,44 @@
     
-var tool = ToolProvider.findFirst(command.name()).orElseThrow();%0A      var normal = new StringWriter();%0A      var errors = new StringWriter();%0A      var code = tool.run(new PrintWriter(normal), new PrintWriter(errors), command.args());%0A%0A      if (!normal.getBuffer().isEmpty()) out.println(normal.toString().indent(3).stripTrailing());%0A      if (!errors.getBuffer().isEmpty()) err.println(errors);%0A%0A      if (code != 0) throw new Error(tool.name() + %22 returned error code: %22 + code
+runner.run(command).checkSuccessful(
 );%0A 

Use tool runner provided by Bach