package test.preview;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.lang.System.Logger.Level;
import java.lang.module.ModuleDescriptor.Version;
import org.junit.jupiter.api.Test;

public class RecordBasedApiTests {

  @Test
  void check() {
    var bach = Bach.of().with(Level.DEBUG);

    var project = Project.of()
        .with(new MainSources(bach.defaultRelease()))
        .with(Version.parse("17.01"))
        .with(new MainSources(8));

    assertEquals("17.01", project.version().toString());
    assertEquals(8, project.main().release());

    bach.build(project);

    class CustomWorkflow extends Workflow {
      CustomWorkflow(Bach bach, Project project) {
        super(bach, project);
      }

      @Override
      public String computeJavac(MainSources main) {
        return super.computeJavac(main).toUpperCase();
      }
    }

    bach.with(CustomWorkflow::new).build(project);
  }

  record Bach(Level threshold, Workflow.Constructor workflowConstructor) {

    public static Bach of() {
      return new Bach(Level.INFO, Workflow::new);
    }

    Bach with(Level threshold) {
      return new Bach(threshold, workflowConstructor);
    }

    Bach with(Workflow.Constructor workflowConstructor) {
      return new Bach(threshold, workflowConstructor);
    }

    void build(Project project) {
      workflowConstructor.newWorkflow(this, project).build();
    }

    boolean log(Level level) {
      return threshold == Level.ALL || level.getSeverity() >= threshold.getSeverity();
    }

    int defaultRelease() {
      return Runtime.version().feature();
    }
  }

  record Project(Version version, MainSources main) {

    public static Project of() {
      return new Project(Version.parse("1-ea"), new MainSources(Runtime.version().feature()));
    }

    public Project with(Version version) {
      return new Project(version, main);
    }

    public Project with(MainSources main) {
      return new Project(version, main);
    }
  }

  record MainSources(int release) {}

  static class Workflow {

    @FunctionalInterface
    interface Constructor {
      Workflow newWorkflow(Bach bach, Project project);
    }

    private final Bach bach;
    private final Project project;

    Workflow(Bach bach, Project project) {
      this.bach = bach;
      this.project = project;
    }

    void build() {
      if (bach.log(Level.DEBUG)) System.out.println("\n" + getClass());
      System.out.println(computeJavac(project.main()));
    }

    public String computeJavac(MainSources main) {
      return "javac --module-version " + project.version() + " --release " + main.release();
    }
  }
}

@@ -645,97 +645,8 @@
 ow %7B
-%0A      CustomWorkflow(Bach bach, Project project) %7B%0A        super(bach, project);%0A      %7D
 %0A%0A  
@@ -686,38 +686,41 @@
  compute
+Main
 Javac(
-MainSources main
+Project project
 ) %7B%0A    
@@ -747,18 +747,25 @@
 pute
+Main
 Javac(
-main
+project
 ).to
@@ -806,16 +806,20 @@
 ch.with(
+new 
 CustomWo
@@ -824,21 +824,18 @@
 Workflow
-::new
+()
 ).build(
@@ -892,40 +892,17 @@
 flow
-.Constructor workflowConstructor
+ workflow
 ) %7B%0A
@@ -965,16 +965,20 @@
 el.INFO,
+ new
  Workflo
@@ -982,13 +982,10 @@
 flow
-::new
+()
 );%0A 
@@ -1060,35 +1060,24 @@
 ld, workflow
-Constructor
 );%0A    %7D%0A%0A  
@@ -1100,40 +1100,17 @@
 flow
-.Constructor workflowConstructor
+ workflow
 ) %7B%0A
@@ -1150,27 +1150,16 @@
 workflow
-Constructor
 );%0A    %7D
@@ -1212,31 +1212,14 @@
 flow
-Constructor.newWorkflow
+.build
 (thi
@@ -1233,16 +1233,8 @@
 ect)
-.build()
 ;%0A  
@@ -1893,304 +1893,45 @@
     
-@FunctionalInterface%0A    interface Constructor %7B%0A      Workflow newWorkflow(Bach bach, Project project);%0A    %7D%0A%0A    private final Bach bach;%0A    private final Project project;%0A%0A    Workflow(Bach bach, Project project) %7B%0A      this.bach = bach;%0A      this.project = project;%0A    %7D%0A%0A    void build(
+void build(Bach bach, Project project
 ) %7B%0A
@@ -2030,24 +2030,28 @@
 ntln(compute
+Main
 Javac(projec
@@ -2051,23 +2051,16 @@
 (project
-.main()
 ));%0A    
@@ -2091,30 +2091,33 @@
 pute
+Main
 Javac(
-MainSources main
+Project project
 ) %7B%0A
@@ -2193,20 +2193,30 @@
 ase %22 + 
+project.
 main
+()
 .release

Use plain objects as components