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

///|
/// A URI template filled in three ways, and a URI read back into the names it
/// was built from.
fn main raise {
  let values : Map[String, @template.Value] = Map([])
  values.set("who", @template.Value::Text("moon bit"))
  values.set("path", @template.Value::Text("/a/b"))
  values.set("list", @template.Value::List(["red", "green", "blue"]))
  values.set("keys", @template.Value::Pairs([("lang", "en"), ("page", "2")]))

  for
    text in [
      "https://example.test/{path}", "{+path}/here", "{/list*}{?who}", "{?keys*}",
      "{;who,keys}",
    ] {
    let template = @template.Template::decode(text[:])
    println(text)
    println("  expanded  " + template.expand(values))
    println("")
  }

  // A template that describes a URI is also the thing that reads one.
  let template = @template.Template::decode("/users/{id}/posts{?page,size}")
  let uri = "/users/42/posts?page=2&size=10"
  println(uri)
  for binding in template.capture(uri[:]).unwrap() {
    println("  \{binding.0} = \{binding.1}")
  }
  println("")

  // Not every string is a template, and the ones that are not say where.
  for text in ["{a", "{a b}", "{a:10000}", "{=a}"] {
    let outcome = @template.Template::decode(text[:]).encode() catch {
      @template.Refused::Bracket(at~) => "not closed, at \{at}"
      @template.Refused::Syntax(at~, got~) =>
        "'\{got}' may not stand there, at \{at}"
      @template.Refused::Operator(at~, got~) => "'\{got}' is reserved, at \{at}"
      @template.Refused::Length(at~, limit~, got~) =>
        "\{got} is past \{limit}, at \{at}"
      @template.Refused::Composite(name~) =>
        "a prefix does not apply to the list or map \{name}"
    }
    println("\{text}  ->  \{outcome}")
  }
}