use std::collections::HashMap;
use std::str::FromStr;
use crate::Exception;

/// HTTP tool, which is mainly used as a reference for using reqwest
pub struct HttpUtil;

impl HttpUtil {

    /// 简单get请求
    pub async fn get(url: &str) -> Result<String, Exception> {
        let result = reqwest::get(url)
            .await?
            .text()
            .await?;
        Ok(result)
    }

    /// 阻塞的get请求
    pub fn blocking_get(url: &str) -> Result<String, Exception>{
        let response = reqwest::blocking::get(url)?;
        let result = response.text()?;
        Ok(result)
    }

    /// 简单post请求
    pub async fn post(url: &str, body: String) -> Result<String, Exception> {
        let client = reqwest::Client::new();
        let result = client.post(url)
            .body(body)
            .send()
            .await?
            .text()
            .await?;
        Ok(result)
    }

    // 阻塞的post请求
    pub fn blocking_post(url: &str, body: String) -> Result<String, Exception> {
        let client = reqwest::blocking::Client::new();
        let result = client.post(url)
            .body(body)
            .send()?
            .text()?;
        Ok(result)
    }

    pub async fn post_json(url: &str, body: HashMap<&str, &str>) -> Result<String, Exception> {
        let client = reqwest::Client::new();
        let result = client.post(url)
            .json(&body)
            .send()
            .await?
            .text()
            .await?;
        Ok(result)
    }

    pub async fn post_form(url: &str, form: Vec<(&str, &str)>) -> Result<String, Exception> {
        let client = reqwest::Client::new();
        let result = client.post(url)
            .form(&form)
            .send()
            .await?
            .text()
            .await?;
        Ok(result)
    }

    pub async fn request(method: reqwest::Method, url: &str, headers: Vec<(&str, &str)>, body: &str) -> Result<String, Exception> { 
        let client = reqwest::Client::new();
        let headers = headers.iter()
            .map(|(k, v)| (reqwest::header::HeaderName::from_str(k).unwrap() , reqwest::header::HeaderValue::from_str(v).unwrap()))
            .collect::<reqwest::header::HeaderMap>();
        let result = client.request(method, url)
            .headers(headers)
            .body(body.to_string())
            .send()
            .await?
            .text()
            .await?;
        Ok(result)
    }

    pub async fn post_bytes(url: &str, data: Vec<u8>) -> Result<(), Exception>{
        let client = reqwest::Client::new();
        let res = client.put(url)
            .header("Content-Type", "image/jpeg")
            .header("Content-Length", data.len())
            .body(data)
            .send()
            .await;

        let res = match res {
            Ok(response) => response,
            Err(e) => return Err(Exception::ReqwestErr(e)),
        };
        let status = res.status();
        println!("status = {}, {}", status, res.text_with_charset("utf-8").await?);
        Ok(())
    }

}

#[cfg(test)]
mod tests {

    use super::*;

    #[tokio::test]
    async fn it_works() -> Result<(), Exception>{
        let result = HttpUtil::get("https://www.baidu.com").await?;
        println!("{}", result);
        Ok(())
    }

}