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

///|
/// Negotiating permessage-deflate, compressing a message, and reading it back —
/// which is the whole of what the extension does to a connection.
///
///     moon run src/examples/14-ws-compressed
#coverage.skip
fn main raise {
  // The client offers it twice, once naming the parameter it understands. The
  // server takes the first offer it can accept, which is the client's preference.
  let offer = "permessage-deflate; client_max_window_bits=9, permessage-deflate"
  let offers = @pmd.offers(offer[:])
  println("offer      -> " + offer)
  let agreed = match @pmd.Extension::agree(offers[:]) {
    Some(terms) => terms
    None => {
      println("declined   -> nothing in common")
      return
    }
  }
  println("answer     -> " + agreed.encode(role=@pmd.Role::Server))
  println(
    "windows    -> server \{agreed.server_window} bits, client \{agreed.client_window} bits",
  )

  // A server's message, compressed with the window it agreed to.
  let writer = @pmd.Writer::new(extension=agreed, role=@pmd.Role::Server)
  let payload = text(400)
  let (frame, compressed) = writer.frame(@ws.Opcode::Text, payload[:])
  let wire = frame.encode_extension(rsv1=compressed)
  println("message    -> \{payload.length()} octets")
  println(
    "frame      -> \{frame.payload.length()} octets, RSV1 \{if compressed { "set" } else { "clear" }}, \{wire.length()} on the wire",
  )

  // And the client reading it: the frame comes off the wire, the bit comes with
  // it, and the reader turns it back into the message that was sent.
  let (decoded, _, rsv1) = match @ws.decode_extension(wire[:], client=false) {
    Some(triple) => triple
    None => {
      println("incomplete -> the frame has not all arrived")
      return
    }
  }
  let reader = @pmd.Reader::new(extension=agreed, role=@pmd.Role::Client)
  let step = reader.feed(decoded, compressed=rsv1)
  match step.message {
    Some(@ws.Message::Text(back)) =>
      println("read back  -> \{back == @utf8.decode(payload[:])} the same text")
    Some(_) => println("read back  -> something else")
    None => println("read back  -> not a whole message")
  }
}

///|
/// Text that repeats, which is what a compressor is for.
fn text(n : Int32) -> Bytes {
  let buf = Buffer()
  let words : Array[Bytes] = [b"alpha ", b"bravo ", b"charlie ", b"delta "]
  let mut i = 0
  while buf.length() < n {
    buf.write_bytes(words[i % 4][:])
    i += 1
  }
  buf.to_bytes()[:n].to_owned()
}