use std::collections::HashMap;
pub use crate::config::ChannelMappingEntry;
#[derive(Debug, Clone)]
pub struct ChannelMap {
mappings: Vec<ChannelMappingEntry>,
index: HashMap<(String, String), usize>,
}
impl ChannelMap {
pub fn new(entries: Vec<ChannelMappingEntry>) -> Self {
let mut index = HashMap::new();
for (i, entry) in entries.iter().enumerate() {
index.insert((entry.platform.to_lowercase(), entry.channel.clone()), i);
}
Self {
mappings: entries,
index,
}
}
pub fn resolve(&self, platform: &str, channel: &str) -> Option<&ChannelMappingEntry> {
self.index
.get(&(platform.to_lowercase(), channel.to_string()))
.and_then(|&idx| self.mappings.get(idx))
}
pub fn for_platform(&self, platform: &str) -> Vec<&ChannelMappingEntry> {
let p = platform.to_lowercase();
self.mappings
.iter()
.filter(|e| e.platform.to_lowercase() == p)
.collect()
}
pub fn all(&self) -> &[ChannelMappingEntry] {
&self.mappings
}
pub fn find_by_name(&self, name: &str) -> Option<&ChannelMappingEntry> {
let lower = name.to_lowercase();
self.mappings.iter().find(|e| {
e.name.to_lowercase() == lower
|| e.project
.as_ref()
.is_some_and(|p| p.to_lowercase().ends_with(&lower))
})
}
pub fn is_empty(&self) -> bool {
self.mappings.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_entries() -> Vec<ChannelMappingEntry> {
vec![
ChannelMappingEntry {
platform: "discord".to_string(),
channel: "999888".to_string(),
project: Some("/home/user/my-app".to_string()),
name: "my-app".to_string(),
agent: Some("architect".to_string()),
},
ChannelMappingEntry {
platform: "telegram".to_string(),
channel: "-100123".to_string(),
project: Some("/home/user/backend".to_string()),
name: "backend".to_string(),
agent: None,
},
]
}
#[test]
fn resolve_existing() {
let map = ChannelMap::new(sample_entries());
let entry = map.resolve("discord", "999888").unwrap();
assert_eq!(entry.project, Some("/home/user/my-app".to_string()));
assert_eq!(entry.agent, Some("architect".to_string()));
}
#[test]
fn resolve_missing() {
let map = ChannelMap::new(sample_entries());
assert!(map.resolve("slack", "C01").is_none());
}
#[test]
fn filter_by_platform() {
let map = ChannelMap::new(sample_entries());
let tg = map.for_platform("telegram");
assert_eq!(tg.len(), 1);
assert_eq!(tg[0].name, "backend");
assert_eq!(tg[0].agent, None);
}
}