#![allow(dead_code)]

use libp2p::{
    core::{muxing::StreamMuxerBox, transport::Boxed, upgrade},
    dns, identity, noise, tcp, websocket, PeerId, Transport,
};
use std::time::Duration;

pub const KIB: usize = 1024;
pub const MIB: usize = 1024 * KIB;

pub struct TransportBuilder {
    timeout: Duration,
    yamux_window_size: u32,
    yamux_maximum_buffer_size: usize,
}

impl TransportBuilder {
    pub fn new() -> TransportBuilder {
        TransportBuilder {
            timeout: Duration::from_secs(20),
            yamux_window_size: 256 * (KIB as u32),
            yamux_maximum_buffer_size: MIB,
        }
    }

    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    pub fn yamux_window_size(mut self, yamux_window_size: u32) -> Self {
        self.yamux_window_size = yamux_window_size;
        self
    }

    pub fn yamux_maximum_buffer_size(mut self, yamux_maximum_buffer_size: usize) -> Self {
        self.yamux_maximum_buffer_size = yamux_maximum_buffer_size;
        self
    }

    pub fn build(self, keypair: identity::Keypair) -> Boxed<(PeerId, StreamMuxerBox)> {
        let tcp_config = tcp::Config::new().nodelay(true);
        let tcp_trans = tcp::tokio::Transport::new(tcp_config.clone());
        let dns = dns::tokio::Transport::system(tcp_trans).expect("Can construct DNS; qed");

        let tcp_trans = tcp::tokio::Transport::new(tcp_config);
        let dns_for_wss = dns::tokio::Transport::system(tcp_trans)
            .expect("Valid config provided; qed");

        let transport = websocket::WsConfig::new(dns_for_wss).or_transport(dns);

        let authentication_config =
            noise::Config::new(&keypair).expect("Can create noise config; qed");

        let multiplexing_config = {
            let mut yamux_config = libp2p::yamux::Config::default();

            yamux_config.set_window_update_mode(libp2p::yamux::WindowUpdateMode::on_read());
            yamux_config.set_max_buffer_size(self.yamux_maximum_buffer_size);
            yamux_config.set_receive_window_size(self.yamux_window_size);

            yamux_config
        };

        transport
            .upgrade(upgrade::Version::V1Lazy)
            .authenticate(authentication_config)
            .multiplex(multiplexing_config)
            .timeout(self.timeout)
            .boxed()
    }
}
