///|
/// Server-Sent Events. An `@sse.Event` encodes to the WHATWG event-stream wire format:
/// `Event::of` is the common data-only frame, `new` sets `event` / `id` / `retry`, multi-line data
/// splits into several `data:` lines, and `ping` is a comment line that dispatches nothing.
/// `sse` builds the `text/event-stream` response around a body that sends frames for as long as
/// it likes — one chunk per frame, which is what makes it an event stream rather than a file
/// shaped like one. The app cancels the body when the client goes. A client that reconnects
/// sends the last id it saw, and `ctx.last_event_id()` lets the stream pick up after it.
///
///     moon run src/examples/17-sse --target native
#coverage.skip
async fn main {
  let events = [
    @sse.Event::of("hello"),
    @sse.Event::new(
      data="first line\nsecond line",
      kind="update",
      id="233",
      retry=3000,
    ),
    @sse.Event::ping(comment="ping"),
  ]
  let app = @moonapi.App::new()
  app.stream("/events", ctx => {
    let resumed = ctx.last_event_id() is Some(_)
    @moonapi.sse(e => {
      if resumed {
        e.send(@sse.Event::of("resumed"))
      }
      for ev in events {
        e.send(ev)
      }
    })
  })
  // The wire form: the head, one body event per frame, then the end of the body.
  let scope = @moonasgi.Scope::Http(
    @moonasgi.HttpScope::new(http_method="GET", path="/events"),
  )
  @testing.communicate(app.to_asgi(), scope, c => {
    c.send(HttpRequest(body=b"", more_body=false))
    while true {
      let event = c.receive() catch {
        @testing.Finished => break
        e => raise e
      }
      match event {
        HttpResponseStart(status~, headers~, ..) => {
          println("start \{status}")
          for h in headers {
            println("  \{h.0}: \{h.1}")
          }
        }
        HttpResponseBody(body~, more_body~) =>
          println(
            "body more_body=\{more_body} \{@utf8.decode_lossy(body[:]).escape()}",
          )
        _ => ()
      }
    }
  })
}