//! Serialization utilities for Veza services
//! 
//! This module provides helper functions for serialization and deserialization
//! using serde, with proper error handling.

use serde::{Deserialize, Serialize};
use crate::error::{CommonError, CommonResult};

/// Serialize a value to a JSON string
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::to_json;
/// use serde::Serialize;
/// 
/// #[derive(Serialize)]
/// struct User {
///     name: String,
///     age: u32,
/// }
/// 
/// let user = User { name: "John".to_string(), age: 30 };
/// let json = to_json(&user).unwrap();
/// assert!(json.contains("John"));
/// ```
pub fn to_json<T: Serialize>(value: &T) -> CommonResult<String> {
    serde_json::to_string(value)
        .map_err(|e| CommonError::SerializationError(format!("Failed to serialize to JSON: {}", e)))
}

/// Serialize a value to a pretty-printed JSON string
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::to_json_pretty;
/// use serde::Serialize;
/// 
/// #[derive(Serialize)]
/// struct User {
///     name: String,
///     age: u32,
/// }
/// 
/// let user = User { name: "John".to_string(), age: 30 };
/// let json = to_json_pretty(&user).unwrap();
/// assert!(json.contains("John"));
/// ```
pub fn to_json_pretty<T: Serialize>(value: &T) -> CommonResult<String> {
    serde_json::to_string_pretty(value)
        .map_err(|e| CommonError::SerializationError(format!("Failed to serialize to pretty JSON: {}", e)))
}

/// Deserialize a value from a JSON string
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::from_json;
/// use serde::Deserialize;
/// 
/// #[derive(Deserialize, Debug)]
/// struct User {
///     name: String,
///     age: u32,
/// }
/// 
/// let json = r#"{"name":"John","age":30}"#;
/// let user: User = from_json(json).unwrap();
/// assert_eq!(user.name, "John");
/// ```
pub fn from_json<'a, T: Deserialize<'a>>(s: &'a str) -> CommonResult<T> {
    serde_json::from_str(s)
        .map_err(|e| CommonError::SerializationError(format!("Failed to deserialize from JSON: {}", e)))
}

/// Deserialize a value from a JSON byte slice
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::from_json_bytes;
/// use serde::Deserialize;
/// 
/// #[derive(Deserialize, Debug)]
/// struct User {
///     name: String,
///     age: u32,
/// }
/// 
/// let json_bytes = br#"{"name":"John","age":30}"#;
/// let user: User = from_json_bytes(json_bytes).unwrap();
/// assert_eq!(user.name, "John");
/// ```
pub fn from_json_bytes<T: for<'de> Deserialize<'de>>(bytes: &[u8]) -> CommonResult<T> {
    serde_json::from_slice(bytes)
        .map_err(|e| CommonError::SerializationError(format!("Failed to deserialize from JSON bytes: {}", e)))
}

/// Deserialize a value from a JSON value
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::from_json_value;
/// use serde::Deserialize;
/// use serde_json::json;
/// 
/// #[derive(Deserialize, Debug)]
/// struct User {
///     name: String,
///     age: u32,
/// }
/// 
/// let json_value = json!({"name": "John", "age": 30});
/// let user: User = from_json_value(&json_value).unwrap();
/// assert_eq!(user.name, "John");
/// ```
pub fn from_json_value<T: serde::de::DeserializeOwned>(value: &serde_json::Value) -> CommonResult<T> {
    serde_json::from_value(value.clone())
        .map_err(|e| CommonError::SerializationError(format!("Failed to deserialize from JSON value: {}", e)))
}

/// Serialize a value to a JSON value
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::to_json_value;
/// use serde::Serialize;
/// 
/// #[derive(Serialize)]
/// struct User {
///     name: String,
///     age: u32,
/// }
/// 
/// let user = User { name: "John".to_string(), age: 30 };
/// let json_value = to_json_value(&user).unwrap();
/// assert_eq!(json_value["name"], "John");
/// ```
pub fn to_json_value<T: Serialize>(value: &T) -> CommonResult<serde_json::Value> {
    serde_json::to_value(value)
        .map_err(|e| CommonError::SerializationError(format!("Failed to serialize to JSON value: {}", e)))
}

/// Clone a value by serializing and deserializing it
/// 
/// This is useful for deep cloning types that don't implement Clone.
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::clone_via_json;
/// use serde::{Serialize, Deserialize};
/// 
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct User {
///     name: String,
///     age: u32,
/// }
/// 
/// let user = User { name: "John".to_string(), age: 30 };
/// let cloned = clone_via_json(&user).unwrap();
/// assert_eq!(user, cloned);
/// ```
pub fn clone_via_json<T: Serialize + for<'de> Deserialize<'de>>(value: &T) -> CommonResult<T> {
    let json = to_json(value)?;
    from_json(&json)
}

/// Validate that a string is valid JSON
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::is_valid_json;
/// 
/// assert!(is_valid_json(r#"{"key":"value"}"#));
/// assert!(!is_valid_json("invalid json"));
/// ```
pub fn is_valid_json(s: &str) -> bool {
    serde_json::from_str::<serde_json::Value>(s).is_ok()
}

/// Pretty print a JSON string
/// 
/// # Examples
/// ```
/// use veza_common::utils::serialization::pretty_print_json;
/// 
/// let json = r#"{"name":"John","age":30}"#;
/// let pretty = pretty_print_json(json).unwrap();
/// assert!(pretty.contains('\n')); // Pretty printed should have newlines
/// ```
pub fn pretty_print_json(s: &str) -> CommonResult<String> {
    let value: serde_json::Value = from_json(s)?;
    to_json_pretty(&value)
}

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

    #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
    struct TestUser {
        id: u32,
        name: String,
        email: String,
        active: bool,
    }

    #[test]
    fn test_to_json() {
        let user = TestUser {
            id: 1,
            name: "John Doe".to_string(),
            email: "john@example.com".to_string(),
            active: true,
        };
        
        let json = to_json(&user).unwrap();
        assert!(json.contains("John Doe"));
        assert!(json.contains("john@example.com"));
        assert!(json.contains("\"id\":1"));
        assert!(json.contains("\"active\":true"));
    }

    #[test]
    fn test_to_json_pretty() {
        let user = TestUser {
            id: 1,
            name: "John Doe".to_string(),
            email: "john@example.com".to_string(),
            active: true,
        };
        
        let json = to_json_pretty(&user).unwrap();
        assert!(json.contains("John Doe"));
        assert!(json.contains('\n')); // Pretty printed should have newlines
    }

    #[test]
    fn test_from_json() {
        let json = r#"{"id":1,"name":"John Doe","email":"john@example.com","active":true}"#;
        let user: TestUser = from_json(json).unwrap();
        
        assert_eq!(user.id, 1);
        assert_eq!(user.name, "John Doe");
        assert_eq!(user.email, "john@example.com");
        assert_eq!(user.active, true);
    }

    #[test]
    fn test_from_json_invalid() {
        let json = r#"{"invalid":"json"}"#;
        let result: Result<TestUser, _> = from_json(json);
        assert!(result.is_err());
    }

    #[test]
    fn test_from_json_bytes() {
        let json_bytes = br#"{"id":1,"name":"John Doe","email":"john@example.com","active":true}"#;
        let user: TestUser = from_json_bytes(json_bytes).unwrap();
        
        assert_eq!(user.id, 1);
        assert_eq!(user.name, "John Doe");
    }

    #[test]
    fn test_from_json_value() {
        let json_value = serde_json::json!({
            "id": 1,
            "name": "John Doe",
            "email": "john@example.com",
            "active": true
        });
        
        let user: TestUser = from_json_value(&json_value).unwrap();
        assert_eq!(user.id, 1);
        assert_eq!(user.name, "John Doe");
    }

    #[test]
    fn test_to_json_value() {
        let user = TestUser {
            id: 1,
            name: "John Doe".to_string(),
            email: "john@example.com".to_string(),
            active: true,
        };
        
        let json_value = to_json_value(&user).unwrap();
        assert_eq!(json_value["id"], 1);
        assert_eq!(json_value["name"], "John Doe");
        assert_eq!(json_value["email"], "john@example.com");
        assert_eq!(json_value["active"], true);
    }

    #[test]
    fn test_clone_via_json() {
        let user = TestUser {
            id: 1,
            name: "John Doe".to_string(),
            email: "john@example.com".to_string(),
            active: true,
        };
        
        let cloned = clone_via_json(&user).unwrap();
        assert_eq!(user, cloned);
    }

    #[test]
    fn test_is_valid_json() {
        assert!(is_valid_json(r#"{"key":"value"}"#));
        assert!(is_valid_json(r#"{"number":123}"#));
        assert!(is_valid_json(r#"{"array":[1,2,3]}"#));
        assert!(is_valid_json("null"));
        assert!(is_valid_json("true"));
        assert!(is_valid_json("123"));
        assert!(!is_valid_json("invalid json"));
        assert!(!is_valid_json("{invalid}"));
        assert!(!is_valid_json(""));
    }

    #[test]
    fn test_pretty_print_json() {
        let json = r#"{"id":1,"name":"John Doe","email":"john@example.com","active":true}"#;
        let pretty = pretty_print_json(json).unwrap();
        
        assert!(pretty.contains("John Doe"));
        assert!(pretty.contains('\n')); // Should be formatted with newlines
        assert!(pretty.contains("  ")); // Should have indentation
    }

    #[test]
    fn test_pretty_print_invalid_json() {
        let json = "invalid json";
        let result = pretty_print_json(json);
        assert!(result.is_err());
    }

    #[test]
    fn test_round_trip_serialization() {
        let user = TestUser {
            id: 42,
            name: "Jane Smith".to_string(),
            email: "jane@example.com".to_string(),
            active: false,
        };
        
        // Serialize
        let json = to_json(&user).unwrap();
        
        // Deserialize
        let deserialized: TestUser = from_json(&json).unwrap();
        
        assert_eq!(user, deserialized);
    }

    #[test]
    fn test_nested_structure() {
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct Address {
            street: String,
            city: String,
        }
        
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct Person {
            name: String,
            address: Address,
        }
        
        let person = Person {
            name: "John".to_string(),
            address: Address {
                street: "123 Main St".to_string(),
                city: "New York".to_string(),
            },
        };
        
        let json = to_json(&person).unwrap();
        let deserialized: Person = from_json(&json).unwrap();
        
        assert_eq!(person, deserialized);
    }
}

