///|
/// Fluent builder for a multimodal message, so callers can assemble mixed
/// text/image content without manually constructing the `Content` enum.
///
/// Example:
/// ```
/// let msg = MessageBuilder::user()
///   .text("What is in these images?")
///   .image_url("https://a/1.png")
///   .image_url("https://a/2.png")
///   .build()
/// ```
pub struct MessageBuilder {
  role : Role
  parts : Array[ContentPart]
  mut name : String?
}

///|
/// Start building a message with the given role.
pub fn MessageBuilder::new(role : Role) -> MessageBuilder {
  { role, parts: [], name: None }
}

///|
/// Start building a `user` message.
pub fn MessageBuilder::user() -> MessageBuilder {
  MessageBuilder::new(User)
}

///|
/// Start building an `assistant` message.
pub fn MessageBuilder::assistant() -> MessageBuilder {
  MessageBuilder::new(Assistant)
}

///|
/// Start building a `system` message.
pub fn MessageBuilder::system() -> MessageBuilder {
  MessageBuilder::new(System)
}

///|
/// Append a text part.
pub fn MessageBuilder::text(
  self : MessageBuilder,
  s : String,
) -> MessageBuilder {
  self.parts.push(Text(s))
  self
}

///|
/// Append an image-URL part.
pub fn MessageBuilder::image_url(
  self : MessageBuilder,
  url : String,
) -> MessageBuilder {
  self.parts.push(ImageUrl(url))
  self
}

///|
/// Append a base64 image part.
pub fn MessageBuilder::image_base64(
  self : MessageBuilder,
  mime : String,
  data : String,
) -> MessageBuilder {
  self.parts.push(ImageUrl("data:" + mime + ";base64," + data))
  self
}

///|
/// Set the optional author name.
pub fn MessageBuilder::name(
  self : MessageBuilder,
  n : String,
) -> MessageBuilder {
  self.name = Some(n)
  self
}

///|
/// Finalize into a `Message`.
///
/// If the builder holds exactly one text part and no name, it collapses to a
/// plain string content (the common case); otherwise it emits a parts array.
pub fn MessageBuilder::build(self : MessageBuilder) -> Message {
  let content = if self.parts.length() == 1 && self.parts[0] is Text(t) {
    Str(t)
  } else {
    Parts(self.parts)
  }
  {
    role: self.role,
    content,
    tool_calls: None,
    tool_call_id: None,
    name: self.name,
  }
}

///|
/// The number of content parts accumulated so far.
pub fn MessageBuilder::part_count(self : MessageBuilder) -> Int {
  self.parts.length()
}

///|
/// Whether the message contains any image part.
pub fn Message::has_image(self : Message) -> Bool {
  match self.content {
    Str(_) => false
    Parts(parts) => {
      for p in parts {
        if p is ImageUrl(_) {
          return true
        }
      }
      false
    }
  }
}

///|
/// Count the image parts in a message.
pub fn Message::image_count(self : Message) -> Int {
  match self.content {
    Str(_) => 0
    Parts(parts) => {
      let mut n = 0
      for p in parts {
        if p is ImageUrl(_) {
          n = n + 1
        }
      }
      n
    }
  }
}