// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! # Bincode Serialization and Deserialization
//!
//! This module provides functionality for serializing and deserializing events to and from
//! Bincode format. Bincode is a compact binary serialization format that is extremely fast
//! and efficient, making it ideal for storage and network transmission in Rust applications.
//!
//! The implementation uses the `bincode` crate, which provides zero-copy serialization
//! and deserialization for Rust data structures.
//!
//! ## Format Description
//!
//! Bincode is a Rust-specific binary serialization format that:
//!
//! - Produces very compact binary representations
//! - Has extremely fast serialization and deserialization
//! - Preserves exact type information
//! - Uses little-endian byte order by default
//! - Supports zero-copy deserialization where possible
//!
//! ## Advantages of Bincode
//!
//! - **Performance**: One of the fastest serialization formats available for Rust
//! - **Size Efficiency**: Very compact binary representation
//! - **Type Safety**: Leverages Rust's type system for safe serialization
//! - **Zero Dependencies**: Minimal overhead in the serialization process
//! - **Cross-Platform**: Consistent binary format across different architectures
//!
//! ## Usage
//!
//! ### Serializing to Bincode
//!
//! ```ignore
//! use psmatcher::event_types::{AttributeValue, DefaultEvent};
//! use psmatcher::traits::BincodeSerializable;
//! use std::fs::File;
//! use std::io::BufWriter;
//!
//! // Create an event
//! let event = DefaultEvent::new("user.login".to_string())
//!     .with_attribute("user_id".to_string(), AttributeValue::String("12345".into()))
//!     .with_attribute("timestamp".to_string(), AttributeValue::Integer(1678901234));
//!
//! // Serialize to Bincode bytes
//! let bincode_bytes = event.to_bincode().unwrap();
//!
//! // Write directly to a file
//! let file = File::create("event.bincode").unwrap();
//! let writer = BufWriter::new(file);
//! event.write_bincode(writer).unwrap();
//! ```
//!
//! ### Deserializing from Bincode
//!
//! ```ignore
//! use psmatcher::event_types::DefaultEvent;
//! use psmatcher::traits::{BincodeDeserializable, BincodeSerializable};
//! use std::fs::File;
//! use std::io::BufReader;
//!
//! let bincode_bytes = DefaultEvent::new("test.event".to_string()).to_bincode().unwrap();
//!
//! // Deserialize from Bincode bytes
//! let event = DefaultEvent::from_bincode(&bincode_bytes).unwrap();
//!
//! // Read directly from a file
//! let file = File::open("event.bincode").unwrap();
//! let reader = BufReader::new(file);
//! let event = DefaultEvent::read_bincode(reader).unwrap();
//! ```
//!
//! ## Error Handling
//!
//! The module provides a dedicated `BincodeError` type that wraps various error types that can occur
//! during Bincode operations. This allows for more precise error handling and better error messages.
//!
//! ## Storage Considerations
//!
//! Bincode is an excellent choice for storing events due to its exceptional performance and
//! compact size. For applications with high throughput or limited storage, Bincode provides
//! significant advantages over text-based formats.
//!
//! Typical compression ratios compared to JSON:
//! - Small events: ~5-7x smaller
//! - Medium events: ~6-8x smaller
//! - Large events with many attributes: ~8-10x smaller
//!
//! Performance characteristics:
//! - Serialization: ~10-50x faster than JSON
//! - Deserialization: ~5-20x faster than JSON

use std::{
    hash::Hash,
    io::{Read, Write},
};

use serde::{de::DeserializeOwned, Serialize};

use crate::{
    event::{serialization::error::BincodeError, AttributeMap, AttributeValue, DefaultEvent},
    traits::Event,
};

/// Trait for Bincode serialization
///
/// This trait defines methods for converting an object to Bincode bytes or writing
/// it directly to a writer.
pub trait BincodeSerializable {
    /// Converts to Bincode bytes
    ///
    /// Serializes the object to Bincode format as a byte vector.
    ///
    /// # Returns
    ///
    /// * `Result<Vec<u8>, BincodeError>` - Bincode bytes or an error
    fn to_bincode(&self) -> Result<Vec<u8>, BincodeError>;

    /// Writes Bincode directly to a writer
    ///
    /// Serializes the object to Bincode format and writes it to the provided writer.
    /// This is more efficient for file I/O as it avoids an intermediate byte vector.
    ///
    /// # Arguments
    ///
    /// * `writer` - Any type that implements the `Write` trait
    ///
    /// # Returns
    ///
    /// * `Result<(), BincodeError>` - Success or an error
    fn write_bincode<W: Write>(&self, writer: W) -> Result<(), BincodeError>;
}

/// Trait for Bincode deserialization
///
/// This trait defines methods for converting Bincode bytes to an object or reading
/// it directly from a reader.
pub trait BincodeDeserializable {
    /// Deserializes from Bincode bytes
    ///
    /// Parses Bincode bytes and converts them to an object of the implementing type.
    ///
    /// # Arguments
    ///
    /// * `bincode_bytes` - Bincode-encoded bytes
    ///
    /// # Returns
    ///
    /// * `Result<Self, BincodeError>` - Deserialized object or an error
    fn from_bincode(bincode_bytes: &[u8]) -> Result<Self, BincodeError>
    where
        Self: Sized;

    /// Reads Bincode directly from a reader
    ///
    /// Reads Bincode data from the provided reader and converts it to an object.
    /// This is more efficient for file I/O as it avoids loading the entire file into memory.
    ///
    /// # Arguments
    ///
    /// * `reader` - Any type that implements the `Read` trait
    ///
    /// # Returns
    ///
    /// * `Result<Self, BincodeError>` - Deserialized object or an error
    fn read_bincode<R: Read>(reader: R) -> Result<Self, BincodeError>
    where
        Self: Sized;
}

impl BincodeSerializable for DefaultEvent {
    fn to_bincode(&self) -> Result<Vec<u8>, BincodeError> {
        bincode::serialize(self.attributes()).map_err(BincodeError::SerializationError)
    }

    fn write_bincode<W: Write>(&self, mut writer: W) -> Result<(), BincodeError> {
        let bytes = self.to_bincode()?;
        writer.write_all(&bytes).map_err(BincodeError::IoError)?;
        Ok(())
    }
}

impl BincodeDeserializable for DefaultEvent {
    fn from_bincode(bincode_bytes: &[u8]) -> Result<Self, BincodeError> {
        let attribute_map: AttributeMap<String, AttributeValue> =
            bincode::deserialize(bincode_bytes).map_err(BincodeError::DeserializationError)?;
        DefaultEvent::from_attributes(attribute_map).map_err(BincodeError::from)
    }

    fn read_bincode<R: Read>(mut reader: R) -> Result<Self, BincodeError> {
        let mut buffer = Vec::new();
        reader
            .read_to_end(&mut buffer)
            .map_err(BincodeError::IoError)?;
        Self::from_bincode(&buffer)
    }
}

impl<K: Serialize, V: Serialize> BincodeSerializable for AttributeMap<K, V> {
    fn to_bincode(&self) -> Result<Vec<u8>, BincodeError> {
        bincode::serialize(self).map_err(BincodeError::SerializationError)
    }

    fn write_bincode<W: Write>(&self, mut writer: W) -> Result<(), BincodeError> {
        let bytes = self.to_bincode()?;
        writer.write_all(&bytes).map_err(BincodeError::IoError)?;
        Ok(())
    }
}

impl<K: Hash + Eq + DeserializeOwned, V: DeserializeOwned> BincodeDeserializable
    for AttributeMap<K, V>
{
    fn from_bincode(bincode_bytes: &[u8]) -> Result<Self, BincodeError> {
        bincode::deserialize(bincode_bytes).map_err(BincodeError::DeserializationError)
    }

    fn read_bincode<R: Read>(mut reader: R) -> Result<Self, BincodeError> {
        let mut buffer = Vec::new();
        reader
            .read_to_end(&mut buffer)
            .map_err(BincodeError::IoError)?;
        Self::from_bincode(&buffer)
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use crate::event::{
        helpers::*,
        serialization::bincode::{BincodeDeserializable, BincodeSerializable},
        AttributeMap, AttributeValue, DefaultEvent, Event,
    };

    #[test]
    fn test_basic_bincode_serialization() {
        // Create a simple event
        let event = DefaultEvent::new("test.event".to_string())
            .with_attribute("key".to_string(), string_attr("value"));

        // Serialize to Bincode bytes
        let bincode_bytes = event.to_bincode().unwrap();

        // Ensure we got some bytes
        assert!(!bincode_bytes.is_empty());
    }

    #[test]
    fn test_all_attribute_types_bincode_serialization() {
        // Create an event with all attribute types
        let event = create_test_event_all_types();

        // Serialize to Bincode bytes
        let bincode_bytes = event.to_bincode().unwrap();

        // Ensure we got some bytes
        assert!(!bincode_bytes.is_empty());
    }

    #[test]
    fn test_bincode_deserialization() {
        // Create an event
        let original_event = create_test_event_all_types();

        // Serialize to Bincode bytes
        let bincode_bytes = original_event.to_bincode().unwrap();

        // Deserialize from Bincode bytes
        let deserialized_event = DefaultEvent::from_bincode(&bincode_bytes).unwrap();

        // Verify events are equal
        assert_eq!(original_event.topic(), deserialized_event.topic());

        // Check events are the same
        assert_eq!(original_event, deserialized_event);
    }

    #[test]
    fn test_write_read_bincode() {
        // Create an event
        let original_event = create_test_event_all_types();

        // Write to memory buffer
        let mut buffer = Vec::new();
        original_event.write_bincode(&mut buffer).unwrap();

        // Read from memory buffer
        let deserialized_event = DefaultEvent::read_bincode(Cursor::new(&buffer)).unwrap();

        // Verify events are equal
        assert_eq!(original_event.topic(), deserialized_event.topic());

        // Check events are the same
        assert_eq!(original_event, deserialized_event);
    }

    #[test]
    fn test_invalid_bincode_deserialization() {
        // Invalid Bincode bytes (just some random bytes)
        let invalid_bincode = vec![0xFF, 0xFE, 0xFD, 0xFC];

        // Attempt to deserialize
        let result = DefaultEvent::from_bincode(&invalid_bincode);

        // Should fail
        assert!(result.is_err());
    }

    #[test]
    fn test_nested_structures_bincode() {
        // Create an event with deeply nested structures
        let event = create_deeply_nested_event();

        // Serialize to Bincode
        let bincode_bytes = event.to_bincode().unwrap();

        // Deserialize
        let deserialized_event = DefaultEvent::from_bincode(&bincode_bytes).unwrap();

        // Verify nested structures
        match deserialized_event.get_attribute("nested") {
            Some(AttributeValue::Map(map)) => match map.get("level1") {
                Some(AttributeValue::Map(level1)) => match level1.get("level2") {
                    Some(AttributeValue::Map(level2)) => match level2.get("level3") {
                        Some(AttributeValue::String(s)) => assert_eq!(s, "deeply nested value"),
                        _ => panic!("nested.level1.level2.level3 wrong type or missing"),
                    },
                    _ => panic!("nested.level1.level2 wrong type or missing"),
                },
                _ => panic!("nested.level1 wrong type or missing"),
            },
            _ => panic!("nested attribute wrong type or missing"),
        }

        // Verify nested lists
        match deserialized_event.get_attribute("nested_lists") {
            Some(AttributeValue::List(outer_list)) => {
                // Outer list should have 2 elements
                assert_eq!(outer_list.len(), 2);

                // First element should be a list with 2 integers
                match &outer_list[0] {
                    AttributeValue::List(inner_list) => {
                        assert_eq!(inner_list.len(), 2);
                        match &inner_list[0] {
                            AttributeValue::Integer(i) => assert_eq!(*i, 1),
                            _ => panic!("nested_lists[0][0] wrong type"),
                        }
                        match &inner_list[1] {
                            AttributeValue::Integer(i) => assert_eq!(*i, 2),
                            _ => panic!("nested_lists[0][1] wrong type"),
                        }
                    }
                    _ => panic!("nested_lists[0] wrong type"),
                }

                // Second element should be a list with 1 map
                match &outer_list[1] {
                    AttributeValue::List(inner_list) => {
                        assert_eq!(inner_list.len(), 1);
                        match &inner_list[0] {
                            AttributeValue::Map(map) => match map.get("key") {
                                Some(AttributeValue::String(s)) => assert_eq!(s, "value"),
                                _ => panic!("nested_lists[1][0].key wrong type or missing"),
                            },
                            _ => panic!("nested_lists[1][0] wrong type"),
                        }
                    }
                    _ => panic!("nested_lists[1] wrong type"),
                }
            }
            _ => panic!("nested_lists attribute wrong type or missing"),
        }
    }

    #[test]
    fn test_large_event_bincode() {
        // Create a larger event
        let mut large_event = DefaultEvent::new("large.event".to_string());

        // Add 100 integer attributes
        for i in 0..100 {
            large_event = large_event.with_attribute(format!("int_{i}"), int_attr(i as i64));
        }

        // Add 50 string attributes with longer content
        for i in 0..50 {
            large_event = large_event.with_attribute(
                format!("string_{i}"),
                string_attr(&format!(
                    "This is a longer string value for testing Bincode serialization efficiency {i}"
                )),
            );
        }

        // Serialize to Bincode
        let bincode_bytes = large_event.to_bincode().unwrap();

        // Deserialize back
        let deserialized_event = DefaultEvent::from_bincode(&bincode_bytes).unwrap();

        // Verify count of attributes
        assert_eq!(
            large_event.attributes().len(),
            deserialized_event.attributes().len()
        );

        // Check we have the expected number of attributes (1 topic + 100 int + 50 string)
        assert_eq!(deserialized_event.attributes().len(), 151);
    }

    #[test]
    fn test_bincode_size_efficiency() {
        // Create a test event
        let event = create_test_event_all_types();

        // Serialize to Bincode
        let bincode_bytes = event.to_bincode().unwrap();

        // Bincode should produce a reasonably compact representation
        // This is mainly to ensure we're actually using Bincode format
        // The representation should be 270 bytes or less for our test event if we were to change the
        // serialization format.
        assert!(bincode_bytes.len() <= 270);

        // Verify we can deserialize it back
        let deserialized = DefaultEvent::from_bincode(&bincode_bytes).unwrap();
        assert_eq!(event, deserialized);
    }

    // Helper function to create a test event with all attribute types
    fn create_test_event_all_types() -> DefaultEvent {
        // Create a map attribute
        let mut map = AttributeMap::new();
        map.insert("nested".to_string(), string_attr("value"));

        DefaultEvent::new("test.event".to_string())
            .with_attribute("string_attr".to_string(), string_attr("text"))
            .with_attribute("int_attr".to_string(), int_attr(42))
            .with_attribute("float_attr".to_string(), float_attr(std::f64::consts::PI))
            .with_attribute("bool_attr".to_string(), bool_attr(true))
            .with_attribute(
                "list_attr".to_string(),
                list_attr(vec![int_attr(1), int_attr(2)]),
            )
            .with_attribute("map_attr".to_string(), map_attr(map))
    }

    // Helper function to create an event with deeply nested structures
    fn create_deeply_nested_event() -> DefaultEvent {
        // Create nested map structure
        let mut level3 = AttributeMap::new();
        level3.insert("level3".to_string(), string_attr("deeply nested value"));

        let mut level2 = AttributeMap::new();
        level2.insert("level2".to_string(), map_attr(level3));

        let mut level1 = AttributeMap::new();
        level1.insert("level1".to_string(), map_attr(level2));

        // Create nested list structure
        let mut inner_map = AttributeMap::new();
        inner_map.insert("key".to_string(), string_attr("value"));

        DefaultEvent::new("nested.test".to_string())
            .with_attribute("nested".to_string(), map_attr(level1))
            .with_attribute(
                "nested_lists".to_string(),
                list_attr(vec![
                    list_attr(vec![int_attr(1), int_attr(2)]),
                    list_attr(vec![map_attr(inner_map)]),
                ]),
            )
    }
}
