use std::env;
use std::fs;
use std::io::{self, Write};
use std::net;

fn main() -> io::Result<()> {
    let addr = env::var("H8R_ADDR").unwrap_or("127.0.0.1:17321".to_string());

    run_server(addr)?;

    Ok(())
}

fn run_server(addr: String) -> Result<(), io::Error> {
    let listener = net::TcpListener::bind(&addr).unwrap();

    eprintln!("h8r: listening at {}", addr);

    for stream in listener.incoming() {
        let mut stream = stream.unwrap();
        handle_conn(&mut stream)?;
        stream.shutdown(net::Shutdown::Both)?;
    }

    Ok(())
}

fn handle_conn(outstream: &mut net::TcpStream) -> io::Result<()> {
    eprintln!("h8r: attempting to respond");

    let relpath = "index.txt";

    let index_res = fs::read_to_string(relpath);
    if index_res.is_ok() {
        let head = concat!["HTTP/1.1 200 OK\r\n", "content-type: text/plain\r\n"];
        let index = index_res.unwrap();
        let index_len = index.len();
        outstream.write_all(head.as_bytes()).unwrap();
        outstream
            .write_all(format!("content-length: {}\r\n", index_len).as_bytes())
            .unwrap();
        outstream.write_all("\r\n".as_bytes()).unwrap();
        outstream.write_all(index.as_bytes()).unwrap();
    } else {
        let response = concat![
            "HTTP/1.1 404 Not Found\r\n",
            "content-type: text/plain\r\n",
            "\r\n",
            "oh no\n",
        ];

        outstream.write_all(response.as_bytes()).unwrap();
    }

    outstream.flush()?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn handle_conn_writes_response() {
        let test_addr = "127.0.0.1:27321".to_string();

        let _l = net::TcpListener::bind(&test_addr);
        let mut stream = match net::TcpStream::connect(&("127.0.0.1", 27321)) {
            Ok(s) => s,
            Err(e) => panic!("cannot connect to test server: {}", e),
        };

        let _ = handle_conn(&mut stream);
    }
}
