//! Props parsing utilities.
//!
//! These helpers are intentionally transport-agnostic.
//! Integrations can feed raw bytes plus a `Content-Type` string.
//!

use serde_json::Value;
use std::collections::HashMap;

#[derive(thiserror::Error, Debug)]
/// Errors returned when decoding request bodies into component props.
///
/// Used by integrations to return helpful `415`/`400` style errors.
pub enum PropsParseError {
    #[error("unsupported content-type: {0}")]
    UnsupportedContentType(String),

    #[error("invalid json: {0}")]
    InvalidJson(String),

    #[error("invalid form body: {0}")]
    InvalidForm(String),
}

/// Parse raw request bytes into a JSON value suitable for `loomx_core::render`.
///
/// Supported content types:
/// - `application/json`
/// - `application/x-www-form-urlencoded`
///
/// If `content_type` is empty, the function treats the body as form-urlencoded.
pub fn parse_props(content_type: &str, body: &[u8]) -> Result<Value, PropsParseError> {
    let ct = content_type.to_ascii_lowercase();

    if ct.starts_with("application/json") {
        serde_json::from_slice::<Value>(body).map_err(|e| PropsParseError::InvalidJson(e.to_string()))
    } else if ct.starts_with("application/x-www-form-urlencoded") || ct.is_empty() {
        let map: HashMap<String, String> =
            serde_urlencoded::from_bytes(body).map_err(|e| PropsParseError::InvalidForm(e.to_string()))?;
        Ok(serde_json::json!(map))
    } else {
        Err(PropsParseError::UnsupportedContentType(content_type.to_string()))
    }
}
