use crate::dat_key::Kid;
use crate::error::DatError;
use crate::util::now_unix_timestamp;

pub struct DatRecords<T: Kid> {
    dat: String,
    expire: u64,
    kid: T,
    plain_ptr: usize,
    secure_ptr: usize,
    sign_ptr: usize,
}
impl <T: Kid> DatRecords<T> {
    pub fn from(dat: String) -> Result<Self, DatError> {
        let dat_ptr = dat.as_ptr() as usize;
        let mut dat_split = dat.split('.');

        let expire = dat_split.next().ok_or_else(|| DatError::InvalidDatFormat)?;
        let expire = expire.parse::<u64>().map_err(|_| DatError::InvalidDatFormat)?;
        if expire < now_unix_timestamp() {
            return Err(DatError::InvalidDat);
        }

        let kid = dat_split.next().ok_or_else(|| DatError::InvalidDatFormat)?;
        let kid = T::from_str(kid).map_err(|_| DatError::InvalidDatKidFormat)?;

        let plain = dat_split.next().ok_or_else(|| DatError::InvalidDatFormat)?;
        let plain_ptr = plain.as_ptr() as usize - dat_ptr;

        let secure = dat_split.next().ok_or_else(|| DatError::InvalidDatFormat)?;
        let secure_ptr = secure.as_ptr() as usize - dat_ptr;

        let sign = dat_split.next().filter(|e| !e.is_empty()).ok_or_else(|| DatError::InvalidDatFormat)?;
        let sign_ptr = sign.as_ptr() as usize - dat_ptr;

        if dat_split.next().is_some() {
            return Err(DatError::InvalidDatFormat);
        }

        Ok(DatRecords {
            dat,
            expire,
            kid,
            plain_ptr,
            secure_ptr,
            sign_ptr,
        })
    }

    pub fn kid(&self) -> &T {
        &self.kid
    }

    pub fn expire(&self) -> u64 {
        self.expire
    }

    pub fn plain_base64(&self) -> &str {
        &self.dat[self.plain_ptr .. self.secure_ptr - 1]
    }

    pub fn secure_base64(&self) -> &str {
        &self.dat[self.secure_ptr .. self.sign_ptr - 1]
    }

    pub fn sign_base64(&self) -> &str {
        &self.dat[self.sign_ptr ..]
    }

    pub fn body_str(&self) -> &str {
        &self.dat[0 .. self.sign_ptr - 1]
    }
}
