//! Pure agent selection and filtering logic — no I/O, no side effects.
//!
//! All functions in this module are pure: they take data, transform it, and
//! return a result without touching the filesystem, network, or any mutable
//! global state. This makes them fast to test without tempdirs or async runtimes.
use crate::agent_log::LogEntry;

/// Concatenate the text of all `output` events from an agent log.
///
/// Non-output events (status, done, error, agent_json, thinking) are silently
/// skipped. Returns an empty string when `entries` is empty or contains no
/// output events.
pub fn collect_output_text(entries: &[LogEntry]) -> String {
    entries
        .iter()
        .filter(|e| e.event.get("type").and_then(|t| t.as_str()) == Some("output"))
        .filter_map(|e| {
            e.event
                .get("text")
                .and_then(|t| t.as_str())
                .map(str::to_owned)
        })
        .collect()
}

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

    fn make_log_entry(event_type: &str, text: Option<&str>) -> LogEntry {
        let mut obj = serde_json::Map::new();
        obj.insert(
            "type".to_string(),
            serde_json::Value::String(event_type.to_string()),
        );
        if let Some(t) = text {
            obj.insert("text".to_string(), serde_json::Value::String(t.to_string()));
        }
        LogEntry {
            timestamp: "2024-01-01T00:00:00Z".to_string(),
            event: serde_json::Value::Object(obj),
        }
    }

    // ── collect_output_text ───────────────────────────────────────────────────

    #[test]
    fn collect_output_text_empty_entries() {
        let result = collect_output_text(&[]);
        assert_eq!(result, "");
    }

    #[test]
    fn collect_output_text_skips_non_output_events() {
        let entries = vec![
            make_log_entry("status", Some("running")),
            make_log_entry("done", None),
        ];
        let result = collect_output_text(&entries);
        assert_eq!(result, "");
    }

    #[test]
    fn collect_output_text_concatenates_output_events() {
        let entries = vec![
            make_log_entry("output", Some("Hello ")),
            make_log_entry("output", Some("world\n")),
        ];
        let result = collect_output_text(&entries);
        assert_eq!(result, "Hello world\n");
    }

    #[test]
    fn collect_output_text_skips_output_without_text_field() {
        let entry = LogEntry {
            timestamp: "2024-01-01T00:00:00Z".to_string(),
            event: serde_json::json!({"type": "output"}),
        };
        let result = collect_output_text(&[entry]);
        assert_eq!(result, "");
    }

    #[test]
    fn collect_output_text_mixed_event_types() {
        let entries = vec![
            make_log_entry("status", Some("running")),
            make_log_entry("output", Some("line1\n")),
            make_log_entry("agent_json", None),
            make_log_entry("output", Some("line2\n")),
            make_log_entry("done", None),
        ];
        let result = collect_output_text(&entries);
        assert_eq!(result, "line1\nline2\n");
    }
}
