#[cfg(feature = "std")]
use std::{
    fs::{self, File},
    io::{self, Read},
    path::Path,
    vec::Vec,
};
use miden_crypto::utils::SliceReader;
use super::{
    super::utils::serde::{
        ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
    },
    Account, AuthSecretKey, Word,
};
#[derive(Debug, Clone)]
pub struct AccountData {
    pub account: Account,
    pub account_seed: Option<Word>,
    pub auth_secret_key: AuthSecretKey,
}
impl AccountData {
    pub fn new(account: Account, account_seed: Option<Word>, auth: AuthSecretKey) -> Self {
        Self {
            account,
            account_seed,
            auth_secret_key: auth,
        }
    }
    #[cfg(feature = "std")]
    pub fn write(&self, filepath: impl AsRef<Path>) -> io::Result<()> {
        fs::write(filepath, self.to_bytes())
    }
    #[cfg(feature = "std")]
    pub fn read(filepath: impl AsRef<Path>) -> io::Result<Self> {
        let mut file = File::open(filepath)?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;
        let mut reader = SliceReader::new(&buffer);
        Ok(AccountData::read_from(&mut reader).map_err(|_| io::ErrorKind::InvalidData)?)
    }
}
impl Serializable for AccountData {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        let AccountData {
            account,
            account_seed,
            auth_secret_key: auth,
        } = self;
        account.write_into(target);
        account_seed.write_into(target);
        auth.write_into(target);
    }
}
impl Deserializable for AccountData {
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
        let account = Account::read_from(source)?;
        let account_seed = <Option<Word>>::read_from(source)?;
        let auth_secret_key = AuthSecretKey::read_from(source)?;
        Ok(Self::new(account, account_seed, auth_secret_key))
    }
    fn read_from_bytes(bytes: &[u8]) -> Result<Self, DeserializationError> {
        Self::read_from(&mut SliceReader::new(bytes))
    }
}
#[cfg(test)]
mod tests {
    use alloc::collections::BTreeMap;
    use miden_crypto::{
        dsa::rpo_falcon512::SecretKey,
        utils::{Deserializable, Serializable},
    };
    use storage::AccountStorage;
    #[cfg(feature = "std")]
    use tempfile::tempdir;
    use super::AccountData;
    use crate::{
        accounts::{
            account_id::testing::ACCOUNT_ID_REGULAR_ACCOUNT_IMMUTABLE_CODE_ON_CHAIN, storage,
            Account, AccountCode, AccountId, AuthSecretKey, Felt, Word,
        },
        assets::AssetVault,
    };
    fn build_account_data() -> AccountData {
        let id = AccountId::try_from(ACCOUNT_ID_REGULAR_ACCOUNT_IMMUTABLE_CODE_ON_CHAIN).unwrap();
        let code = AccountCode::mock();
        let vault = AssetVault::new(&[]).unwrap();
        let storage = AccountStorage::new(vec![], BTreeMap::new()).unwrap();
        let nonce = Felt::new(0);
        let account = Account::from_parts(id, vault, storage, code, nonce);
        let account_seed = Some(Word::default());
        let auth_secret_key = AuthSecretKey::RpoFalcon512(SecretKey::new());
        AccountData::new(account, account_seed, auth_secret_key)
    }
    #[test]
    fn test_serde() {
        let account_data = build_account_data();
        let serialized = account_data.to_bytes();
        let deserialized = AccountData::read_from_bytes(&serialized).unwrap();
        assert_eq!(deserialized.account, account_data.account);
        assert_eq!(deserialized.account_seed, account_data.account_seed);
        assert_eq!(
            deserialized.auth_secret_key.to_bytes(),
            account_data.auth_secret_key.to_bytes()
        );
    }
    #[cfg(feature = "std")]
    #[test]
    fn test_serde_file() {
        let dir = tempdir().unwrap();
        let filepath = dir.path().join("account_data.mac");
        let account_data = build_account_data();
        account_data.write(filepath.as_path()).unwrap();
        let deserialized = AccountData::read(filepath.as_path()).unwrap();
        assert_eq!(deserialized.account, account_data.account);
        assert_eq!(deserialized.account_seed, account_data.account_seed);
        assert_eq!(
            deserialized.auth_secret_key.to_bytes(),
            account_data.auth_secret_key.to_bytes()
        );
    }
}