// Regression baselines for every configuration.
//
// The golden corpus (test/fixtures/golden) is the *correctness* oracle, but it
// only covers five chains. This tool records what the other fourteen produce on a
// fixed mixed-script sample, so an unintended behaviour change shows up as a diff
// instead of going unnoticed. See test/fixtures/regression/README.md.
//
//     moon run tools/gen_baseline --target native
//     moon run tools/gen_baseline --target native -- --verify

///|
/// Read a text file, exiting with a message when it cannot be read.
fn read_text(path : String) -> String {
  @fs.read_file_to_string(path) catch {
    _ => {
      println("gen_baseline: cannot read " + path)
      @sys.exit(1)
      ""
    }
  }
}

///|
/// Write a text file, exiting with a message when it cannot be written.
fn write_text(path : String, content : String) -> Unit {
  @fs.write_string_to_file(path, content) catch {
    _ => {
      println("gen_baseline: cannot write " + path)
      @sys.exit(1)
    }
  }
}

///|
/// Write or check one baseline; returns 1 when verify mode found drift.
fn sync(path : String, content : String, verify : Bool) -> Int {
  if verify {
    if !@fs.path_exists(path) {
      println("gen_baseline: missing " + path)
      return 1
    }
    if read_text(path) == content {
      0
    } else {
      println("gen_baseline: stale " + path)
      1
    }
  } else {
    write_text(path, content)
    0
  }
}

///|
/// Entry point.
fn main {
  let args = @env.args()
  let mut corpus = "test/fixtures/regression/input.txt"
  let mut out_dir = "test/fixtures/regression"
  let mut verify = false
  let mut index = 0
  while index < args.length() && !args[index].has_prefix("--") {
    index = index + 1
  }
  while index < args.length() {
    let arg = args[index]
    if arg == "--input" && index + 1 < args.length() {
      corpus = args[index + 1]
      index = index + 2
    } else if arg == "--out" && index + 1 < args.length() {
      out_dir = args[index + 1]
      index = index + 2
    } else if arg == "--verify" {
      verify = true
      index = index + 1
    } else {
      println("gen_baseline: ignoring argument " + arg)
      index = index + 1
    }
  }

  let source = read_text(corpus)
  let names = @config.chain_names()
  let mut problems = 0
  let mut written = 0
  for name in names {
    match @config.chain(name) {
      None => {
        println("gen_baseline: no chain for " + name)
        problems = problems + 1
      }
      Some(chain) => {
        // A trailing newline on the baseline keeps the files diff-friendly and
        // makes the comparison explicit rather than relying on file browsers.
        let output = chain.apply(source)
        let text = if output.has_suffix("\n") { output } else { output + "\n" }
        problems = problems + sync(out_dir + "/" + name + ".txt", text, verify)
        written = written + 1
      }
    }
  }
  if problems > 0 {
    println("gen_baseline: " + problems.to_string() + " problem(s)")
    @sys.exit(1)
  }
  println(
    "gen_baseline: " +
    written.to_string() +
    " baseline(s) " +
    (if verify { "verified" } else { "written" }),
  )
}