//! This code was AUTOGENERATED using the codama library.
//! Please DO NOT EDIT THIS FILE, instead use visitors
//! to add features, then rerun codama to update it.
//!
//! <https://github.com/codama-idl/codama>
//!

use crate::accounts::Nonce;
use crate::ID;

/// System Program State
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
#[cfg_attr(feature = "tracing", derive(strum_macros::Display))]
pub enum SystemProgramState {
    Nonce(Nonce),
}

impl SystemProgramState {
    pub fn try_unpack(data_bytes: &[u8]) -> yellowstone_vixen_core::ParseResult<Self> {
        let data_len = data_bytes.len();
        const NONCE_LEN: usize = std::mem::size_of::<Nonce>();

        let acc = match data_len {
            NONCE_LEN => Ok(SystemProgramState::Nonce(Nonce::from_bytes(data_bytes)?)),
            _ => Err(yellowstone_vixen_core::ParseError::from(
                "Invalid Account data length".to_owned(),
            )),
        };

        #[cfg(feature = "tracing")]
        match &acc {
            Ok(acc) => {
                tracing::info!(
                    name: "correctly_parsed_account",
                    name = "account_update",
                    program = ID.to_string(),
                    account = acc.to_string()
                );
            }
            Err(e) => {
                tracing::info!(
                    name: "incorrectly_parsed_account",
                    name = "account_update",
                    program = ID.to_string(),
                    account = "error",
                    data_len = ?data_len,
                    error = ?e
                );
            }
        }

        acc
    }
}

#[derive(Debug, Copy, Clone)]
pub struct AccountParser;

impl yellowstone_vixen_core::Parser for AccountParser {
    type Input = yellowstone_vixen_core::AccountUpdate;
    type Output = SystemProgramState;

    fn id(&self) -> std::borrow::Cow<str> {
        "system::AccountParser".into()
    }

    fn prefilter(&self) -> yellowstone_vixen_core::Prefilter {
        yellowstone_vixen_core::Prefilter::builder()
            .account_owners([ID])
            .build()
            .unwrap()
    }

    async fn parse(
        &self,
        acct: &yellowstone_vixen_core::AccountUpdate,
    ) -> yellowstone_vixen_core::ParseResult<Self::Output> {
        let inner = acct
            .account
            .as_ref()
            .ok_or(solana_program_error::ProgramError::InvalidArgument)?;
        SystemProgramState::try_unpack(&inner.data)
    }
}

impl yellowstone_vixen_core::ProgramParser for AccountParser {
    #[inline]
    fn program_id(&self) -> yellowstone_vixen_core::Pubkey {
        ID.to_bytes().into()
    }
}

// #[cfg(feature = "proto")]
mod proto_parser {
    use crate::proto_def;
    use yellowstone_vixen_core::proto_helper_traits;
    proto_helper_traits!();
    use super::{AccountParser, SystemProgramState};
    use yellowstone_vixen_core::proto::ParseProto;

    use super::Nonce;
    impl IntoProto<proto_def::Nonce> for Nonce {
        fn into_proto(self) -> proto_def::Nonce {
            proto_def::Nonce {
                version: self.version as i32,
                state: self.state as i32,
                authority: self.authority.to_string(),
                blockhash: self.blockhash.to_string(),
                lamports_per_signature: self.lamports_per_signature,
            }
        }
    }

    impl IntoProto<proto_def::ProgramState> for SystemProgramState {
        fn into_proto(self) -> proto_def::ProgramState {
            let state_oneof = match self {
                SystemProgramState::Nonce(data) => {
                    proto_def::program_state::StateOneof::Nonce(data.into_proto())
                }
            };

            proto_def::ProgramState {
                state_oneof: Some(state_oneof),
            }
        }
    }

    impl ParseProto for AccountParser {
        type Message = proto_def::ProgramState;

        fn output_into_message(value: Self::Output) -> Self::Message {
            value.into_proto()
        }
    }
}
