use androscalpel_serializer::{Error, ReadSeek, Result, Serializable};
use std::io::Write;

#[derive(Debug, Clone, PartialEq, Eq, Serializable, Default)]
pub struct Magic([u8; 16]);

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ApkSigningBlock {
    // TODO: parse the block: Length (u64) - id - value (size = length - 4)
    pub data: Vec<u8>,
}

impl ApkSigningBlock {
    pub const MAGIC: Magic = Magic([
        b'A', b'P', b'K', b' ', b'S', b'i', b'g', b' ', b'B', b'l', b'o', b'c', b'k', b' ', b'4',
        b'2',
    ]);
}

impl Serializable for ApkSigningBlock {
    fn serialize(&self, output: &mut dyn Write) -> Result<()> {
        let size: u64 = self.data.len() as u64 + 16 + 4;
        size.serialize(output)?;
        for c in &self.data {
            c.serialize(output)?;
        }
        size.serialize(output)?;
        Self::MAGIC.serialize(output)?;
        Ok(())
    }

    fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
        let size = u64::deserialize(input)?;
        let mut data = vec![];
        for _ in 0..(size - 8 - 16) {
            data.push(u8::deserialize(input)?);
        }
        let size_b = u64::deserialize(input)?;
        if size_b != size {
            return Err(Error::DeserializationError(
                "Not an apk signing block: the size fields do not match".into(),
            ))?;
        }
        let magic = Magic::deserialize(input)?;
        if magic != Self::MAGIC {
            return Err(Error::DeserializationError(
                "Not an apk signing block: invalid magic number".into(),
            ))?;
        }
        Ok(Self { data })
    }

    fn size(&self) -> usize {
        self.data.len() + 16 + 8 + 8
    }
}
