//! SSE streaming support for `POST /v1/shield/guard/stream`.

use crate::HighflameError;
use async_stream::stream;
use futures_util::StreamExt as _;
use std::collections::HashMap;

/// A single server-sent event from `POST /v1/shield/guard/stream`.
#[derive(Debug, Clone)]
pub struct SseEvent {
    /// Event type: `"detector_result"`, `"decision"`, `"error"`, or `"done"`.
    pub r#type: String,
    /// Parsed JSON payload.
    pub data: HashMap<String, serde_json::Value>,
}

/// Parse a raw SSE response body into a stream of [`SseEvent`]s.
///
/// Implements the SSE wire protocol (RFC 8895) manually so the SDK stays
/// dependency-free beyond `reqwest` and `async-stream`.
pub(crate) fn parse_sse_response(
    response: reqwest::Response,
) -> impl futures_util::Stream<Item = Result<SseEvent, HighflameError>> {
    stream! {
        let mut byte_stream = response.bytes_stream();
        let mut line_buf = String::new();
        let mut current_event: Option<String> = None;
        let mut current_data: Option<String> = None;

        while let Some(chunk) = byte_stream.next().await {
            let chunk = match chunk {
                Ok(c) => c,
                Err(e) => {
                    yield Err(HighflameError::ApiConnection(e.to_string()));
                    return;
                }
            };

            line_buf.push_str(&String::from_utf8_lossy(&chunk));

            loop {
                match line_buf.find('\n') {
                    None => break,
                    Some(pos) => {
                        let raw = line_buf[..pos].trim_end_matches('\r').to_string();
                        line_buf.drain(..=pos);

                        if raw.is_empty() {
                            if let Some(data) = current_data.take() {
                                let event_type = current_event
                                    .take()
                                    .unwrap_or_else(|| "detector_result".to_string());
                                match serde_json::from_str::<HashMap<String, serde_json::Value>>(
                                    &data,
                                ) {
                                    Ok(parsed) => yield Ok(SseEvent {
                                        r#type: event_type,
                                        data: parsed,
                                    }),
                                    Err(e) => {
                                        yield Err(HighflameError::Deserialisation(e));
                                        return;
                                    }
                                }
                            } else {
                                current_event = None;
                            }
                        } else if let Some(rest) = raw.strip_prefix("data:") {
                            current_data = Some(rest.trim().to_string());
                        } else if let Some(rest) = raw.strip_prefix("event:") {
                            current_event = Some(rest.trim().to_string());
                        }
                    }
                }
            }
        }

        // Flush any unterminated trailing message.
        if let Some(data) = current_data.take() {
            let event_type = current_event
                .take()
                .unwrap_or_else(|| "detector_result".to_string());
            match serde_json::from_str::<HashMap<String, serde_json::Value>>(&data) {
                Ok(parsed) => yield Ok(SseEvent { r#type: event_type, data: parsed }),
                Err(e) => yield Err(HighflameError::Deserialisation(e)),
            }
        }
    }
}
