///
#[allow(warnings)]
#[cfg(feature = "http")]
pub mod http {
    use std::ptr::replace;

    pub use reqwest::blocking::Client;
    pub use reqwest::header::HeaderMap;
    pub use reqwest::header::HeaderName;

    use crate::hashmap;
    use crate::DebugPrint;
    use crate::DynError;
    use crate::Str;
    ///```ignore
    /// let h_map = headers![
    ///     "Host"=>"www.gitlink.org.cn",
    ///     "Content-Type"=> "application/json",
    ///     "Origin"=> "https://www.gitlink.org.cn",
    ///     "Referer"=> "https://www.gitlink.org.cn/projects/mirror/new"
    /// ];
    /// ```
    #[macro_export]
    macro_rules! headers {
        ($($key:expr => $val:expr),*) => {
            {
            let mut headers = $crate::ctf::HeaderMap::new();
            $(
                let header_name = $crate::ctf::HeaderName::from_lowercase($key.to_lowercase().as_bytes()).unwrap();
                headers.insert(header_name,$val.parse().unwrap());
            )*
            headers
            }
        };
    }
    ///ToHeader
    ///```ignore
    /// let h_map = include_str!("./demo.m").to_headers();
    /// ```
    pub trait ToHeader {
        ///ToHeader
        ///```ignore
        /// let h_map = include_str!("./demo.m").to_headers();
        /// ```
        fn to_headers(&self) -> HeaderMap;
        fn to_url(&self) -> Option<String>;
        ///url_and_headers
        /// ```ignore
        /// async fn get_session_id(path:&str) -> doe::DynError<String> {
        ///     use doe::http::async_client_builder;
        ///     use doe::http::ToHeader;
        ///     use doe::*;
        ///     let (url,headers) = r#"
        ///     GET [path] HTTP/1.1
        ///     Host: 10.124.111.122:8080
        ///     User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0
        ///     Cookie: JSESSIONID=FB234F334207384BDC07C70C1065231B
        ///     "#
        ///     .replace("[path]", path)
        ///     .url_and_headers();
        ///     let client = async_client_builder()
        ///         .await
        ///         .danger_accept_invalid_certs(true)
        ///         .no_proxy()
        ///         .default_headers(headers)
        ///         .build()
        ///         .unwrap();
        ///     let res = client
        ///         .get(url.unwrap().push_front("http://"))
        ///         .send()
        ///         .await?;
        ///     let html = res.text().await?;
        ///     Ok(html)
        /// }
        /// ```
        /// 
        fn url_and_headers(&self)->(Option<String>,HeaderMap);
    }
    
    impl<T: ToString> ToHeader for T {
        fn url_and_headers(&self) ->(Option<String>,HeaderMap){
            let header_str = self.to_string();
            (header_str.to_url(),header_str.to_headers())
        }
        fn to_url(&self) -> Option<String> {
            let header_str = self.to_string();
            let mut header_str_split = header_str.split("\n");
            let mut hash_map: std::collections::HashMap<String, String> = hashmap!();
            header_str_split
                .clone()
                .filter(|s| !s.is_empty())
                .map(|s| {
                    s.to_string()
                        .trim()
                        .split(":")
                        .filter(|s| !s.is_empty())
                        .map(|s| s.to_string())
                        .collect()
                })
                .filter(|s: &Vec<String>| s.to_owned().len() > 1)
                .map(|s| {
                    let header_name = s.first().expect("get header_name error").to_string();
                    let header_val = &s[1..].join(":").to_string().replace("\"", "'");
                    vec![header_name, header_val.to_string()]
                })
                .collect::<Vec<Vec<_>>>()
                .iter()
                .for_each(|s| {
                    let header_name = s
                        .first()
                        .expect("get header_name error")
                        .to_string()
                        .to_ascii_lowercase();
                    let header_val = s.get(1).expect("get header_val error").to_string();
                    let _ = hash_map
                        .insert(header_name, header_val);
                });

            if let Some(fist_line) = header_str_split.filter(|s|!s.is_empty()).next() {
                if let Some(host) = hash_map.get("host") {
                    let path = &fist_line.trim().split(" ").collect::<Vec<_>>()[1].trim();
                    let url = host.to_string().push_back(path.to_string());
                    Some(url.trim().to_string())
                } else {
                    None
                }
            } else {
                None
            }
        }
        fn to_headers(&self) -> HeaderMap {
            let header_str = self.to_string();
            let header_str_split = header_str.split("\n");
            let head_vec = header_str_split
                .filter(|s| !s.is_empty())
                .map(|s| {
                    s.to_string()
                        .trim()
                        .split(":")
                        .filter(|s| !s.is_empty())
                        .map(|s| s.to_string())
                        .collect()
                })
                .filter(|s: &Vec<String>| s.to_owned().len() > 1)
                .map(|s| {
                    let header_name = s.first().expect("get header_name error").to_string();
                    let header_val = &s[1..].join(":").to_string().replace("\"", "'");
                    vec![header_name, header_val.to_string()]
                })
                .collect::<Vec<Vec<_>>>();
            let mut headers = HeaderMap::new();
            for kv in head_vec.iter() {
                let mut kv = kv.iter();
                let key = kv.next().unwrap();
                let val = kv.next().unwrap();
                let header_name =
                    HeaderName::from_lowercase(key.to_lowercase().as_bytes()).unwrap();
                headers.insert(header_name, val.parse().unwrap());
            }
            headers
        }
    }

    pub trait ClientAsyncSend {
        async fn async_post_bytes(&self, url: impl ToString, body: &[u8]) -> Vec<u8>;
        async fn async_get_bytes(&self, url: impl ToString) -> Vec<u8>;
    }
    impl ClientAsyncSend for reqwest::Client {
        async fn async_post_bytes(&self, url: impl ToString, body: &[u8]) -> Vec<u8> {
            let mut resp = self
                .post(url.to_string())
                .body(body.to_vec())
                .send()
                .await
                .unwrap();

            resp.bytes().await.unwrap().to_vec()
        }
        async fn async_get_bytes(&self, url: impl ToString) -> Vec<u8> {
            let mut resp = self.get(url.to_string()).send().await.unwrap();
            resp.bytes().await.unwrap().to_vec()
        }
    }

    pub trait ClientSyncSend {
        ///post_bytes
        /// ```ignore
        /// use doe::json::*;
        /// let mut headers = HeaderMap::new();
        /// headers.insert("Host", "www.gitlink.org.cn".parse().unwrap());
        /// headers.insert("Content-Type", "application/json".parse().unwrap());
        /// headers.insert("Origin", "https://www.gitlink.org.cn".parse().unwrap());
        /// headers.insert("Referer", "https://www.gitlink.org.cn/projects/mirror/new".parse().unwrap());
        /// let client = client_with_headers(headers);
        /// let data = json!({
        ///     "user_id": 89579,
        ///     "auth_password": "dW5kZWZpbmVk",
        ///     "blockchain": false,
        ///     "blockchain_token_all": 10000,
        ///     "blockchain_init_token": null
        /// });
        /// let json_bytes = data.as_bytes();
        /// let response = client.sync_post_bytes("http://www.gitlink.org.cn/api/projects/migrate.json",&json_bytes);
        /// ```
        fn sync_post_bytes(&self, url: impl ToString, body: &[u8]) -> Vec<u8>;
        // async fn async_post_bytes(&self, url: impl ToString, body: &[u8]) -> Option<Vec<u8>>;
        ///post_bytes
        /// ```ignore
        /// let mut headers = HeaderMap::new();
        /// headers.insert("Host", "www.gitlink.org.cn".parse().unwrap());
        /// headers.insert("Content-Type", "application/json".parse().unwrap());
        /// headers.insert("Origin", "https://www.gitlink.org.cn".parse().unwrap());
        /// headers.insert("Referer", "https://www.gitlink.org.cn/projects/mirror/new".parse().unwrap());
        /// let client = client_with_headers(headers);
        /// let response = client.sync_get_bytes("http://www.gitlink.org.cn/api/projects/migrate.json");
        fn sync_get_bytes(&self, url: impl ToString) -> Vec<u8>;
    }

    impl ClientSyncSend for reqwest::blocking::Client {
        fn sync_post_bytes(&self, url: impl ToString, body: &[u8]) -> Vec<u8> {
            let mut resp = self
                .post(url.to_string())
                .body(body.to_vec())
                .send()
                .unwrap();

            let mut body = vec![];
            resp.copy_to(&mut body).unwrap();
            body
        }
        fn sync_get_bytes(&self, url: impl ToString) -> Vec<u8> {
            let mut resp = self.get(url.to_string()).send().unwrap();
            let mut body = vec![];
            resp.copy_to(&mut body).unwrap();
            body
        }
    }
    pub async fn async_client() -> reqwest::Client {
        let client_builder = reqwest::ClientBuilder::new();
        let client = client_builder.build().unwrap();
        client
    }
    pub fn sync_client() -> reqwest::blocking::Client {
        let client_builder = reqwest::blocking::ClientBuilder::new();
        let client = client_builder.build().unwrap();
        client
    }
    pub async fn async_client_with_headers(headers: reqwest::header::HeaderMap) -> reqwest::Client {
        let client_builder = reqwest::ClientBuilder::new();
        let client = client_builder.default_headers(headers).build().unwrap();
        client
    }
    pub async fn async_client_builder() -> reqwest::ClientBuilder {
        reqwest::ClientBuilder::new()
    }
    pub use reqwest::Method;
    pub fn sync_client_with_headers(
        headers: reqwest::header::HeaderMap,
    ) -> reqwest::blocking::Client {
        let client_builder = reqwest::blocking::ClientBuilder::new();
        let client = client_builder.default_headers(headers).build().unwrap();
        client
    }
    pub async fn sync_client_builder() -> reqwest::blocking::ClientBuilder {
        reqwest::blocking::ClientBuilder::new()
    }
}





#[cfg(feature = "http")]
pub use http::*;
