#![allow(deprecated)]

use anyhow::Result;
use dittolive_ditto::prelude::*;
use rand::Rng;

#[cfg(feature = "experimental-bus")]
pub(crate) fn pubkey(ditto: &Ditto) -> PeerPubkey {
    #[allow(deprecated)]
    PeerPubkey::from(ditto.presence().graph().local_peer.peer_key.as_slice())
}

fn get_ditto(app_id: Option<AppId>) -> Result<Ditto> {
    let app_id = app_id.unwrap_or_else(AppId::generate);

    let ditto = Ditto::builder()
        .with_temp_dir()
        // If you need to benchmark against persistent storage, uncomment this and set a path
        // .with_root(Arc::new(PersistentRoot::new(format!(
        //     "/Volumes/Untitled/ditto/{}",
        //     rand::thread_rng().gen::<u64>()
        // ))?))
        .with_identity(|r| identity::OfflinePlayground::new(r, app_id))?
        .with_minimum_log_level(LogLevel::Error)
        .build()?;
    Ditto::set_logging_enabled(false);
    ditto.set_license_from_env("DITTO_LICENSE")?;
    Ok(ditto)
}

#[allow(dead_code)]
pub(crate) async fn setup(n: usize) -> Result<Vec<Ditto>> {
    let mut output = vec![];

    let app_id = AppId::generate();

    let mut tc = TransportConfig::default();
    tc.peer_to_peer.lan.enabled = false;
    tc.peer_to_peer.bluetooth_le.enabled = false;
    tc.listen.tcp.enabled = true;
    tc.listen.tcp.interface_ip = "127.0.0.1".to_string();

    let port = rand::thread_rng().gen_range(10000..(65535 - n as u16));

    for i in 0..(n as u16) {
        let ditto = get_ditto(Some(app_id.clone()))?;

        let mut tc = tc.clone();
        tc.listen.tcp.port = port + i;

        if i != 0 {
            let remote_port = port + i - 1;
            tc.connect
                .tcp_servers
                .insert(format!("127.0.0.1:{remote_port}"));
        }

        ditto.set_transport_config(tc.clone());
        ditto.sync().start()?;

        output.push(ditto);
    }

    for ditto in &output {
        while ditto.presence().graph().remote_peers.len() != n - 1 {
            // wait for all peers to connect
            tokio::time::sleep(std::time::Duration::from_millis(5)).await;
        }
    }

    // Let's wait for the router to populate the routing table. OSPF takes about 500ms to do so
    // because of timers and debouncing.
    tokio::time::sleep(std::time::Duration::from_millis(500)).await;

    Ok(output)
}
