use http::Method;
use http::StatusCode;
use raspa::request::{ParameterType, Request, RequestBase};
use raspa::response::ResponseBase;
use raspa::selector::{Selector, SelectorBase};
use serde_json::Value;
// use std::collections::HashMap;

#[test]
fn plain_text_selector() {
    let html = "
<html>
  <body>
    <h1>hello world</h1>
    <p id='text'>good bye</p>
    <a>simple text</a>
  </body>
</html>
";
    let sel = Selector::from_html(html);
    assert_eq!(sel.css("h1")[0].html(), "<h1>hello world</h1>");
    assert_eq!(sel.css("#text")[0].content(), "good bye");
    assert_eq!(sel.css_once("body > a").unwrap().content(), "simple text");
}

#[test]
fn simple_request() {
    let req: Request = RequestBase::new("https://httpbin.org/").unwrap();
    let resp = req.launch();
    assert_eq!(resp.status_code, StatusCode::OK);
    assert!(resp.css("h2")[0].html().contains("httpbin.org"));
}

#[test]
fn complex_selectors() {
    let html = "
<html>
  <body>
    <p id='text'>good bye</p>
    <a href='http://google.com'>simple text</a>
    <ul>
        <li class='item' id='item-1'>1</li>
        <li class='item' id='item-2'>2</li>
        <li class='item' id='item-3'>3</li>
    </ul>
    <div>
        <a href='#'>non link</a>
        <a href='http://localhost'>link</a>
        <a href='#'>non link</a>
    </div>
  </body>
</html>
";
    let sel = Selector::from_html(html);
    assert_eq!(sel.css_once("p").unwrap().attr("id").unwrap(), "text");
    assert_eq!(sel.css("a")[0].attr("href").unwrap(), "http://google.com");
    for node in sel.css("ul li").iter() {
        let text = node.content();
        assert_eq!(node.attr("class").unwrap(), "item");
        assert!(node.attr("id").unwrap().contains(&text));
    }

    let div = sel.css_once("div").unwrap();
    for node in div.css("a").iter() {
        if node.attr("href").unwrap() == "#" {
            assert_eq!(node.content(), "non link");
        } else {
            assert_eq!(node.content(), "link");
        }
    }
    assert!(sel.css_once("h1").is_none());
}

#[test]
fn xpath_test() {
    let html = "
<html>
  <body>
    <p id='text'>good bye</p>
    <a href='http://google.com'>simple text</a>
    <div class='container'>
        <a href='#'>first text</a>
        <a href='http://localhost'>link</a>
        <a href='#'>non link</a>
    </div>
  </body>
</html>
";
    let sel = Selector::from_html(html);
    assert_eq!(
        sel.xpath_once("//div/a[1]").unwrap().content(),
        "first text"
    );
    assert_eq!(sel.xpath("//*[@id='text']")[0].content(), "good bye");
    assert_eq!(
        sel.xpath("//a[contains(@href, 'localhost')]")[0]
            .attr("href")
            .unwrap(),
        "http://localhost"
    );
    assert_eq!(
        sel.xpath_once("//div[@class='container']/a[3]")
            .unwrap()
            .content(),
        "non link"
    );
}

#[test]
fn simple_json_test() {
    let req = Request::new("https://httpbin.org/json").unwrap();
    let resp: Value = req.launch().to_json().expect("cannot parse json");

    assert_eq!(resp["slideshow"]["title"], "Sample Slide Show");
}

#[test]
fn simple_post_request() {
    let resp: Value = Request::new("https://httpbin.org/post")
        .unwrap()
        .method(Method::POST)
        .launch()
        .to_json()
        .expect("cannot parse json");
    assert_eq!(resp["url"].as_str().unwrap(), "https://httpbin.org/post");
}

#[test]
fn parameter_get_request() {
    use ParameterType::*;

    let mut req = Request::new("https://httpbin.org/get").unwrap().add_params(
        [
            ("param_str", Text("hello".to_string())),
            ("param_num", Number(42)),
            ("param_bool", Boolean(true)),
        ]
        .to_vec(),
    );
    req.add_param("param_float", 3.14159);
    let resp: Value = req.launch().to_json().expect("cannot parse json");
    println!("{}", resp);

    assert_eq!(resp["args"]["param_str"].as_str(), Some("hello"));
    assert_eq!(resp["args"]["param_num"].as_str(), Some("42"));
    assert_eq!(resp["args"]["param_bool"].as_str(), Some("true"));
    assert_eq!(resp["args"]["param_float"].as_str(), Some("3.14159"));
}

#[test]
fn default_user_agent() {
    let resp: Value = Request::new("https://httpbin.org/get")
        .unwrap()
        .launch()
        .to_json()
        .expect("Weird JSON parsed fail");
    assert_eq!(
        resp["headers"]["User-Agent"].as_str().unwrap(),
        std::env::var("DEFAULT_USER_AGENT").unwrap()
    );
}

#[test]
fn custom_user_agent() {
    let resp: Value = Request::new("https://httpbin.org/get")
        .unwrap()
        .set_user_agent("test user agent")
        .launch()
        .to_json()
        .expect("Weird JSON parsed fail");
    assert_eq!(
        resp["headers"]["User-Agent"].as_str(),
        Some("test user agent")
    );
}

#[test]
fn simple_cookie_test() {
    let mut req = Request::new("https://httpbin.org/cookies").unwrap();
    req.add_cookie("test_cookie", "100");

    let resp: Value = req.launch().to_json().expect("Weird JSON parsed fail");
    assert_eq!(resp["cookies"]["test_cookie"].as_str(), Some("100"));
}

#[test]
fn multiple_cookies_test() {
    let resp: Value = Request::new("https://httpbin.org/cookies")
        .unwrap()
        .add_cookies(vec![
            ("cookie_1", 100),
            ("cookie_2", 200),
            ("cookie_3", 300),
        ])
        .launch()
        .to_json()
        .expect("Weird JSON parsed fail");

    assert_eq!(resp["cookies"]["cookie_1"].as_str(), Some("100"));
    assert_eq!(resp["cookies"]["cookie_2"].as_str(), Some("200"));
    assert_eq!(resp["cookies"]["cookie_3"].as_str(), Some("300"));
}