//! Minimal SSE frame parser for integration tests.
//!
//! Parses `event: ...\nid: ...\ndata: ...\n\n` frames from a
//! `Bytes` body produced by axum's `Sse` responder. Returns
//! `Vec<SseFrame>` so tests can assert on event sequence + data
//! payloads.

use bytes::Bytes;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SseFrame {
    pub event: Option<String>,
    pub id: Option<String>,
    pub data: String,
}

/// Parse all SSE frames in `body`. Tolerant of trailing
/// whitespace; rejects frames without a `data:` line silently.
pub fn parse_sse_frames(body: &Bytes) -> Vec<SseFrame> {
    let text = std::str::from_utf8(body).unwrap_or("");
    let mut frames = Vec::new();
    for chunk in text.split("\n\n") {
        let chunk = chunk.trim_end_matches('\n');
        if chunk.is_empty() {
            continue;
        }
        let mut event = None;
        let mut id = None;
        let mut data_lines = Vec::new();
        for line in chunk.lines() {
            if let Some(rest) = line.strip_prefix("event:") {
                event = Some(rest.trim().to_string());
            } else if let Some(rest) = line.strip_prefix("id:") {
                id = Some(rest.trim().to_string());
            } else if let Some(rest) = line.strip_prefix("data:") {
                data_lines.push(rest.trim().to_string());
            }
        }
        if !data_lines.is_empty() {
            frames.push(SseFrame {
                event,
                id,
                data: data_lines.join("\n"),
            });
        }
    }
    frames
}

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

    #[test]
    fn parses_single_event_with_event_id_data() {
        let body = Bytes::from("event: task-update\nid: 1\ndata: {\"x\":1}\n\n".to_string());
        let frames = parse_sse_frames(&body);
        assert_eq!(frames.len(), 1);
        assert_eq!(frames[0].event.as_deref(), Some("task-update"));
        assert_eq!(frames[0].id.as_deref(), Some("1"));
        assert_eq!(frames[0].data, "{\"x\":1}");
    }

    #[test]
    fn parses_multiple_frames_in_order() {
        let body =
            Bytes::from("event: a\nid: 1\ndata: one\n\nevent: b\nid: 2\ndata: two\n\n".to_string());
        let frames = parse_sse_frames(&body);
        assert_eq!(frames.len(), 2);
        assert_eq!(frames[0].data, "one");
        assert_eq!(frames[1].data, "two");
    }

    #[test]
    fn empty_body_returns_no_frames() {
        let frames = parse_sse_frames(&Bytes::new());
        assert!(frames.is_empty());
    }
}
