// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

///|
/// The whole surface in one run, so a reader can see what this is for before
/// reading any of it.
///
///     moon run examples/tour
#coverage.skip
fn show(a : Array[String?]) -> String {
  let buf = StringBuilder::StringBuilder()
  buf.write_char('[')
  let mut i = 0
  for x in a {
    if i > 0 {
      buf.write_string(", ")
    }
    match x {
      None => buf.write_string("None")
      Some(s) => buf.write_string(s)
    }
    i += 1
  }
  buf.write_char(']')
  buf.to_string()
}

///|
/// The whole surface in one run, so a reader can see what this is for before
/// reading any of it.
///
///     moon run examples/tour
#coverage.skip
fn main raise {
  // A plain search and a forced match-at-start.
  println(@moonregex.search("\\d+", "order 42").unwrap().group(0).unwrap())
  println(
    "prefix at the start: " +
    (@moonregex.prefix("\\d+", "order 42") is None).to_string(),
  )

  // findall collects one capture per match; a pattern with two of them has to
  // say which, because Python answers a tuple there.
  println(
    "findall: " +
    show(
      @moonregex.findall("(\\w+)=(\\d+)", "a=1 b=2", group=@moonregex.Num(n=1)),
    ),
  )
  // finditer hands over the matches themselves, groups and all.
  let walk = StringBuilder::StringBuilder()
  for m in @moonregex.finditer("(\\w+)=(\\d+)", "a=1 b=2") {
    walk.write_string(
      " " + m.group(1).unwrap_or("?") + ":" + m.group(2).unwrap_or("?"),
    )
  }
  println("finditer:" + walk.to_string())

  // split keeps the captured separators.
  println("split: " + show(@moonregex.split("(\\s+)", "a  b\tc")))

  // sub with a callable replacement.
  let numbered = @moonregex.sub_with(
    "(\\w+)",
    fn(m) -> String raise @moonregex.Refused {
      match m.group(0) {
        Some(s) => s.to_upper()
        None => ""
      }
    },
    "hello world",
  )
  println("sub_with: " + numbered)

  // case-insensitive and multiline flags.
  let rx = @moonregex.compile(
    "^line",
    flags=@moonregex.Flags::new(ignorecase=true, multiline=true),
  )
  println(
    "anchored, case-insensitive: " +
    (rx.search("LINE\nline") is Some(_)).to_string(),
  )

  // a named group.
  match @moonregex.search("(?P\\w+)", "see spot") {
    None => ()
    Some(m) => println("named group: " + m.group("word").unwrap())
  }

  // a named Unicode character and a line break.
  println(
    "named char: " +
    (@moonregex.full("\\N{EM DASH}", "\u{2014}") is Some(_)).to_string(),
  )
  println(
    "line break: " + (@moonregex.full("\\R", "\u{2028}") is Some(_)).to_string(),
  )

  // a control verb: (*COMMIT) aborts the whole match.
  println(
    "commit: " + (@moonregex.search("a(*COMMIT)b", "ab") is None).to_string(),
  )

  // branch reset: (?|(a)|(b)) captures to group 1 either way.
  println(
    "branch reset: " +
    (@moonregex.full("(?|(a)|(b))", "b") is Some(_)).to_string(),
  )

  // (?(DEFINE)…) declares a subroutine, then recursion calls it.
  let grammar = @moonregex.compile("(?(DEFINE)(?P\\d+))(?P>num)")
  println("define+recursion: " + (grammar.full("12345") is Some(_)).to_string())
}