use std::io::{Read, Write};
use std::net::TcpListener;
use std::thread;

use rpki::fetch::http::{BlockingHttpFetcher, HttpFetcherConfig};
use rpki::sync::rrdp::Fetcher;

fn start_one_shot_http_server() -> (String, thread::JoinHandle<()>) {
    let listener = TcpListener::bind("127.0.0.1:0").expect("bind");
    let addr = listener.local_addr().expect("local addr");
    let addr_s = addr.to_string();

    let h = thread::spawn(move || {
        for _ in 0..3 {
            let (mut sock, _peer) = listener.accept().expect("accept");
            let mut buf = [0u8; 4096];
            let n = sock.read(&mut buf).expect("read request");
            let req = String::from_utf8_lossy(&buf[..n]);
            let path = req
                .lines()
                .next()
                .and_then(|l| l.split_whitespace().nth(1))
                .unwrap_or("/");

            let (status, body) = if path == "/ok" {
                ("200 OK", b"ok".as_slice())
            } else {
                ("404 Not Found", b"nope".as_slice())
            };

            let resp = format!(
                "HTTP/1.1 {status}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
                body.len()
            );
            sock.write_all(resp.as_bytes()).expect("write headers");
            sock.write_all(body).expect("write body");
        }
    });

    (addr_s, h)
}

#[test]
fn http_fetcher_handles_success_and_status_errors() {
    let (addr, h) = start_one_shot_http_server();

    let fetcher = BlockingHttpFetcher::new(HttpFetcherConfig::default()).expect("build fetcher");

    let ok = fetcher
        .fetch_bytes(&format!("http://{addr}/ok"))
        .expect("fetch ok");
    assert_eq!(ok, b"ok");

    // Also exercise the trait method wrapper.
    let ok2 = Fetcher::fetch(&fetcher, &format!("http://{addr}/ok")).expect("fetch via trait");
    assert_eq!(ok2, b"ok");

    let err = fetcher
        .fetch_bytes(&format!("http://{addr}/missing"))
        .unwrap_err();
    assert!(err.contains("404"), "error should mention 404, got: {err}");

    h.join().expect("server thread join");
}
