use crate::types::{Bytes, H160, H256, U256};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
mod filter;
pub use filter::*;
#[derive(Debug, Clone, Serialize)]
pub enum TraceType {
    
    #[serde(rename = "trace")]
    Trace,
    
    #[serde(rename = "vmTrace")]
    VmTrace,
    
    #[serde(rename = "stateDiff")]
    StateDiff,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct BlockTrace {
    
    pub output: Bytes,
    
    pub trace: Option<Vec<TransactionTrace>>,
    
    #[serde(rename = "vmTrace")]
    pub vm_trace: Option<VMTrace>,
    
    #[serde(rename = "stateDiff")]
    pub state_diff: Option<StateDiff>,
    
    #[serde(rename = "transactionHash")]
    pub transaction_hash: Option<H256>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct ChangedType<T> {
    
    pub from: T,
    
    pub to: T,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub enum Diff<T> {
    
    #[serde(rename = "=")]
    Same,
    
    #[serde(rename = "+")]
    Born(T),
    
    #[serde(rename = "-")]
    Died(T),
    
    #[serde(rename = "*")]
    Changed(ChangedType<T>),
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct AccountDiff {
    
    pub balance: Diff<U256>,
    
    pub nonce: Diff<U256>,
    
    pub code: Diff<Bytes>,
    
    pub storage: BTreeMap<H256, Diff<H256>>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct StateDiff(pub BTreeMap<H160, AccountDiff>);
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct TransactionTrace {
    
    #[serde(rename = "traceAddress")]
    pub trace_address: Vec<usize>,
    
    pub subtraces: usize,
    
    pub action: Action,
    
    #[serde(rename = "type")]
    pub action_type: ActionType,
    
    pub result: Option<Res>,
    
    pub error: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct VMTrace {
    
    pub code: Bytes,
    
    pub ops: Vec<VMOperation>,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct VMOperation {
    
    pub pc: usize,
    
    pub cost: u64,
    
    pub ex: Option<VMExecutedOperation>,
    
    
    pub sub: Option<VMTrace>,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct VMExecutedOperation {
    
    #[serde(rename = "used")]
    pub used: u64,
    
    pub push: Vec<U256>,
    
    #[serde(rename = "mem")]
    pub mem: Option<MemoryDiff>,
    
    #[serde(rename = "store")]
    pub store: Option<StorageDiff>,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct MemoryDiff {
    
    pub off: usize,
    
    pub data: Bytes,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct StorageDiff {
    
    pub key: U256,
    
    pub val: U256,
}
#[cfg(test)]
mod tests {
    use super::*;
    
    
    
    const EXAMPLE_TRACE: &str = include!("./example-trace-str.rs");
    
    
    
    const EXAMPLE_TRACES: &str = include!("./example-traces-str.rs");
    #[test]
    fn test_serialize_trace_type() {
        let trace_type_str = r#"["trace","vmTrace","stateDiff"]"#;
        let trace_type = vec![TraceType::Trace, TraceType::VmTrace, TraceType::StateDiff];
        let se_trace_str: String = serde_json::to_string(&trace_type).unwrap();
        assert_eq!(trace_type_str, se_trace_str);
    }
    #[test]
    fn test_deserialize_blocktrace() {
        let _trace: BlockTrace = serde_json::from_str(EXAMPLE_TRACE).unwrap();
    }
    #[test]
    fn test_deserialize_blocktraces() {
        let _traces: Vec<BlockTrace> = serde_json::from_str(EXAMPLE_TRACES).unwrap();
    }
}