use std::collections::BTreeMap;
use chrono::{DateTime, SecondsFormat, Utc};
use lean_ctx::core::knowledge::{FactOrigin, KnowledgeFact, fact_version_id_v1};
pub fn rfc3339(at: DateTime<Utc>) -> String {
at.to_rfc3339_opts(SecondsFormat::Secs, true)
}
pub fn is_read_noise(f: &KnowledgeFact) -> bool {
lean_ctx::core::knowledge::is_machine_derived(&f.category, &f.key)
|| (f.category.eq_ignore_ascii_case("finding")
&& lean_ctx::core::auto_findings::is_activity_record(f.value.trim()))
}
pub fn version_id(f: &KnowledgeFact) -> String {
format!("{}/{}@{}", f.category, f.key, fact_version_id_v1(f))
}
pub fn current_ids(current: &[&KnowledgeFact]) -> Vec<String> {
let mut groups: BTreeMap<(&str, &str), Vec<usize>> = BTreeMap::new();
for (i, f) in current.iter().enumerate() {
groups.entry((&f.category, &f.key)).or_default().push(i);
}
let mut ids = vec![String::new(); current.len()];
for ((category, key), mut members) in groups {
members.sort_by(|&a, &b| {
let (a, b) = (current[a], current[b]);
let rank = |f: &KnowledgeFact| u8::from(!matches!(f.origin, FactOrigin::Local));
rank(a)
.cmp(&rank(b))
.then_with(|| b.created_at.cmp(&a.created_at))
.then_with(|| fact_version_id_v1(a).cmp(&fact_version_id_v1(b)))
});
for (n, i) in members.into_iter().enumerate() {
ids[i] = if n == 0 {
format!("{category}/{key}")
} else {
version_id(current[i])
};
}
}
ids
}