///|
let runs : Int = 100

///|
let seed : Bytes = b"moonmask-monkey-typewriter-00042"

///|
fn is_valid(text : Bytes, validator : @moonschema.Schema) -> Bool {
  try {
    let value = @json.parse(@utf8.decode(text))
    validator.valid(value)
  } catch {
    _ => false
  } noraise {
    ok => ok
  }
}

///|
fn preview(text : Bytes) -> String {
  let buf = StringBuilder()
  let mut n = 0
  for c in @utf8.decode_lossy(text) {
    if n == 100 {
      buf.write_string("...")
      break
    }
    buf.write_char(c)
    n += 1
  }
  buf.to_string()
}

///|
fn run(args : Array[String]) -> Unit raise {
  let whitespace = args[1] == "--whitespace"
  let offset = if whitespace { 2 } else { 1 }
  if args.length() < offset + 2 {
    fail("expected tokenizer and at least one schema")
  }
  let tok = @tokenizer.from_file(args[offset])
  let vocab = @vocab.from_tokenizer(tok, eos_token="<|endoftext|>")
  println("vocab size: \{vocab.size()}, runs per schema: \{runs}")
  println("JSON whitespace: \{whitespace}; uniform random sampling, no model")
  let samples : Array[String] = []
  let mut timed = false
  let rows : Array[String] = []
  for path in args[offset + 1:] {
    let schema = @json.parse(@fs.read_file_to_string(path))
    let dfa = @schema.compile(schema, whitespace~)
    let guide = @mask.Guide::new(dfa, vocab)
    if !timed {
      let started = @bench.monotonic_clock_start()
      let mask = guide.transitions(guide.start())
      let elapsed_us = @bench.monotonic_clock_end(started)
      println(
        "prefix-tree token mask, one DFA state, vocab \{vocab.size()}, allowed \{mask.length()}: \{elapsed_us} us (\{path})",
      )
      timed = true
    }
    let validator = @moonschema.Schema::new(schema)
    let rand = @random.Rand::chacha8(seed~)
    let mut masked_ok = 0
    let mut unmasked_ok = 0
    let mut total_tokens = 0
    for k in 0.. ...",
    )
    panic()
  }
  run(args) catch {
    e => {
      println("moonmask: \{e}")
      panic()
    }
  }
}