use crate::error::Result;
use crate::protocol::*;
use crate::debug;
use serde::{Deserialize, Serialize};
use bytes::{Bytes, BytesMut, BufMut};
use std::time::Instant;

pub use crate::protocol::{SerializedComponent, SerializedEntity};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorldSnapshot {
    pub entities: Vec<SerializedEntity>,
    pub timestamp: f64,
    pub version: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Delta {
    pub changes: Vec<DeltaChange>,
    pub timestamp: f64,
    pub base_timestamp: f64,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryFormat {
    Json,
    MessagePack,
    Bincode,
}

pub struct BinarySerializer {
    format: BinaryFormat,
}

impl BinarySerializer {
    pub fn new(format: BinaryFormat) -> Self {
        Self { format }
    }

    pub fn json() -> Self {
        Self::new(BinaryFormat::Json)
    }

    pub fn messagepack() -> Self {
        Self::new(BinaryFormat::MessagePack)
    }

    pub fn bincode() -> Self {
        Self::new(BinaryFormat::Bincode)
    }

    pub fn serialize_message(&self, message: &Message) -> Result<Bytes> {
        let start = Instant::now();

        let result = match self.format {
            BinaryFormat::Json => {
                let json = serde_json::to_vec(message)?;
                Ok(Bytes::from(json))
            }
            BinaryFormat::MessagePack => {
                let msgpack = rmp_serde::to_vec(message)?;
                Ok(Bytes::from(msgpack))
            }
            BinaryFormat::Bincode => {
                let bincode_data = bincode::serialize(message)?;
                Ok(Bytes::from(bincode_data))
            }
        };

        if let Ok(ref bytes) = result {
            if debug::is_debug_enabled() {
                debug::log_message("Serialized", message);
            }

            if debug::is_trace_enabled() {
                let format_name = match self.format {
                    BinaryFormat::Json => "JSON",
                    BinaryFormat::MessagePack => "MessagePack",
                    BinaryFormat::Bincode => "Bincode",
                };
                debug::trace_serialization(format_name, bytes.len(), start.elapsed().as_micros());
            }
        }

        result
    }

    pub fn deserialize_message(&self, data: &[u8]) -> Result<Message> {
        let start = Instant::now();

        let result = match self.format {
            BinaryFormat::Json => {
                let message = serde_json::from_slice(data)?;
                Ok(message)
            }
            BinaryFormat::MessagePack => {
                let message = rmp_serde::from_slice(data)?;
                Ok(message)
            }
            BinaryFormat::Bincode => {
                let message = bincode::deserialize(data)?;
                Ok(message)
            }
        };

        if let Ok(ref message) = result {
            if debug::is_debug_enabled() {
                debug::log_message("Deserialized", message);
            }

            if debug::is_trace_enabled() {
                let format_name = match self.format {
                    BinaryFormat::Json => "JSON",
                    BinaryFormat::MessagePack => "MessagePack",
                    BinaryFormat::Bincode => "Bincode",
                };
                debug::trace_deserialization(format_name, data.len(), start.elapsed().as_micros());
            }
        }

        result
    }

    pub fn serialize_snapshot(&self, snapshot: &WorldSnapshot) -> Result<Bytes> {
        match self.format {
            BinaryFormat::Json => {
                let json = serde_json::to_vec(snapshot)?;
                Ok(Bytes::from(json))
            }
            BinaryFormat::MessagePack => {
                let msgpack = rmp_serde::to_vec(snapshot)?;
                Ok(Bytes::from(msgpack))
            }
            BinaryFormat::Bincode => {
                let bincode_data = bincode::serialize(snapshot)?;
                Ok(Bytes::from(bincode_data))
            }
        }
    }

    pub fn deserialize_snapshot(&self, data: &[u8]) -> Result<WorldSnapshot> {
        match self.format {
            BinaryFormat::Json => {
                let snapshot = serde_json::from_slice(data)?;
                Ok(snapshot)
            }
            BinaryFormat::MessagePack => {
                let snapshot = rmp_serde::from_slice(data)?;
                Ok(snapshot)
            }
            BinaryFormat::Bincode => {
                let snapshot = bincode::deserialize(data)?;
                Ok(snapshot)
            }
        }
    }

    pub fn serialize_delta(&self, delta: &Delta) -> Result<Bytes> {
        match self.format {
            BinaryFormat::Json => {
                let json = serde_json::to_vec(delta)?;
                Ok(Bytes::from(json))
            }
            BinaryFormat::MessagePack => {
                let msgpack = rmp_serde::to_vec(delta)?;
                Ok(Bytes::from(msgpack))
            }
            BinaryFormat::Bincode => {
                let bincode_data = bincode::serialize(delta)?;
                Ok(Bytes::from(bincode_data))
            }
        }
    }

    pub fn deserialize_delta(&self, data: &[u8]) -> Result<Delta> {
        match self.format {
            BinaryFormat::Json => {
                let delta = serde_json::from_slice(data)?;
                Ok(delta)
            }
            BinaryFormat::MessagePack => {
                let delta = rmp_serde::from_slice(data)?;
                Ok(delta)
            }
            BinaryFormat::Bincode => {
                let delta = bincode::deserialize(data)?;
                Ok(delta)
            }
        }
    }

    pub fn serialize_component(&self, component: &SerializedComponent) -> Result<Bytes> {
        match self.format {
            BinaryFormat::Json => {
                let json = serde_json::to_vec(component)?;
                Ok(Bytes::from(json))
            }
            BinaryFormat::MessagePack => {
                let msgpack = rmp_serde::to_vec(component)?;
                Ok(Bytes::from(msgpack))
            }
            BinaryFormat::Bincode => {
                let bincode_data = bincode::serialize(component)?;
                Ok(Bytes::from(bincode_data))
            }
        }
    }

    pub fn deserialize_component(&self, data: &[u8]) -> Result<SerializedComponent> {
        match self.format {
            BinaryFormat::Json => {
                let component = serde_json::from_slice(data)?;
                Ok(component)
            }
            BinaryFormat::MessagePack => {
                let component = rmp_serde::from_slice(data)?;
                Ok(component)
            }
            BinaryFormat::Bincode => {
                let component = bincode::deserialize(data)?;
                Ok(component)
            }
        }
    }

    pub fn get_format(&self) -> BinaryFormat {
        self.format
    }
}

pub struct StreamingSerializer {
    format: BinaryFormat,
    buffer: BytesMut,
}

impl StreamingSerializer {
    pub fn new(format: BinaryFormat) -> Self {
        Self {
            format,
            buffer: BytesMut::with_capacity(8192),
        }
    }

    pub fn write_message(&mut self, message: &Message) -> Result<()> {
        let serializer = BinarySerializer::new(self.format);
        let data = serializer.serialize_message(message)?;

        let len = data.len() as u32;
        self.buffer.put_u32_le(len);
        self.buffer.put(data);

        Ok(())
    }

    pub fn flush(&mut self) -> Bytes {
        self.buffer.split().freeze()
    }

    pub fn clear(&mut self) {
        self.buffer.clear();
    }
}

pub struct StreamingDeserializer {
    format: BinaryFormat,
    buffer: BytesMut,
}

impl StreamingDeserializer {
    pub fn new(format: BinaryFormat) -> Self {
        Self {
            format,
            buffer: BytesMut::with_capacity(8192),
        }
    }

    pub fn feed(&mut self, data: &[u8]) {
        self.buffer.extend_from_slice(data);
    }

    pub fn try_read_message(&mut self) -> Result<Option<Message>> {
        if self.buffer.len() < 4 {
            return Ok(None);
        }

        let len = u32::from_le_bytes([
            self.buffer[0],
            self.buffer[1],
            self.buffer[2],
            self.buffer[3],
        ]) as usize;

        if self.buffer.len() < 4 + len {
            return Ok(None);
        }

        self.buffer.advance(4);

        let message_data = self.buffer.split_to(len);

        let serializer = BinarySerializer::new(self.format);
        let message = serializer.deserialize_message(&message_data)?;

        Ok(Some(message))
    }

    pub fn clear(&mut self) {
        self.buffer.clear();
    }
}

trait Advance {
    fn advance(&mut self, cnt: usize);
}

impl Advance for BytesMut {
    fn advance(&mut self, cnt: usize) {
        let _ = self.split_to(cnt);
    }
}

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

    #[test]
    fn test_json_serialization() {
        let serializer = BinarySerializer::json();
        let message = Message::ping(1);

        let serialized = serializer.serialize_message(&message).unwrap();
        let deserialized = serializer.deserialize_message(&serialized).unwrap();

        assert_eq!(message.header.msg_type, deserialized.header.msg_type);
    }

    #[test]
    fn test_messagepack_serialization() {
        let serializer = BinarySerializer::messagepack();
        let message = Message::ping(1);

        let serialized = serializer.serialize_message(&message).unwrap();
        let deserialized = serializer.deserialize_message(&serialized).unwrap();

        assert_eq!(message.header.msg_type, deserialized.header.msg_type);
    }

    #[test]
    fn test_bincode_serialization() {
        let serializer = BinarySerializer::bincode();

        let snapshot = WorldSnapshot {
            entities: vec![],
            timestamp: 100.0,
            version: "1.0.0".to_string(),
        };

        let serialized = serializer.serialize_snapshot(&snapshot).unwrap();
        let deserialized = serializer.deserialize_snapshot(&serialized).unwrap();

        assert_eq!(snapshot.timestamp, deserialized.timestamp);
    }

    #[test]
    fn test_streaming_serialization() {
        let mut stream_serializer = StreamingSerializer::new(BinaryFormat::MessagePack);
        let mut stream_deserializer = StreamingDeserializer::new(BinaryFormat::MessagePack);

        let msg1 = Message::ping(1);
        let msg2 = Message::pong(1);

        stream_serializer.write_message(&msg1).unwrap();
        stream_serializer.write_message(&msg2).unwrap();

        let data = stream_serializer.flush();
        stream_deserializer.feed(&data);

        let decoded1 = stream_deserializer.try_read_message().unwrap().unwrap();
        let decoded2 = stream_deserializer.try_read_message().unwrap().unwrap();

        assert_eq!(msg1.header.msg_type, decoded1.header.msg_type);
        assert_eq!(msg2.header.msg_type, decoded2.header.msg_type);
    }

    #[test]
    fn test_snapshot_serialization() {
        let snapshot = WorldSnapshot {
            entities: vec![
                SerializedEntity {
                    id: 1,
                    components: vec![
                        SerializedComponent {
                            id: "Position".to_string(),
                            data: ComponentData::from_json_value(serde_json::json!({"x": 10.0, "y": 20.0})),
                        }
                    ],
                }
            ],
            timestamp: 123.456,
            version: "1.0.0".to_string(),
        };

        let serializer = BinarySerializer::messagepack();
        let serialized = serializer.serialize_snapshot(&snapshot).unwrap();
        let deserialized = serializer.deserialize_snapshot(&serialized).unwrap();

        assert_eq!(snapshot.entities.len(), deserialized.entities.len());
        assert_eq!(snapshot.timestamp, deserialized.timestamp);
        assert_eq!(snapshot.version, deserialized.version);
    }
}
