///|
fn demo_source() -> String {
  "var total = 0\n" +
  "for (current in 1..10) {\n" +
  "  total = total + current\n" +
  "}\n" +
  "System.print(total)\n"
}

///|
fn file_candidate(path : String) -> String {
  let value : @path.Path = path
  if value.extname().length() == 0 {
    path + ".wren"
  } else {
    path
  }
}

///|
fn canonical_path(path : String) -> String {
  let value : @path.Path = file_candidate(path)
  value.resolve().to_string()
}

///|
fn read_source(path : String) -> String? {
  let source = @fs.read_file_to_string(path) catch { _ => return None }
  Some(source)
}

///|
fn resolve_import_path(importer : String, specifier : String) -> String {
  let requested : @path.Path = file_candidate(specifier)
  let combined = if requested.is_absolute() {
    requested
  } else {
    let parent : @path.Path = importer
    parent.dirname().join(requested)
  }
  combined.resolve().to_string()
}

///|
fn file_loader(
  importer : String,
  specifier : String,
) -> @moonwren.ModuleLoadResult {
  let resolved = resolve_import_path(importer, specifier)
  match read_source(resolved) {
    Some(source) => @moonwren.ModuleLoaded(resolved, source)
    None =>
      @moonwren.ModuleLoadFailed(
        "cannot load module '\{specifier}' resolved as '\{resolved}'",
      )
  }
}

///|
fn print_result(
  result : @moonwren.ProgramRunResult,
  fallback_source : String,
) -> Int32 {
  match result {
    ProgramCompleted(_, output) => {
      for line in output {
        println(line)
      }
      0
    }
    ProgramFailed(diagnostics, output) => {
      for line in output {
        println(line)
      }
      for diagnostic in diagnostics {
        println(diagnostic.render(fallback_source))
      }
      if diagnostics.length() == 0 {
        70
      } else {
        match diagnostics[0].phase {
          Scan | Parse | Resolve => 65
          Runtime => 70
        }
      }
    }
  }
}

///|
fn main {
  let arguments = @env.args()
  if arguments.length() <= 1 {
    @sys.exit(print_result(@moonwren.run(demo_source()), ""))
  } else if arguments[1] == "--eval" {
    if arguments.length() <= 2 {
      println("usage: moonwren --eval ")
      @sys.exit(64)
    } else {
      @sys.exit(print_result(@moonwren.run(arguments[2]), ""))
    }
  } else {
    let entry = canonical_path(arguments[1])
    match read_source(entry) {
      None => {
        println("cannot read source file: \{entry}")
        @sys.exit(66)
      }
      Some(source) =>
        @sys.exit(
          print_result(
            @moonwren.run_with_loader(entry, source, 20000000, file_loader),
            entry,
          ),
        )
    }
  }
}