use serde::Serializer;
use serde_bytes::ByteBuf;

pub const ACTION_TYPE_SPAWN: u8 = 1;
pub const ACTION_TYPE_DESPAWN: u8 = 2;
pub const ACTION_TYPE_CHANGE: u8 = 3;
pub const ACTION_TYPE_INVOKE: u8 = 4;
pub const ACTION_TYPE_FRAME: u8 = 5;

#[derive(Default)]
struct AxonSnapshotEntity {
    t: u32,
    m: std::collections::HashMap<u32, Vec<u8>>,
}

#[derive(Default)]
pub struct AxonSnapshot {
    entities: std::collections::HashMap<u64, AxonSnapshotEntity>,
}

impl AxonSnapshot {
    pub fn spawn(&mut self, id: u64, t: u32) {
        self.entities.insert(
            id,
            AxonSnapshotEntity {
                t,
                m: std::collections::HashMap::new(),
            },
        );
    }
    pub fn despawn(&mut self, id: u64) {
        self.entities.remove(&id);
    }
    pub fn change(&mut self, id: u64, t: u32, v: &[u8]) {
        if let Some(m) = self.entities.get_mut(&id) {
            m.m.insert(t, v.to_vec());
        }
    }
    pub fn snapshot(&mut self) -> Vec<u8> {
        let mut s = axon_sbin::SbinSerializer::new();
        for (id, entity) in self.entities.iter() {
            s.serialize_u8(ACTION_TYPE_SPAWN).unwrap();
            s.serialize_u64(*id).unwrap();
            s.serialize_u32(entity.t).unwrap();
            s.serialize_bytes(&[]).unwrap();

            for (t, variant) in entity.m.iter() {
                s.serialize_u8(ACTION_TYPE_CHANGE).unwrap();
                s.serialize_u64(*id).unwrap();
                s.serialize_u32(*t).unwrap();
                s.serialize_bytes(variant).unwrap();
            }
        }
        s.into_vec()
    }
}

pub fn receive_events(client_id: u64, raw: &[u8], events: &mut Vec<axon_core::AxonReceiveEvent>) {
    let mut dec = axon_sbin::SbinDeserializer::from_bytes(raw);
    loop {
        let act: Result<u8, _> = serde::Deserialize::deserialize(&mut dec);
        if let Ok(act) = act {
            let id: Result<u64, _> = serde::Deserialize::deserialize(&mut dec);
            if let Ok(id) = id {
                let t: Result<u32, _> = serde::Deserialize::deserialize(&mut dec);
                if let Ok(t) = t {
                    let v: Result<ByteBuf, _> = serde::Deserialize::deserialize(&mut dec);
                    if let Ok(vv) = v {
                        if act == ACTION_TYPE_INVOKE {
                            events.push(axon_core::AxonReceiveEvent::Invoke {
                                client_id,
                                id,
                                t,
                                v: vv.into_vec(),
                            });
                        }
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            } else {
                break;
            }
        } else {
            break;
        }
    }
}
