csusage-core 0.0.1

Coding agent CLI usage reports (ccusage fork with Claude Science support)
use serde_json::{Value, json};

use crate::{UsageSummary, cli::AgentReportKind};

pub fn agent_summary_json(
    row: &UsageSummary,
    kind: AgentReportKind,
    include_session_metadata: bool,
) -> Value {
    let mut value = json!({
        period_key(kind): summary_period(row),
        "inputTokens": row.input_tokens,
        "outputTokens": row.output_tokens,
        "cacheCreationTokens": row.cache_creation_tokens,
        "cacheReadTokens": row.cache_read_tokens,
        "totalTokens": row.total_tokens(),
        "totalCost": row.total_cost,
        "modelsUsed": row.models_used,
        "modelBreakdowns": row.model_breakdowns,
    });
    if let (Some(obj), Some(credits)) = (value.as_object_mut(), row.credits) {
        obj.insert("credits".to_string(), json!(credits));
    }
    if let (Some(obj), Some(message_count)) = (value.as_object_mut(), row.message_count) {
        obj.insert("messageCount".to_string(), json!(message_count));
    }
    if include_session_metadata && let Some(obj) = value.as_object_mut() {
        obj.insert(
            "lastActivity".to_string(),
            row.last_activity
                .as_ref()
                .map_or(Value::Null, |value| json!(value)),
        );
        obj.insert(
            "firstActivity".to_string(),
            row.first_activity
                .as_ref()
                .map_or(Value::Null, |value| json!(value)),
        );
        obj.insert(
            "projectPath".to_string(),
            row.project_path
                .as_ref()
                .map_or(Value::Null, |value| json!(value)),
        );
    }
    value
}

pub fn first_column(kind: AgentReportKind) -> &'static str {
    match kind {
        AgentReportKind::Daily => "Date",
        AgentReportKind::Weekly => "Week",
        AgentReportKind::Monthly => "Month",
        AgentReportKind::Session => "Session",
    }
}

pub fn summary_period(row: &UsageSummary) -> &str {
    row.date
        .as_deref()
        .or(row.week.as_deref())
        .or(row.month.as_deref())
        .or(row.session_id.as_deref())
        .unwrap_or_default()
}

fn period_key(kind: AgentReportKind) -> &'static str {
    match kind {
        AgentReportKind::Daily => "date",
        AgentReportKind::Weekly => "week",
        AgentReportKind::Monthly => "month",
        AgentReportKind::Session => "sessionId",
    }
}