use serde_yaml::{Mapping, Value};

pub fn strip_reserved(mapping: &mut Mapping) {
    let keys_to_remove: Vec<Value> = mapping
        .iter()
        .filter_map(|(k, _)| match k.as_str() {
            Some(s) if is_reserved_segment(s) => Some(k.clone()),
            _ => None,
        })
        .collect();
    for k in keys_to_remove {
        mapping.remove(&k);
    }
}

pub fn is_reserved_segment(s: &str) -> bool {
    matches!(s.chars().next(), Some('_' | '$' | '.' | '#' | '@'))
}

#[cfg(test)]
mod tests {
    use super::*;

    fn map(yaml: &str) -> Mapping {
        match serde_yaml::from_str::<Value>(yaml).unwrap() {
            Value::Mapping(m) => m,
            Value::Null => Mapping::new(),
            _ => panic!(),
        }
    }

    #[test]
    fn strip_removes_reserved_prefixes() {
        let mut m = map("_internal: 1\n$weird: 2\n.dot: 3\n\"#hash\": 4\n\"@user\": 5\nname: ok\n");
        strip_reserved(&mut m);
        assert!(!m.contains_key(Value::String("_internal".into())));
        assert!(!m.contains_key(Value::String("$weird".into())));
        assert!(!m.contains_key(Value::String(".dot".into())));
        assert!(!m.contains_key(Value::String("#hash".into())));
        assert!(!m.contains_key(Value::String("@user".into())));
        assert!(m.contains_key(Value::String("name".into())));
    }

    #[test]
    fn strip_keeps_unreserved_prefixes() {
        let mut m =
            map("foo: 1\nfoo_bar: 2\nfoo123: 3\n\"2024\": 4\n\"-hyphen\": 5\n\"with/slash\": 6\n");
        strip_reserved(&mut m);
        assert!(m.contains_key(Value::String("foo".into())));
        assert!(m.contains_key(Value::String("foo_bar".into())));
        assert!(m.contains_key(Value::String("foo123".into())));
        assert!(m.contains_key(Value::String("2024".into())));
        assert!(m.contains_key(Value::String("-hyphen".into())));
        assert!(m.contains_key(Value::String("with/slash".into())));
    }

    #[test]
    fn reserved_segment_classification() {
        assert!(is_reserved_segment("_x"));
        assert!(is_reserved_segment("$x"));
        assert!(is_reserved_segment(".x"));
        assert!(is_reserved_segment("#x"));
        assert!(is_reserved_segment("@x"));
        assert!(!is_reserved_segment("foo"));
        assert!(!is_reserved_segment("2024"));
        assert!(!is_reserved_segment("-foo"));
        assert!(!is_reserved_segment("/foo"));
        assert!(!is_reserved_segment(""));
    }
}
