use waproto::whatsapp::message::{
ContactMessage, LiveLocationMessage, LocationMessage, ReactionMessage,
};
pub(crate) fn describe_location(loc: &LocationMessage) -> String {
let lat = loc.degrees_latitude.unwrap_or_default();
let lng = loc.degrees_longitude.unwrap_or_default();
let mut out = format!("[location] {lat:.6}, {lng:.6}");
if let Some(name) = loc.name.as_deref().filter(|n| !n.trim().is_empty()) {
out.push_str(&format!(" ({})", name.trim()));
}
if let Some(addr) = loc.address.as_deref().filter(|a| !a.trim().is_empty()) {
out.push_str(&format!(" - {}", addr.trim()));
}
out
}
pub(crate) fn describe_live_location(loc: &LiveLocationMessage) -> String {
let lat = loc.degrees_latitude.unwrap_or_default();
let lng = loc.degrees_longitude.unwrap_or_default();
let mut out = format!("[live location] {lat:.6}, {lng:.6}");
if let Some(caption) = loc.caption.as_deref().filter(|c| !c.trim().is_empty()) {
out.push_str(&format!(" - {}", caption.trim()));
}
out
}
pub(crate) fn phone_from_vcard(vcard: &str) -> Option<String> {
vcard
.lines()
.map(str::trim)
.find(|line| line.to_ascii_uppercase().starts_with("TEL"))
.and_then(|line| line.rsplit(':').next())
.map(str::trim)
.filter(|phone| !phone.is_empty())
.map(str::to_string)
}
pub(crate) fn describe_contact(contact: &ContactMessage) -> String {
let name = contact
.display_name
.as_deref()
.map(str::trim)
.filter(|n| !n.is_empty())
.unwrap_or("unnamed");
match contact.vcard.as_deref().and_then(phone_from_vcard) {
Some(phone) => format!("[contact] {name} - {phone}"),
None => format!("[contact] {name}"),
}
}
pub(crate) fn describe_reaction(reaction: &ReactionMessage) -> Option<String> {
let emoji = reaction.text.as_deref().map(str::trim).unwrap_or("");
if emoji.is_empty() {
return None;
}
let target = reaction
.key
.as_option()
.and_then(|k| k.id.as_deref())
.unwrap_or("unknown message");
Some(format!("[reaction] {emoji} on message {target}"))
}