use std::path::Path;
use serde_json::{Map, Value};
use crate::data;
use crate::output::{emit, CliError, Ctx};
pub fn all_people(data: &Value) -> Vec<(String, Map<String, Value>)> {
let mut out: Vec<(String, Map<String, Value>)> = Vec::new();
if let Some(depts) = data.get("departments").and_then(|v| v.as_object()) {
for (dept_name, dept) in depts {
if let Some(members) = dept.get("members").and_then(|v| v.as_array()) {
for m in members {
if let Some(obj) = m.as_object() {
out.push((dept_name.clone(), obj.clone()));
}
}
}
}
}
if let Some(root) = data.get("root_users").and_then(|v| v.as_array()) {
for m in root {
if let Some(obj) = m.as_object() {
out.push(("Root".to_string(), obj.clone()));
}
}
}
out
}
pub fn find_person<'a>(
people: &'a [(String, Map<String, Value>)],
needle: &str,
) -> Option<&'a (String, Map<String, Value>)> {
let n = needle.to_lowercase();
for entry in people {
let m = &entry.1;
if m.get("name").and_then(|v| v.as_str()) == Some(needle) {
return Some(entry);
}
if let Some(gh) = m.get("github").and_then(|v| v.as_str()) {
if gh.to_lowercase() == n {
return Some(entry);
}
}
if let Some(arr) = m.get("git_aliases").and_then(|v| v.as_array()) {
for a in arr {
if let Some(s) = a.as_str() {
if s.to_lowercase() == n {
return Some(entry);
}
}
}
}
}
None
}
fn with_department(person: &Map<String, Value>, dept: &str) -> Value {
let mut out = person.clone();
out.insert("department".to_string(), Value::String(dept.to_string()));
Value::Object(out)
}
pub fn list(dir: &Path, ctx: Ctx, dept_filter: Option<&str>) -> Result<(), CliError> {
let data = data::load(dir, "people")?;
let people = all_people(&data);
let items: Vec<Value> = people
.iter()
.filter(|(d, _)| dept_filter.map_or(true, |want| d == want))
.map(|(d, p)| with_department(p, d))
.collect();
emit(ctx, &Value::Array(items));
Ok(())
}
pub fn get(dir: &Path, ctx: Ctx, name: &str) -> Result<(), CliError> {
let data = data::load(dir, "people")?;
let people = all_people(&data);
match find_person(&people, name) {
Some((dept, person)) => {
emit(ctx, &with_department(person, dept));
Ok(())
}
None => Err(CliError::not_found(
format!("person not found: {name}"),
Some("try `liber people list` or check git_aliases / github username".into()),
)),
}
}