//! JSON body parser

use crate::core::CoreError;
use bytes::Bytes;
use serde::de::DeserializeOwned;

/// Maximum body size for JSON parsing (2MB)
const MAX_SIZE: usize = 2 * 1024 * 1024;

/// JSON parser
///
/// Parses JSON request bodies with a 2MB size limit.
/// Use `parse_as<T>()` to deserialize into a specific type.
#[derive(Debug, Clone, Default)]
pub struct JsonParser;

impl JsonParser {
    /// Parse JSON bytes into a specific type
    ///
    /// Returns `CoreError::PayloadTooLarge` (413) if the body exceeds 2MB.
    /// Returns `CoreError::BodyParseError` (400) if the JSON is invalid.
    pub async fn parse_as<T: DeserializeOwned>(body: &Bytes) -> Result<T, CoreError> {
        if body.len() > MAX_SIZE {
            return Err(CoreError::payload_too_large(format!(
                "Request body too large: {} bytes (max: {} bytes)",
                body.len(),
                MAX_SIZE
            )));
        }

        serde_json::from_slice(body).map_err(|e| {
            CoreError::body_parse_error(format!("Invalid JSON: {}", Self::format_error(&e)))
        })
    }

    fn format_error(e: &serde_json::Error) -> String {
        if e.is_eof() {
            "Unexpected end of JSON input".to_string()
        } else if e.is_syntax() {
            format!("Syntax error at line {}", e.line())
        } else if e.is_data() {
            "Invalid data type or structure".to_string()
        } else {
            e.to_string()
        }
    }
}

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

    #[derive(Debug, Deserialize, PartialEq)]
    struct User {
        name: String,
        age: u32,
    }

    #[tokio::test]
    async fn test_parse_valid_json() {
        let body = Bytes::from(r#"{"name":"Alice","age":30}"#);
        let user: User = JsonParser::parse_as(&body).await.unwrap();
        assert_eq!(user.name, "Alice");
        assert_eq!(user.age, 30);
    }

    #[tokio::test]
    async fn test_parse_invalid_json() {
        let body = Bytes::from("not valid json");
        let result: Result<User, _> = JsonParser::parse_as(&body).await;
        assert!(matches!(result.unwrap_err(), CoreError::BodyParseError(_)));
    }

    #[tokio::test]
    async fn test_parse_incomplete_json() {
        let body = Bytes::from(r#"{"name":"Alice""#);
        let result: Result<User, _> = JsonParser::parse_as(&body).await;
        assert!(result.is_err());
    }

    #[tokio::test]
    async fn test_parse_wrong_type() {
        let body = Bytes::from(r#"{"name":"Alice","age":"not a number"}"#);
        let result: Result<User, _> = JsonParser::parse_as(&body).await;
        assert!(result.is_err());
    }

    #[tokio::test]
    async fn test_size_limit_exceeded() {
        // Build a body just over MAX_SIZE
        let big = Bytes::from(vec![b'x'; MAX_SIZE + 1]);
        let result: Result<serde_json::Value, _> = JsonParser::parse_as(&big).await;
        assert!(matches!(result.unwrap_err(), CoreError::PayloadTooLarge(_)));
    }

    #[tokio::test]
    async fn test_empty_json_object() {
        let body = Bytes::from("{}");
        let result: serde_json::Value = JsonParser::parse_as(&body).await.unwrap();
        assert!(result.is_object());
    }

    #[tokio::test]
    async fn test_json_array() {
        let body = Bytes::from(r#"[1,2,3]"#);
        let result: serde_json::Value = JsonParser::parse_as(&body).await.unwrap();
        assert_eq!(result.as_array().unwrap().len(), 3);
    }

    #[tokio::test]
    async fn test_nested_json() {
        let body = Bytes::from(r#"{"user":{"name":"Alice","age":30}}"#);
        let result: serde_json::Value = JsonParser::parse_as(&body).await.unwrap();
        assert_eq!(result["user"]["name"], "Alice");
    }

    #[test]
    fn test_parser_is_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}
        assert_send_sync::<JsonParser>();
    }
}
