use bft_json_crdt::{
    json_crdt::{BaseCrdt, SignedOp},
    keypair::make_keypair,
};
use side_node::{clients::websocket::Client, crdt::TransactionList, keys, node::SideNode, utils};
use tokio::sync::mpsc;

#[tokio::test]
async fn test_distribute_via_websockets() {
    let mut node1 = setup("alice").await;
    let mut node2 = setup("bob").await;

    assert_eq!(node1.current_sha(), node2.current_sha());

    let transaction = utils::fake_generic_transaction_json("from_alice".to_string());
    let signed_op = node1.add_transaction_local(transaction);
    node2.handle_incoming(signed_op);

    assert_eq!(node1.current_sha(), node2.current_sha());

    let transaction = utils::fake_generic_transaction_json("from_alice2".to_string());
    let signed_op = node1.add_transaction_local(transaction);
    node2.handle_incoming(signed_op);

    assert_eq!(node1.current_sha(), node2.current_sha());

    let transaction = utils::fake_generic_transaction_json("from_alice3".to_string());
    let signed_op = node1.add_transaction_local(transaction);
    node2.handle_incoming(signed_op);

    assert_eq!(node1.current_sha(), node2.current_sha());
}

/// Wire everything up, ignoring things we are not using in the test
async fn setup(_: &str) -> SideNode {
    // First, load up the keys and create a bft-crdt
    let bft_crdt_keys = make_keypair();
    let bitcoin_keys = keys::bitcoin::make_keypair();
    let crdt = BaseCrdt::<TransactionList>::new(&bft_crdt_keys);

    // Channels for internal communication, and a tokio task for stdin input
    let (incoming_sender, incoming_receiver) = mpsc::channel::<SignedOp>(32);
    let (_, stdin_receiver) = std::sync::mpsc::channel();

    // Finally, create the node and return it
    let handle = Client::new(incoming_sender).await;
    let node = SideNode::new(
        crdt,
        bft_crdt_keys,
        bitcoin_keys,
        incoming_receiver,
        stdin_receiver,
        handle,
    );
    node
}
