#![cfg(all(feature = "local-http", feature = "server"))]

use std::time::Duration;

use tokio::{
    io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader},
    net::TcpStream,
    time,
};

use shadowsocks_service::{
    config::{Config, ConfigType},
    run_local, run_server,
};

#[tokio::test]
async fn http_proxy() {
    let _ = env_logger::try_init();

    let local_config = Config::load_from_str(
        r#"{
            "locals": [
                {
                    "local_port": 5110,
                    "local_address": "127.0.0.1",
                    "protocol": "http"
                }
            ],
            "server": "127.0.0.1",
            "server_port": 5120,
            "password": "password",
            "method": "aes-256-gcm"
        }"#,
        ConfigType::Local,
    )
    .unwrap();

    let server_config = Config::load_from_str(
        r#"{
            "server": "127.0.0.1",
            "server_port": 5120,
            "password": "password",
            "method": "aes-256-gcm"
        }"#,
        ConfigType::Server,
    )
    .unwrap();

    tokio::spawn(run_local(local_config));
    tokio::spawn(run_server(server_config));

    time::sleep(Duration::from_secs(1)).await;

    {
        let mut c = TcpStream::connect("127.0.0.1:5110").await.unwrap();
        c.write_all(b"GET http://www.example.com/ HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n")
            .await
            .unwrap();
        c.flush().await.unwrap();

        // Proxy should close connection actively because HTTP/1.0 use short connection by default
        let mut buf = Vec::new();
        c.read_to_end(&mut buf).await.unwrap();

        assert!(buf.starts_with(b"HTTP/1.0 200 OK\r\n"));
    }

    {
        let mut c = TcpStream::connect("127.0.0.1:5110").await.unwrap();
        c.write_all(b"CONNECT http://www.example.com/ HTTP/1.0\r\n\r\n")
            .await
            .unwrap();
        c.flush().await.unwrap();

        c.write_all(b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n")
            .await
            .unwrap();
        c.flush().await.unwrap();

        let mut r = BufReader::new(c);

        let mut buf = Vec::new();
        r.read_until(b'\n', &mut buf).await.unwrap();

        assert!(buf.starts_with(b"HTTP/1.0 200 OK\r\n"));
    }
}
