use http_body_util::{BodyExt, Full};
use hyper::body::Bytes;
use hyper::header::{CONTENT_TYPE, HOST, HeaderValue};
use hyper_rustls::HttpsConnectorBuilder;
use hyper_util::client::legacy::Client;
use hyper_util::rt::TokioExecutor;

async fn run_request(with_host: bool) -> (String, Option<hyper::StatusCode>, Option<String>) {
    let connector = HttpsConnectorBuilder::new()
        .with_webpki_roots()
        .https_or_http()
        .enable_http1()
        .enable_http2()
        .build();
    let client: Client<_, Full<Bytes>> =
        Client::builder(TokioExecutor::new()).build(connector);

    let body_bytes = Bytes::from_static(b"grant_type=authorization_code&code=FAKE_CODE_FOR_TEST");
    let mut builder = hyper::Request::builder()
        .method("POST")
        .uri("https://oauth2.googleapis.com/token")
        .header(
            CONTENT_TYPE,
            HeaderValue::from_static("application/x-www-form-urlencoded"),
        );
    if with_host {
        builder = builder.header(
            HOST,
            HeaderValue::from_static("oauth2.googleapis.com"),
        );
    }
    let req = builder.body(Full::new(body_bytes)).unwrap();

    let label = if with_host { "with-host" } else { "no-host" };
    match client.request(req).await {
        Ok(resp) => {
            let status = resp.status();
            let body = resp.into_body().collect().await.ok().map(|c| {
                String::from_utf8_lossy(&c.to_bytes()).chars().take(400).collect()
            });
            (label.to_string(), Some(status), body)
        }
        Err(err) => {
            let txt = format!("{err:?}");
            (label.to_string(), None, Some(txt))
        }
    }
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[ignore = "hits real oauth2.googleapis.com; run manually with --ignored"]
async fn host_header_with_h2_google() {
    let _ = tracing_subscriber::fmt()
        .with_max_level(tracing::Level::DEBUG)
        .with_test_writer()
        .try_init();
    let _ = rustls::crypto::ring::default_provider().install_default();

    println!("=== Test A: POST to oauth2.googleapis.com/token WITH host header ===");
    let (label_a, status_a, body_a) = run_request(true).await;
    println!("[{label_a}] status={status_a:?}");
    println!("[{label_a}] body/err={body_a:?}");

    println!();
    println!("=== Test B: POST to oauth2.googleapis.com/token WITHOUT host header ===");
    let (label_b, status_b, body_b) = run_request(false).await;
    println!("[{label_b}] status={status_b:?}");
    println!("[{label_b}] body/err={body_b:?}");

    println!();
    println!("== SUMMARY ==");
    println!("  with-host: status={status_a:?}");
    println!("  no-host  : status={status_b:?}");
}
