package build;

import com.github.sormuras.bach.Bach;
import com.github.sormuras.bach.Command;
import com.github.sormuras.bach.ToolResponse;
import com.github.sormuras.bach.ToolRunner;
import java.io.PrintWriter;
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 Build implements ToolProvider {

  public static void main(String... args) {
    new Build().run(System.out, System.err, args);
  }

  public Build() {}

  @Override
  public String name() {
    return "build";
  }

  @Override
  public int run(PrintWriter out, PrintWriter err, String... args) {
    out.println(getClass().getSimpleName() + " in " + getClass().getModule());
    out.println("With args = [" + String.join(", ", args) + "]");
    var version = args.length == 0 ? "15-ea" : args[0];
    var start = Instant.now();
    try {
      new Simple(out, err, version).run();
      return 0;
    } catch (Exception exception) {
      err.println(exception);
      return 1;
    } finally {
      out.printf("Build took %d milliseconds%n", Duration.between(start, Instant.now()).toMillis());
    }
  }

  static class Simple {

    final PrintWriter out;
    final PrintWriter err;
    final String version;

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

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

    void run() throws Exception {
      out.println("Compile " + Bach.class.getModule() + "@" + version);

      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 + "@" + version + ".jar");

      run(
          Command.builder("javac")
              .with("--module", module)
              .with("--module-version", version)
              .with("--module-source-path", "./*/main/java")
              .with("--release", 15)
              .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("-C", classes.resolve(module), ".")
              .with("-C", Path.of(module, "main", "java"), ".")
              .build());

      var description = run(Command.of("jar", "--describe-module", "--file", file)).out();
      if (!description.startsWith(module + '@' + version))
        throw new AssertionError("Module name and version not found at the start!");

      var list = run(Command.of("jar", "--list", "--file", file), false).out();
      if (list.lines().noneMatch(line -> line.endsWith(".java")))
        throw new AssertionError("No Java source file found in JAR file: " + file);

      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("-footer", "\uD83C\uDFBC Bach " + version)
              .with("-use")
              .with("-linksource")
              .with("-notimestamp")
              .with("-Werror")
              .with("-Xdoclint")
              .with("-encoding", "UTF-8")
              .with("-d", api)
              .build(),
          false);

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

    ToolResponse run(Command command) {
      return run(command, true);
    }

    ToolResponse run(Command command, boolean verbose) {
      out.printf("<< %s%n", command);
      var response = runner.run(command);
      var normal = response.out();
      var errors = response.err();
      if (!normal.isBlank() && verbose) out.println(normal.indent(3).stripTrailing());
      if (!errors.isBlank()) err.println(errors);
      response.checkSuccessful();
      return response;
    }
  }
}

@@ -1171,16 +1171,97 @@
  %7D%0A  %7D%0A%0A
+  @Override%0A  public String toString() %7B%0A    return %22Bach's Build Program%22;%0A  %7D%0A%0A
   static
@@ -1276,16 +1276,16 @@
 imple %7B%0A
-
 %0A    fin
@@ -2074,57 +2074,8 @@
 le)%0A
-              .with(%22--module-version%22, version)%0A
     
@@ -2559,16 +2559,65 @@
 .Main%22)%0A
+              .with(%22--module-version%22, version)%0A
         
@@ -2937,16 +2937,29 @@
 onError(
+%0A            
 %22Module 
@@ -2998,17 +2998,131 @@
 e start!
-%22
+%5Cn%22%0A                + (%22Expected: %22 + module + '@' + version + '%5Cn')%0A                + (%22But got:%5Cn%22 + description)
 );%0A%0A    

Set module version while creating the modular JAR file