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::wait_for_port;
use crate::test::pki::Pki;
use crate::test::test_files_utils::create_temp_file_with_random_content;
use crate::test::{get_port_number, PortsAllocation, BAD_PATH, LOCALHOST_IP};

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

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

    let pki = Pki::load();
    let random_file = create_temp_file_with_random_content();

    crate::tcp_relay_client::run_app(ClientConfig {
        token: Some("token".to_string()),
        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
        listen_address: LOCALHOST_IP.to_string(),
        tls_cert: Some(random_file.to_string_lossy().to_string()),
        tls_key: Some(pki.valid_client_key.file_path()),
        ..Default::default()
    })
    .await
    .unwrap_err();
}

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

    let pki = Pki::load();
    let random_file = create_temp_file_with_random_content();

    crate::tcp_relay_client::run_app(ClientConfig {
        token: Some("token".to_string()),
        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
        listen_address: LOCALHOST_IP.to_string(),
        tls_cert: Some(pki.valid_client_crt.file_path()),
        tls_key: Some(random_file.to_string_lossy().to_string()),
        ..Default::default()
    })
    .await
    .unwrap_err();
}

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

    let pki = Pki::load();

    crate::tcp_relay_client::run_app(ClientConfig {
        token: Some("token".to_string()),
        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
        listen_address: LOCALHOST_IP.to_string(),
        tls_cert: Some(pki.root_ca_crl.file_path()),
        tls_key: Some(pki.valid_client_key.file_path()),
        ..Default::default()
    })
    .await
    .unwrap_err();
}

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

    let pki = Pki::load();

    crate::tcp_relay_client::run_app(ClientConfig {
        token: Some("token".to_string()),
        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
        listen_address: LOCALHOST_IP.to_string(),
        tls_cert: Some(pki.valid_client_crt.file_path()),
        tls_key: Some(pki.root_ca_crl.file_path()),
        ..Default::default()
    })
    .await
    .unwrap_err();
}

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

    let pki = Pki::load();

    crate::tcp_relay_client::run_app(ClientConfig {
        token: Some("token".to_string()),
        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
        listen_address: LOCALHOST_IP.to_string(),
        tls_cert: Some(BAD_PATH.to_string()),
        tls_key: Some(pki.valid_client_key.file_path()),
        ..Default::default()
    })
    .await
    .unwrap_err();
}

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

    let pki = Pki::load();

    crate::tcp_relay_client::run_app(ClientConfig {
        token: Some("token".to_string()),
        relay_url: format!("https://{}:{}", LOCALHOST_IP, port(0)),
        listen_address: LOCALHOST_IP.to_string(),
        tls_cert: Some(pki.valid_client_crt.file_path()),
        tls_key: Some(BAD_PATH.to_string()),
        ..Default::default()
    })
    .await
    .unwrap_err();
}

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

    let pki = Pki::load();
    let local_set = task::LocalSet::new();
    local_set
        .run_until(async move {
            // Start server relay
            task::spawn_local(crate::tcp_relay_server::run_app(ServerConfig {
                tokens: vec!["dqsd".to_string()],
                tokens_file: None,
                ports: vec![port(1)],
                upstream_server: "127.0.0.1".to_string(),
                listen_address: format!("127.0.0.1:{}", port(0)),
                increment_ports: 1,
                tls_cert: Some(pki.localhost_crt.file_path()),
                tls_key: Some(pki.localhost_key.file_path()),
                tls_client_auth_root_cert: Some(pki.root_ca_crt.file_path()),
                tls_revocation_list: None,
            }));
            wait_for_port(port(0)).await;

            crate::tcp_relay_client::run_app(ClientConfig {
                token: Some("token".to_string()),
                relay_url: format!("https://localhost:{}", port(0)),
                listen_address: LOCALHOST_IP.to_string(),
                tls_cert: Some(pki.valid_client_crt.file_path()),
                tls_key: Some(pki.revoked_client_key.file_path()),
                root_certificate: Some(pki.root_ca_crt.file_path()),
                ..Default::default()
            })
            .await
            .unwrap_err();
        })
        .await;
}