use iamgroot::jsonrpc;

pub fn main() {
    tracing_subscriber::fmt::init();
    demo::demo();
}

mod demo {
    use super::*;

    pub fn demo() {
        let state = State;

        call(
            &state,
            1,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getBlockWithTxHashes",
                "params": {
                    "block_id": {
                        "block_hash": "0xFACE"
                    }
                }
            }),
        );

        call(
            &state,
            2,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getBlockWithTxs",
                "params": {
                    "block_id": {
                        "block_number": 123456
                    }
                }
            }),
        );

        call(
            &state,
            3,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getStateUpdate",
                "params": {
                    "block_id": "pending"
                }
            }),
        );

        call(
            &state,
            4,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getStorageAt",
                "params": {
                    "contract_address": "0x1",
                    "key": "0x02",
                    "block_id": {
                        "block_number": 42
                    },
                }
            }),
        );

        call(
            &state,
            5,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getTransactionByHash",
                "params": {
                    "transaction_hash": "0xcafebabe",
                }
            }),
        );

        call(
            &state,
            6,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getTransactionByHash",
                "params": {
                    "transaction_hash": "0xcafebabe",
                }
            }),
        );

        call(
            &state,
            7,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getTransactionByBlockIdAndIndex",
                "params": {
                    "block_id": {
                        "block_number": 42
                    },
                    "index": 24
                }
            }),
        );

        call(
            &state,
            8,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getTransactionReceipt",
                "params": {
                    "transaction_hash": "0x1"
                }
            }),
        );

        call(
            &state,
            9,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getClass",
                "params": {
                    "block_id": {
                        "block_number": 1
                    },
                    "class_hash": "0x1"
                }
            }),
        );

        call(
            &state,
            10,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getClassAt",
                "params": {
                    "block_id": {
                        "block_number": 42
                    },
                    "contract_address": "0xFF"
                }
            }),
        );

        call(
            &state,
            11,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getClassHashAt",
                "params": {
                    "block_id": "pending",
                    "contract_address": "0x1"
                }
            }),
        );

        call(
            &state,
            12,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getBlockTransactionCount",
                "params": {
                    "block_id": "latest"
                }
            }),
        );

        call(
            &state,
            13,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_call",
                "params": [
                    {
                        "entry_point_selector": "0x1",
                        "calldata": ["0x2"],
                        "contract_address": "0x3"
                    },
                    {
                        "block_number": 42
                    }
                ]
            }),
        );

        call(
            &state,
            1401,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_estimateFee",
                "params": {
                    "request": [{
                        "version": "0x0",
                        "max_fee": "0x3",
                        "signature": [
                            "0x4",
                            "0x5"
                        ],
                        "calldata": [
                            "0x6",
                            "0x7"
                        ],
                        "entry_point_selector": "0x8",
                        "contract_address": "0x9",
                        "type": "INVOKE"
                    }],
                    "simulation_flags": [],
                    "block_id": {
                        "block_number": 1
                    }
                },
            }),
        );

        call(
            &state,
            1402,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_estimateFee",
                "params": {
                    "request": [
                        {
                            "nonce": "0x01",
                            "version": "0x0",
                            "max_fee": "0x3",
                            "signature": [
                                "0x4",
                                "0x5"
                            ],
                            "sender_address": "0xA",
                            "calldata": [
                                "0xB",
                                "0xC"
                            ],
                            "entry_point_selector": "0x8",
                            "contract_address": "0x9",
                            "type": "INVOKE"
                        }
                    ],
                    "simulation_flags": [],
                    "block_id": {
                        "block_number": 1
                    }
                },
            }),
        );

        call(
            &state,
            15,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_blockNumber"
            }),
        );

        call(
            &state,
            16,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_blockHashAndNumber"
            }),
        );

        call(
            &state,
            17,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_chainId"
            }),
        );

        call(
            &state,
            18,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_syncing"
            }),
        );

        call(
            &state,
            19,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getEvents",
                "params": {
                    "filter": {
                        "to_block": {"block_number": 200},
                        "from_block": {"block_number": 100},
                        "address": "0xA",
                        "keys": [
                            ["0x1", "0x2"],
                            ["0x3", "0x4"]
                        ],
                        "continuation_token": "req-token-0",
                        "chunk_size": 42
                    }
                }
            }),
        );

        call(
            &state,
            20,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_getNonce",
                "params": {
                    "block_id": {"block_number": 12},
                    "contract_address": "0x1"
                }
            }),
        );

        call(
            &state,
            201,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_addInvokeTransaction",
                "params": {
                    "invoke_transaction": {
                        "max_fee": "0x1",
                        "version": "0x0",
                        "nonce": "0x3",
                        "signature": [
                            "0x4"
                        ],
                        "type": "INVOKE",
                        "calldata": [
                            "0x6",
                            "0x7"
                        ],
                        "entry_point_selector": "0x8",
                        "contract_address": "0x9"
                    }
                }
            }),
        );

        call(
            &state,
            202,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_addInvokeTransaction",
                "params": {
                    "invoke_transaction": {
                        "max_fee": "0x1",
                        "version": "0x1",
                        "nonce": "0x3",
                        "signature": [
                            "0x4"
                        ],
                        "type": "INVOKE",
                        "sender_address": "0xA",
                        "calldata": [
                            "0xB",
                            "0xC"
                        ]
                    }
                }
            }),
        );

        call(
            &state,
            21,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_addDeclareTransaction",
                "params": {
                    "declare_transaction": {
                        "type": "DECLARE",
                        "max_fee": "0x1",
                        "version": "0x1",
                        "nonce": "0x3",
                        "signature": [
                            "0x4"
                        ],
                        "contract_class": {
                            "abi": [],
                            "entry_points_by_type": {
                                "constructor": [],
                                "external": [],
                                "l1_handler": []
                            },
                            "program": "CAFEBABE"
                        },
                        "sender_address": "0xA"
                    }
                }
            }),
        );

        call(
            &state,
            22,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_addDeclareTransaction",
                "params": {
                    "declare_transaction": {
                        "max_fee": "0x1",
                        "version": "0x2",
                        "nonce": "0x3",
                        "signature": [
                            "0x4"
                        ],
                        "compiled_class_hash": "0xB",
                        "contract_class": {
                            "abi": "just-another-string",
                            "entry_points_by_type": {
                                "constructor": [],
                                "external": [],
                                "l1_handler": []
                            },
                            "sierra_program": [
                                "0xAA",
                                "0xBB",
                                "0xCC"
                            ],
                            "contract_class_version": "some-version"
                        },
                        "sender_address": "0xC",
                        "type": "DECLARE"
                    }
                }
            }),
        );

        call(
            &state,
            23,
            serde_json::json!({
                "jsonrpc": "2.0",
                "method": "starknet_addDeployAccountTransaction",
                "params": {
                    "deploy_account_transaction": {
                        "max_fee": "0x1",
                        "version": "0x1",
                        "nonce": "0x3",
                        "signature": [
                            "0x4"
                        ],
                        "contract_address_salt": "0x5",
                        "type": "DEPLOY_ACCOUNT",
                        "class_hash": "0x7",
                        "constructor_calldata": [
                            "0x8"
                        ]
                    }
                }
            }),
        );
    }

    fn call<T: gen::blocking::Rpc>(rpc: &T, id: i64, json: serde_json::Value) {
        let req: jsonrpc::Request = serde_json::from_value(json).unwrap();
        let req = req.with_id(jsonrpc::Id::Number(id));
        let json = serde_json::to_string_pretty(&req).unwrap();
        tracing::debug!(">>> {json}");

        let req: jsonrpc::Request = serde_json::from_str(&json).unwrap();
        let res = gen::blocking::handle(rpc, &req);
        let json = serde_json::to_string_pretty(&res).unwrap();
        tracing::debug!("<<< {json}");
    }
}

struct State;

#[allow(non_snake_case)]
impl gen::blocking::Rpc for State {
    fn getBlockWithTxHashes(
        &self,
        block_id: gen::BlockId,
    ) -> std::result::Result<gen::GetBlockWithTxHashesResult, jsonrpc::Error>
    {
        let result = gen::GetBlockWithTxHashesResult::BlockWithTxHashes(
            gen::BlockWithTxHashes {
                status: gen::BlockStatus::Pending,
                block_header: gen::BlockHeader {
                    block_hash: gen::BlockHash(gen::Felt::try_new("0x1")?),
                    timestamp: gen::BlockHeaderTimestamp::try_new(1042)?,
                    sequencer_address: gen::Felt::try_new("0x2")?,
                    block_number: gen::BlockNumber::try_new(42)?,
                    new_root: gen::Felt::try_new("0x3")?,
                    parent_hash: gen::BlockHash(gen::Felt::try_new("0x4")?),
                    l1_gas_price: gen::ResourcePrice {
                        price_in_fri: gen::Felt::try_new("0x4")?,
                        price_in_wei: gen::Felt::try_new("0x4")?,
                    },
                    starknet_version: "starknet-version".to_string(),
                    l1_da_mode: Some(gen::BlockHeaderL1DaMode::Blob),
                    l1_data_gas_price: Some(gen::ResourcePrice {
                        price_in_fri: gen::Felt::try_new("0x5")?,
                        price_in_wei: gen::Felt::try_new("0x6")?,
                    }),
                },
                block_body_with_tx_hashes: gen::BlockBodyWithTxHashes {
                    transactions: vec![
                        gen::TxnHash(gen::Felt::try_new("0x5")?),
                        gen::TxnHash(gen::Felt::try_new("0x6")?),
                    ],
                },
            },
        );
        tracing::debug!(?block_id, ?result);
        Ok(result)
    }

    fn getBlockWithTxs(
        &self,
        block_id: gen::BlockId,
    ) -> std::result::Result<gen::GetBlockWithTxsResult, jsonrpc::Error> {
        let result =
            gen::GetBlockWithTxsResult::BlockWithTxs(gen::BlockWithTxs {
                status: gen::BlockStatus::AcceptedOnL1,
                block_header: gen::BlockHeader {
                    block_hash: gen::BlockHash(gen::Felt::try_new("0x1")?),
                    timestamp: gen::BlockHeaderTimestamp::try_new(1042)?,
                    sequencer_address: gen::Felt::try_new("0x2")?,
                    block_number: gen::BlockNumber::try_new(42)?,
                    new_root: gen::Felt::try_new("0x3")?,
                    parent_hash: gen::BlockHash(gen::Felt::try_new("0x4")?),
                    l1_gas_price: gen::ResourcePrice {
                        price_in_fri: gen::Felt::try_new("0x1111")?,
                        price_in_wei: gen::Felt::try_new("0x2222")?,
                    },
                    starknet_version: "starknet-version".to_owned(),
                    l1_da_mode: Some(gen::BlockHeaderL1DaMode::Blob),
                    l1_data_gas_price: Some(gen::ResourcePrice {
                        price_in_fri: gen::Felt::try_new("0x5")?,
                        price_in_wei: gen::Felt::try_new("0x6")?,
                    }),
                },
                block_body_with_txs: gen::BlockBodyWithTxs {
                    transactions: vec![gen::TransactionsInBlock {
                        txn: gen::Txn::InvokeTxn(gen::InvokeTxn::InvokeTxnV0(
                            gen::InvokeTxnV0 {
                                r#type: gen::InvokeTxnV0Type::Invoke,
                                max_fee: gen::Felt::try_new("0x1111")?,
                                version: gen::InvokeTxnV0Version::V0x0,
                                signature: vec![gen::Felt::try_new("0x1111")?],
                                contract_address: gen::Address(
                                    gen::Felt::try_new("0x1111")?,
                                ),
                                entry_point_selector: gen::Felt::try_new(
                                    "0x1111",
                                )?,
                                calldata: vec![gen::Felt::try_new("0x1111")?],
                            },
                        )),
                        transaction_hash: gen::TxnHash(gen::Felt::try_new(
                            "0x1111",
                        )?),
                    }],
                },
            });
        tracing::debug!(?block_id, ?result);
        Ok(result)
    }

    fn getStateUpdate(
        &self,
        block_id: gen::BlockId,
    ) -> std::result::Result<gen::GetStateUpdateResult, jsonrpc::Error> {
        let result = gen::GetStateUpdateResult::StateUpdate(gen::StateUpdate {
            new_root: gen::Felt::try_new("0xcafebabe")?,
            block_hash: gen::BlockHash(gen::Felt::try_new("0xdeadbeef")?),
            state_diff: gen::StateDiff {
                nonces: vec![gen::NonceUpdate {
                    nonce: Some(gen::Felt::try_new("0x1")?),
                    contract_address: Some(gen::Address(gen::Felt::try_new(
                        "0x2",
                    )?)),
                }],
                declared_classes: vec![gen::NewClasses {
                    class_hash: Some(gen::Felt::try_new("0x101")?),
                    compiled_class_hash: Some(gen::Felt::try_new("0x102")?),
                }],
                deprecated_declared_classes: vec![gen::Felt::try_new("0x3")?],
                deployed_contracts: vec![gen::DeployedContractItem {
                    address: gen::Felt::try_new("0x4")?,
                    class_hash: gen::Felt::try_new("0x5")?,
                }],
                replaced_classes: vec![gen::ReplacedClass {
                    contract_address: Some(gen::Address(gen::Felt::try_new(
                        "0x6",
                    )?)),
                    class_hash: Some(gen::Felt::try_new("0x7")?),
                }],
                storage_diffs: vec![gen::ContractStorageDiffItem {
                    address: gen::Felt::try_new("0x8")?,
                    storage_entries: vec![gen::StorageDiffItem {
                        key: Some(gen::Felt::try_new("0x9")?),
                        value: Some(gen::Felt::try_new("0xA")?),
                    }],
                }],
            },
            old_root: gen::Felt::try_new("0xFACE")?,
        });
        tracing::debug!(?block_id, ?result);
        Ok(result)
    }

    fn getStorageAt(
        &self,
        contract_address: gen::Address,
        key: gen::StorageKey,
        block_id: gen::BlockId,
    ) -> std::result::Result<gen::Felt, jsonrpc::Error> {
        let result = gen::Felt::try_new("0xcafebabe")?;
        tracing::debug!(?contract_address, ?key, ?block_id, ?result);
        Ok(result)
    }

    fn getTransactionByHash(
        &self,
        transaction_hash: gen::TxnHash,
    ) -> std::result::Result<gen::GetTransactionByHashResult, jsonrpc::Error>
    {
        let result = gen::GetTransactionByHashResult {
            txn: gen::Txn::L1HandlerTxn(gen::L1HandlerTxn {
                version: gen::L1HandlerTxnVersion::V0x0,
                r#type: gen::L1HandlerTxnType::L1Handler,
                nonce: gen::NumAsHex::try_new("0x1")?,
                function_call: gen::FunctionCall {
                    calldata: vec![gen::Felt::try_new("0x1")?],
                    entry_point_selector: gen::Felt::try_new("0x1")?,
                    contract_address: gen::Address(gen::Felt::try_new("0x1")?),
                },
            }),
            transaction_hash: transaction_hash.clone(),
        };
        tracing::debug!(?transaction_hash, ?result);
        Ok(result)
    }

    fn getTransactionByBlockIdAndIndex(
        &self,
        block_id: gen::BlockId,
        index: gen::GetTransactionByBlockIdAndIndexIndex,
    ) -> std::result::Result<
        gen::GetTransactionByBlockIdAndIndexResult,
        jsonrpc::Error,
    > {
        let result = gen::GetTransactionByBlockIdAndIndexResult {
            txn: gen::Txn::DeclareTxn(gen::DeclareTxn::DeclareTxnV2(
                gen::DeclareTxnV2 {
                    compiled_class_hash: gen::Felt::try_new("0x1")?,
                    r#type: gen::DeclareTxnV2Type::Declare,
                    sender_address: gen::Address(gen::Felt::try_new("0x1")?),
                    max_fee: gen::Felt::try_new("0x1")?,
                    version: gen::DeclareTxnV2Version::V0x2,
                    signature: vec![gen::Felt::try_new("0x1")?],
                    nonce: gen::Felt::try_new("0x1")?,
                    class_hash: gen::Felt::try_new("0x1")?,
                },
            )),
            transaction_hash: gen::TxnHash(gen::Felt::try_new("0x1")?),
        };
        tracing::debug!(?block_id, ?index, ?result);
        Ok(result)
    }

    fn getTransactionReceipt(
        &self,
        transaction_hash: gen::TxnHash,
    ) -> std::result::Result<gen::TxnReceiptWithBlockInfo, jsonrpc::Error> {
        let txn_receipt = gen::TxnReceipt::DeployTxnReceipt(gen::DeployTxnReceipt {
            common_receipt_properties: gen::CommonReceiptProperties {
                messages_sent: vec![gen::MsgToL1 {
                    to_address: gen::Felt::try_new("0x1")?,
                    payload: vec![
                        gen::Felt::try_new("0x1")?,
                        gen::Felt::try_new("0x1")?,
                    ],
                    from_address: gen::Felt::try_new("0x1")?,
                }],
                events: vec![gen::Event {
                    from_address: gen::Address(gen::Felt::try_new("0x42")?),
                    event_content: gen::EventContent {
                        data: vec![
                            gen::Felt::try_new("0x1")?,
                            gen::Felt::try_new("0x1")?,
                        ],
                        keys: vec![
                            gen::Felt::try_new("0x1")?,
                            gen::Felt::try_new("0x1")?,
                        ],
                    },
                }],
                transaction_hash: gen::TxnHash(gen::Felt::try_new("0x1")?),
                actual_fee: gen::FeePayment {
                    amount: gen::Felt::try_new("0x1")?,
                    unit: gen::PriceUnit::Wei,
                },
                finality_status: gen::TxnFinalityStatus::AcceptedOnL2,
                execution_resources: gen::ExecutionResources {
                    computation_resources: gen::ComputationResources {
                        steps: 42,
                        memory_holes: Some(42),
                        range_check_builtin_applications: Some(1),
                        pedersen_builtin_applications: Some(1),
                        poseidon_builtin_applications: Some(1),
                        ec_op_builtin_applications: Some(1),
                        ecdsa_builtin_applications: Some(1),
                        bitwise_builtin_applications: Some(1),
                        keccak_builtin_applications: Some(1),
                        segment_arena_builtin: Some(1),
                    },
                    data_availability: gen::ExecutionResourcesDataAvailability {
                        l1_data_gas: 42,
                        l1_gas: 142,
                    },
                },
                result_common_receipt_properties: gen::ResultCommonReceiptProperties::SuccessfulCommonReceiptProperties(
                    gen::SuccessfulCommonReceiptProperties {
                        execution_status: gen::SuccessfulCommonReceiptPropertiesExecutionStatus::Succeeded,
                    }
                ),
            },
            contract_address: gen::Felt::try_new("0x1")?,
            r#type: gen::DeployTxnReceiptType::Deploy,
        });
        let result = gen::TxnReceiptWithBlockInfo {
            txn_receipt,
            block_hash: None,
            block_number: None,
        };
        tracing::debug!(?transaction_hash, ?result);
        Ok(result)
    }

    fn getClass(
        &self,
        block_id: gen::BlockId,
        class_hash: gen::Felt,
    ) -> std::result::Result<gen::GetClassResult, jsonrpc::Error> {
        let result = gen::GetClassResult::ContractClass(gen::ContractClass {
            entry_points_by_type: gen::ContractClassEntryPointsByType {
                constructor: vec![gen::SierraEntryPoint {
                    selector: gen::Felt::try_new("0x11")?,
                    function_idx: 1,
                }],
                external: vec![gen::SierraEntryPoint {
                    selector: gen::Felt::try_new("0x22")?,
                    function_idx: 2,
                }],
                l1_handler: vec![gen::SierraEntryPoint {
                    selector: gen::Felt::try_new("0x33")?,
                    function_idx: 3,
                }],
            },
            abi: Some("abi".to_string()),
            sierra_program: vec![gen::Felt::try_new("0xABCD")?],
            contract_class_version: "0".to_string(),
        });
        tracing::debug!("block_id={block_id:?}\nclass_hash={class_hash:?}\nresult={result:#?}");
        Ok(result)
    }

    fn getClassHashAt(
        &self,
        block_id: gen::BlockId,
        contract_address: gen::Address,
    ) -> std::result::Result<gen::Felt, jsonrpc::Error> {
        let result = gen::Felt::try_new("0xF")?;
        tracing::debug!(
            "block_id={block_id:?}\ncontract_address={contract_address:?}\nresult={result:#?}"
        );
        Ok(result)
    }

    fn getClassAt(
        &self,
        block_id: gen::BlockId,
        contract_address: gen::Address,
    ) -> std::result::Result<gen::GetClassAtResult, jsonrpc::Error> {
        let result = gen::GetClassAtResult::ContractClass(gen::ContractClass {
            entry_points_by_type: gen::ContractClassEntryPointsByType {
                constructor: vec![gen::SierraEntryPoint {
                    selector: gen::Felt::try_new("0x11")?,
                    function_idx: 1,
                }],
                external: vec![gen::SierraEntryPoint {
                    selector: gen::Felt::try_new("0x22")?,
                    function_idx: 2,
                }],
                l1_handler: vec![gen::SierraEntryPoint {
                    selector: gen::Felt::try_new("0x33")?,
                    function_idx: 3,
                }],
            },
            abi: Some("abi".to_string()),
            sierra_program: vec![gen::Felt::try_new("0x44")?],
            contract_class_version: "0".to_string(),
        });
        tracing::debug!(
            "block_id={block_id:?}\ncontract_address={contract_address:?}\nresult={result:#?}"
        );
        Ok(result)
    }

    fn getBlockTransactionCount(
        &self,
        block_id: gen::BlockId,
    ) -> std::result::Result<gen::GetBlockTransactionCountResult, jsonrpc::Error>
    {
        let result = gen::GetBlockTransactionCountResult::try_new(42)?;
        tracing::debug!("block_id={block_id:?}\nresult={result:#?}");
        Ok(result)
    }

    fn call(
        &self,
        request: gen::FunctionCall,
        block_id: gen::BlockId,
    ) -> std::result::Result<Vec<gen::Felt>, jsonrpc::Error> {
        let result = vec![gen::Felt::try_new("0x0")?];
        tracing::debug!(
            "block_id={block_id:?}\nreques={request:#?}\nresult={result:#?}"
        );
        Ok(result)
    }

    fn estimateFee(
        &self,
        request: Vec<gen::BroadcastedTxn>,
        simulation_flags: Vec<gen::SimulationFlagForEstimateFee>,
        block_id: gen::BlockId,
    ) -> std::result::Result<Vec<gen::FeeEstimate>, jsonrpc::Error> {
        let result = vec![gen::FeeEstimate {
            data_gas_consumed: gen::Felt::try_new("0xDD")?,
            data_gas_price: gen::Felt::try_new("0xEE")?,
            gas_consumed: gen::Felt::try_new("0xAA")?,
            gas_price: gen::Felt::try_new("0xBB")?,
            overall_fee: gen::Felt::try_new("0xCC")?,
            unit: gen::PriceUnit::Wei,
        }];
        tracing::debug!(
            "block_id={block_id:?}\nsimulation_flags={simulation_flags:?}\nreques={request:#?}\nresult={result:#?}"
        );
        Ok(result)
    }

    fn blockNumber(
        &self,
    ) -> std::result::Result<gen::BlockNumber, jsonrpc::Error> {
        Ok(gen::BlockNumber::try_new(42)?)
    }

    fn blockHashAndNumber(
        &self,
    ) -> std::result::Result<gen::BlockHashAndNumberResult, jsonrpc::Error>
    {
        Ok(gen::BlockHashAndNumberResult {
            block_number: gen::BlockNumber::try_new(42)?,
            block_hash: gen::BlockHash(gen::Felt::try_new("0xface")?),
        })
    }

    fn chainId(&self) -> std::result::Result<gen::ChainId, jsonrpc::Error> {
        Ok(gen::ChainId::try_new("0xdeadbeef")?)
    }

    fn syncing(
        &self,
    ) -> std::result::Result<gen::SyncingResult, jsonrpc::Error> {
        Ok(gen::SyncingResult::SyncStatus(gen::SyncStatus {
            starting_block_num: gen::BlockNumber::try_new(42)?,
            current_block_hash: gen::BlockHash(gen::Felt::try_new("0x2")?),
            starting_block_hash: gen::BlockHash(gen::Felt::try_new("0x3")?),
            current_block_num: gen::BlockNumber::try_new(42)?,
            highest_block_hash: gen::BlockHash(gen::Felt::try_new("0x5")?),
            highest_block_num: gen::BlockNumber::try_new(42)?,
        }))
    }

    fn getEvents(
        &self,
        filter: gen::GetEventsFilter,
    ) -> std::result::Result<gen::EventsChunk, jsonrpc::Error> {
        let result = gen::EventsChunk {
            continuation_token: Some("token-0".to_string()),
            events: vec![gen::EmittedEvent {
                event: gen::Event {
                    from_address: gen::Address(gen::Felt::try_new("0xA")?),
                    event_content: gen::EventContent {
                        keys: vec![gen::Felt::try_new("0x4")?],
                        data: vec![gen::Felt::try_new("0x3")?],
                    },
                },
                block_hash: Some(gen::BlockHash(gen::Felt::try_new("0x2")?)),
                block_number: Some(gen::BlockNumber::try_new(42)?),
                transaction_hash: gen::TxnHash(gen::Felt::try_new("0x1")?),
            }],
        };
        tracing::debug!(?filter, ?result);
        Ok(result)
    }

    fn getNonce(
        &self,
        block_id: gen::BlockId,
        contract_address: gen::Address,
    ) -> std::result::Result<gen::Felt, jsonrpc::Error> {
        let result = gen::Felt::try_new("0xA")?;
        tracing::debug!(?block_id, ?contract_address, ?result);
        Ok(result)
    }

    fn addInvokeTransaction(
        &self,
        invoke_transaction: gen::BroadcastedInvokeTxn,
    ) -> std::result::Result<gen::AddInvokeTransactionResult, jsonrpc::Error>
    {
        let result = gen::AddInvokeTransactionResult {
            transaction_hash: gen::TxnHash(gen::Felt::try_new("0x1")?),
        };
        tracing::debug!(?invoke_transaction, ?result);
        Ok(result)
    }

    fn addDeclareTransaction(
        &self,
        declare_transaction: gen::BroadcastedDeclareTxn,
    ) -> std::result::Result<gen::AddDeclareTransactionResult, jsonrpc::Error>
    {
        let result = gen::AddDeclareTransactionResult {
            class_hash: gen::Felt::try_new("0x1")?,
            transaction_hash: gen::TxnHash(gen::Felt::try_new("0x2")?),
        };
        tracing::debug!(?declare_transaction, ?result);
        Ok(result)
    }

    fn addDeployAccountTransaction(
        &self,
        deploy_account_transaction: gen::BroadcastedDeployAccountTxn,
    ) -> std::result::Result<
        gen::AddDeployAccountTransactionResult,
        jsonrpc::Error,
    > {
        let result = gen::AddDeployAccountTransactionResult {
            transaction_hash: gen::TxnHash(gen::Felt::try_new("0x1")?),
            contract_address: gen::Felt::try_new("0x2")?,
        };
        tracing::debug!(?deploy_account_transaction, ?result);
        Ok(result)
    }

    fn traceTransaction(
        &self,
        _transaction_hash: gen::TxnHash,
    ) -> std::result::Result<gen::TransactionTrace, jsonrpc::Error> {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }

    fn traceBlockTransactions(
        &self,
        _block_hash: gen::BlockId,
    ) -> std::result::Result<Vec<gen::BlockTransactionTrace>, jsonrpc::Error>
    {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }

    fn specVersion(&self) -> std::result::Result<String, jsonrpc::Error> {
        Ok("0.0.0".to_string())
    }

    fn getTransactionStatus(
        &self,
        _transaction_hash: gen::TxnHash,
    ) -> std::result::Result<gen::GetTransactionStatusResult, jsonrpc::Error>
    {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }

    fn estimateMessageFee(
        &self,
        _message: gen::MsgFromL1,
        _block_id: gen::BlockId,
    ) -> std::result::Result<gen::FeeEstimate, jsonrpc::Error> {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }

    fn simulateTransactions(
        &self,
        _block_id: gen::BlockId,
        _transactions: Vec<gen::BroadcastedTxn>,
        _simulation_flags: Vec<gen::SimulationFlag>,
    ) -> std::result::Result<Vec<gen::SimulatedTransaction>, jsonrpc::Error>
    {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }

    fn getProof(
        &self,
        _block_id: gen::BlockId,
        _contract_address: gen::Address,
        _keys: Vec<gen::Address>,
    ) -> std::result::Result<gen::GetProofResult, jsonrpc::Error> {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }

    fn getTxStatus(
        &self,
        _transaction_hash: gen::TxnHash,
    ) -> std::result::Result<gen::TxGatewayStatus, jsonrpc::Error> {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }

    fn version(&self) -> std::result::Result<String, jsonrpc::Error> {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }

    fn getBlockWithReceipts(
        &self,
        _block_id: gen::BlockId,
    ) -> std::result::Result<gen::GetBlockWithReceiptsResult, jsonrpc::Error>
    {
        Err(jsonrpc::Error {
            code: 1,
            message: "not implemented".to_owned(),
        })
    }
}
