use crate::{
    deserialisations::{
        de_string_to_bytes, de_string_to_h256, de_string_to_u64, de_string_to_u64_pure,
        de_string_to_vec_of_bytes,
    },
    Decode, Deserialize, Encode, RuntimeDebug, Vec, H256,
};

const NUMBER_OF_TOPICS: usize = 3;

#[derive(RuntimeDebug, Clone, PartialEq, Deserialize, Encode, Decode)]
pub struct EvmResponse {
    #[serde(default)]
    id: Option<u32>,
    #[serde(default, deserialize_with = "de_string_to_bytes")]
    jsonrpc: Option<Vec<u8>>,
    #[serde(default, deserialize_with = "de_string_to_bytes")]
    pub error: Option<Vec<u8>>,
    #[serde(default)]
    pub result: Option<EvmResponseType>,
}

#[derive(RuntimeDebug, Clone, PartialEq, Deserialize, Encode, Decode)]
#[serde(untagged)]
pub enum EvmResponseType {
    #[serde(deserialize_with = "de_string_to_u64_pure")]
    BlockNumber(u64),
    TransactionLogs(Vec<Log>),
}

#[derive(RuntimeDebug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Encode, Decode)]
#[serde(rename_all = "camelCase")]
pub struct Log {
    #[serde(default, deserialize_with = "de_string_to_h256")]
    pub transaction_hash: Option<H256>,
    #[serde(default, deserialize_with = "de_string_to_u64")]
    pub block_number: Option<u64>,
    #[serde(default, deserialize_with = "de_string_to_vec_of_bytes")]
    pub topics: Vec<Vec<u8>>,
    pub removed: bool,
}

impl Log {
    pub fn is_sufficient(&self) -> bool {
        self.transaction_hash.is_some()
            && self.block_number.is_some()
            && self.topics.len() == NUMBER_OF_TOPICS
    }
}
