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

///|
/// A URI reference, taken apart and put back; a relative one resolved against
/// a base; and the same text escaped for four different components.
fn main raise {
  let url = @moonurl.Url::decode(
    "https://leo:pw@example.test:12000/v1/a%20b?q=1#top",
  )
  println("scheme    " + show(url.scheme))
  println("userinfo  " + show(url.userinfo))
  println("host      " + show(url.host))
  println("port      " + show(url.port.map(fn(p) { p.to_string() })))
  println("path      " + url.path)
  println("query     " + show(url.query))
  println("fragment  " + show(url.fragment))
  println("back      " + url.encode())
  println("")

  // RFC 3986 §5.4, a few of the examples the section prints.
  let base = @moonurl.Url::decode("http://a/b/c/d;p?q")
  for reference in ["g", "./g", "/g", "//g", "?y", "#s", "..", "../../g", "g:h"] {
    let target = base.resolve(@moonurl.Url::decode(reference[:])).encode()
    println("against http://a/b/c/d;p?q  \{reference}  ->  \{target}")
  }
  println("")

  // Which octets may stand for themselves is the component's question.
  let text = "a b&c/d"
  for
    one in [
      ("Bare", @moonurl.escape_text(text)),
      ("Path", @moonurl.escape_text(text, kind=Path)),
      ("Query", @moonurl.escape_text(text, kind=Query)),
      ("Whole", @moonurl.escape_text(text, kind=Whole)),
    ] {
    println("\{one.0}  \{one.1}")
  }
  println("")

  // RFC 3986 §6.2.2, the three things normalising does.
  let messy = @moonurl.Url::decode("HTTP://EXAMPLE.test/a/./b/../c/%7euser")
  println("messy     " + messy.encode())
  println("normal    " + messy.normalize().encode())
  println("")

  // A query as pairs: `+` is a space only here, and a repeated name is a list.
  let query = @moonurl.Query::decode(b"q=two+words&tag=a&tag=b"[:])
  println("q         " + show(query.get("q")))
  println("tags      " + query.values("tag").join(", "))
  query.set("page", "2")
  println("written   " + query.encode())
}

///|
fn show(value : String?) -> String {
  match value {
    Some(value) => "\"" + value + "\""
    None => "(absent)"
  }
}