use tokio::task;

use crate::tcp_relay_client::client_config::ClientConfig;
use crate::tcp_relay_server::server_config::ServerConfig;
use crate::test::dummy_tcp_sockets::{
    dummy_tcp_client_additions_requests, dummy_tcp_client_square_root_requests, wait_for_port,
    DummyTCPServer,
};
use crate::test::{get_port_number, PortsAllocation, LOCALHOST_IP};

const VALID_TOKEN: &str = "AvalidTOKEN";
const NUM_INC: i32 = 5;

fn port(index: u16) -> u16 {
    get_port_number(PortsAllocation::ValidWithTokenAuthMultiplePorts, index)
}

#[tokio::test()]
async fn test() {
    let _ = env_logger::builder().is_test(true).try_init();

    // Start internal services
    let local_server_1 = DummyTCPServer::start(port(1)).await;
    tokio::spawn(async move {
        local_server_1.loop_conn_square_operations().await;
    });

    let local_server_2 = DummyTCPServer::start(port(3)).await;
    tokio::spawn(async move {
        local_server_2.loop_next_conn_add_operations(NUM_INC).await;
    });

    let local_set = task::LocalSet::new();
    local_set
        .run_until(async move {
            wait_for_port(port(1)).await;

            // Start server relay
            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
                tokens: vec![VALID_TOKEN.to_string()],
                tokens_file: None,
                ports: vec![port(1), port(3)],
                upstream_server: "127.0.0.1".to_string(),
                listen_address: format!("127.0.0.1:{}", port(0)),
                increment_ports: 1,
                tls_cert: None,
                tls_key: None,
                tls_client_auth_root_cert: None,
                tls_revocation_list: None,
            }));
            wait_for_port(port(0)).await;

            // Start client relay
            task::spawn(crate::tcp_relay_client::run_app(ClientConfig {
                token: Some(VALID_TOKEN.to_string()),
                relay_url: format!("http://{}:{}", LOCALHOST_IP, port(0)),
                listen_address: LOCALHOST_IP.to_string(),
                root_certificate: None,
                ..Default::default()
            }));
            wait_for_port(port(2)).await;

            dummy_tcp_client_square_root_requests(port(2), 10).await;
            dummy_tcp_client_additions_requests(port(4), NUM_INC, 10).await;
        })
        .await;
}