liber-cli 0.1.0

AI-agent-readable company directory CLI
//! `liber customers …` verbs.

use std::path::Path;

use serde_json::{Map, Value};

use crate::data;
use crate::output::{emit, CliError, Ctx};

pub fn list(dir: &Path, ctx: Ctx) -> Result<(), CliError> {
    let data = data::load(dir, "customers")?;
    let arr = data
        .get("customers")
        .cloned()
        .unwrap_or(Value::Array(vec![]));
    emit(ctx, &arr);
    Ok(())
}

pub fn get(dir: &Path, ctx: Ctx, slug: &str) -> Result<(), CliError> {
    let data = data::load(dir, "customers")?;
    let customers = data
        .get("customers")
        .and_then(|v| v.as_array())
        .cloned()
        .unwrap_or_default();
    for c in customers {
        if c.get("slug").and_then(|v| v.as_str()) == Some(slug) {
            let enriched = enrich(dir, &c)?;
            emit(ctx, &enriched);
            return Ok(());
        }
    }
    Err(CliError::not_found(
        format!("customer not found: {slug}"),
        Some("try `liber customers list`".into()),
    ))
}

fn enrich(dir: &Path, customer: &Value) -> Result<Value, CliError> {
    let mut out: Map<String, Value> = customer
        .as_object()
        .cloned()
        .unwrap_or_default();

    if let Some(related) = customer.get("related_products").and_then(|v| v.as_array()) {
        if !related.is_empty() {
            let products = data::load(dir, "products")?;
            let arr = products
                .get("products")
                .and_then(|v| v.as_array())
                .cloned()
                .unwrap_or_default();
            let wanted: Vec<&str> = related.iter().filter_map(|v| v.as_str()).collect();
            let detail: Vec<Value> = arr
                .into_iter()
                .filter(|p| {
                    p.get("slug")
                        .and_then(|v| v.as_str())
                        .map(|s| wanted.contains(&s))
                        .unwrap_or(false)
                })
                .collect();
            out.insert("products_detail".to_string(), Value::Array(detail));
        }
    }

    if let Some(chats) = customer.get("chats").and_then(|v| v.as_array()) {
        if !chats.is_empty() {
            let chat_data = data::load(dir, "chats")?;
            let map = chat_data
                .get("group_chats")
                .and_then(|v| v.as_object())
                .cloned()
                .unwrap_or_default();
            let mut chat_ids = Map::new();
            for c in chats {
                if let Some(name) = c.as_str() {
                    let val = map.get(name).cloned().unwrap_or(Value::Null);
                    // Normalize {id, platform} object to bare id string for convenience.
                    let id_val = match &val {
                        Value::Object(o) => o.get("id").cloned().unwrap_or(Value::Null),
                        _ => val,
                    };
                    chat_ids.insert(name.to_string(), id_val);
                }
            }
            out.insert("chat_ids".to_string(), Value::Object(chat_ids));
        }
    }

    Ok(Value::Object(out))
}