#![cfg(feature = "runtime")]
extern crate pretty_env_logger;

use std::thread;
use std::time::Duration;

use futures::Async;
use futures::future::poll_fn;
use tokio::executor::thread_pool::{Builder as ThreadPoolBuilder};

use mock::MockConnector;
use super::*;

#[test]
fn retryable_request() {
    let _ = pretty_env_logger::try_init();

    let executor = ThreadPoolBuilder::new().pool_size(1).build();
    let mut connector = MockConnector::new();

    let sock1 = connector.mock("http://mock.local");
    let sock2 = connector.mock("http://mock.local");

    let client = Client::builder()
        .executor(executor.sender().clone())
        .build::<_, ::Body>(connector);

    client.pool.no_timer();

    {

        let req = Request::builder()
            .uri("http://mock.local/a")
            .body(Default::default())
            .unwrap();
        let res1 = client.request(req);
        let srv1 = poll_fn(|| {
            try_ready!(sock1.read(&mut [0u8; 512]));
            try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
            Ok(Async::Ready(()))
        }).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e));
        res1.join(srv1).wait().expect("res1");
    }
    drop(sock1);

    let req = Request::builder()
        .uri("http://mock.local/b")
        .body(Default::default())
        .unwrap();
    let res2 = client.request(req)
        .map(|res| {
            assert_eq!(res.status().as_u16(), 222);
        });
    let srv2 = poll_fn(|| {
        try_ready!(sock2.read(&mut [0u8; 512]));
        try_ready!(sock2.write(b"HTTP/1.1 222 OK\r\nContent-Length: 0\r\n\r\n"));
        Ok(Async::Ready(()))
    }).map_err(|e: ::std::io::Error| panic!("srv2 poll_fn error: {}", e));

    res2.join(srv2).wait().expect("res2");
}

#[test]
fn conn_reset_after_write() {
    let _ = pretty_env_logger::try_init();

    let executor = ThreadPoolBuilder::new().pool_size(1).build();
    let mut connector = MockConnector::new();

    let sock1 = connector.mock("http://mock.local");

    let client = Client::builder()
        .executor(executor.sender().clone())
        .build::<_, ::Body>(connector);

    client.pool.no_timer();

    {
        let req = Request::builder()
            .uri("http://mock.local/a")
            //TODO: remove this header when auto lengths are fixed
            .header("content-length", "0")
            .body(Default::default())
            .unwrap();
        let res1 = client.request(req);
        let srv1 = poll_fn(|| {
            try_ready!(sock1.read(&mut [0u8; 512]));
            try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
            Ok(Async::Ready(()))
        }).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e));
        res1.join(srv1).wait().expect("res1");
    }

    // sleep to allow some time for the connection to return to the pool
    thread::sleep(Duration::from_millis(10));

    let req = Request::builder()
        .uri("http://mock.local/a")
        .body(Default::default())
        .unwrap();
    let res2 = client.request(req);
    let mut sock1 = Some(sock1);
    let srv2 = poll_fn(|| {
        // We purposefully keep the socket open until the client
        // has written the second request, and THEN disconnect.
        //
        // Not because we expect servers to be jerks, but to trigger
        // state where we write on an assumedly good connetion, and
        // only reset the close AFTER we wrote bytes.
        try_ready!(sock1.as_mut().unwrap().read(&mut [0u8; 512]));
        sock1.take();
        Ok(Async::Ready(()))
    }).map_err(|e: ::std::io::Error| panic!("srv2 poll_fn error: {}", e));
    let err = res2.join(srv2).wait().expect_err("res2");
    match err.kind() {
        &::error::Kind::Incomplete => (),
        other => panic!("expected Incomplete, found {:?}", other)
    }
}
