use crate::{IResult, JsonV};
use isahc::prelude::Configurable;
// use isahc::prelude::Configurable;
// use isahc::prelude::*;
use isahc::{Body, ReadResponseExt};
use serde::de::DeserializeOwned;
use std::collections::HashMap;
use std::path::Path;
// use std::time::Duration;

#[allow(dead_code)]

fn get_haeders<'a>() -> HashMap<&'a str, &'a str> {
    let mut haeders = HashMap::new();
    haeders.insert("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0");
    haeders.insert("Accept", "text/html,application/xhtml+xml,application/xml;application/json;q=0.9,image/webp,*/*;q=0.8");
    haeders.insert("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
    // haeders.insert("Connection", "Close".parse()?);
    haeders.insert("Cache-Control", "no-cache");
    haeders
}

fn get_json_haeders<'a>() -> HashMap<&'a str, &'a str> {
    let mut haeders = HashMap::new();
    haeders.insert("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0");
    haeders.insert("Accept", "text/html,application/xhtml+xml,application/xml;application/json;q=0.9,image/webp,*/*;q=0.8");
    haeders.insert("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
    haeders.insert("Content-Type", "application/json;charset=utf-8");
    // haeders.insert("Connection", "Close".parse()?);
    haeders.insert("Cache-Control", "no-cache");
    haeders
}

#[cfg(feature = "req_timeout_30")]
const TIME_OUT: u64 = 30;
#[cfg(feature = "req_timeout_30")]
const TIME_OUT_CONNECT: u64 = 5;

#[cfg(feature = "req_timeout_60")]
const TIME_OUT: u64 = 60;
#[cfg(feature = "req_timeout_60")]
const TIME_OUT_CONNECT: u64 = 10;

#[cfg(all(feature = "req_timeout_30", feature = "req_timeout_60"))]
compile_error!("feature 'req_timeout_30' and feature 'req_timeout_60' cannot be enabled at the same time");

pub fn post_json<T: DeserializeOwned>(url: String, json_v: JsonV) -> IResult<T> {
    #[allow(unused_mut)]
    let mut req = isahc::HttpClientBuilder::new().default_headers(get_json_haeders());

    #[cfg(any(feature = "req_timeout_30", feature = "req_timeout_60"))]
    {
        req = req.connect_timeout(std::time::Duration::from_secs(TIME_OUT_CONNECT)).timeout(std::time::Duration::from_secs(TIME_OUT));
    }

    let r = req.build()?.post(url, json_v.to_string())?.json::<T>()?;
    Ok(r)
}

/// 使用cookie进行请求post
pub fn post_with_header(url: String, mut headers: HashMap<String, String>, body: impl Into<Body> + std::fmt::Debug) -> IResult<JsonV> {
    let mut headers_default = get_json_haeders();
    for (k, v) in headers.iter_mut() {
        for x in v.to_string().chars() {
            if !x.is_ascii() {
                let vv = percent_encoding::percent_encode_byte(x as u8);
                *v = v.replace(x, vv);
            }
        }
        headers_default.insert(k, v);
    }

    #[allow(unused_mut)]
    let mut req = isahc::HttpClientBuilder::new().default_headers(headers_default);
    // for (k, v) in headers.iter_mut() {
    //     for x in v.to_string().chars() {
    //         if !x.is_ascii(){
    //             let vv = percent_encoding::percent_encode_byte(x as u8);
    //             *v = v.replace(x, vv);
    //         }
    //     }
    //     let v = v.to_string();
    //     req = req.default_header(k, v);
    // }

    #[cfg(any(feature = "req_timeout_30", feature = "req_timeout_60"))]
    {
        req = req.connect_timeout(std::time::Duration::from_secs(TIME_OUT_CONNECT)).timeout(std::time::Duration::from_secs(TIME_OUT));
    }

    let res = req
        // .connect_timeout(Duration::from_secs(TIME_OUT))
        // .timeout(Duration::from_secs(TIME_OUT))
        .build()?
        .post(url, body)?
        .text()?;
    let json_val = serde_json::from_str::<JsonV>(&res);
    let r = match json_val {
        Ok(v) => v,
        Err(e) => {
            warn!("post_with_header error: {:?} \nres:{}", e, res);
            JsonV::String(res)
        }
    };
    Ok(r)
}
#[test]
fn test_post_with_header() {
    let r = post_with_header(
        "https://blog.csdn.net/".to_string(),
        hashmap! {|v: &str|v.to_string();
            "Cookie" => "xxx离宇x",
        },
        "fdsafdsafsda",
    );
    println!("test_post_with_header: {:?}", r);
}

/// 使用cookie进行请求post
pub fn get_with_header(url: String, mut headers: HashMap<String, String>) -> IResult<JsonV> {
    let mut headers_default = get_json_haeders();
    for (k, v) in headers.iter_mut() {
        for x in v.to_string().chars() {
            if !x.is_ascii() {
                let vv = percent_encoding::percent_encode_byte(x as u8);
                *v = v.replace(x, vv);
            }
        }
        headers_default.insert(k, v);
    }

    let mut req = isahc::HttpClientBuilder::new().default_headers(headers_default);
    for (k, v) in headers.iter_mut() {
        for x in v.to_string().chars() {
            if !x.is_ascii() {
                let vv = percent_encoding::percent_encode_byte(x as u8);
                *v = v.replace(x, vv);
            }
        }
        let v = v.to_string();
        // println!("header-value: {}", v);
        req = req.default_header(k, v);
    }

    #[cfg(any(feature = "req_timeout_30", feature = "req_timeout_60"))]
    {
        req = req.connect_timeout(std::time::Duration::from_secs(TIME_OUT_CONNECT)).timeout(std::time::Duration::from_secs(TIME_OUT));
    }

    let res = req
        // .connect_timeout(Duration::from_secs(TIME_OUT))
        // .timeout(Duration::from_secs(TIME_OUT))
        .build()?
        .get(url)?
        .text()?;
    let json_val = serde_json::from_str::<JsonV>(&res);
    let r = match json_val {
        Ok(v) => v,
        Err(_e) => JsonV::String(res),
    };

    Ok(r)
}
#[test]
fn test_get_with_header() {
    let map = hashmap! {|v: &str|v.to_owned();"guoyu" => "guog*%*&*&jadgo-郭宇-345325a08678)(*^fd"};
    let _ = get_with_header("https://vip2.kdzwy.com/guanjia/#/home".to_string(), map);
}

pub fn get_json<T: DeserializeOwned>(url: String) -> IResult<T> {
    #[allow(unused_mut)]
    let mut req = isahc::HttpClientBuilder::new().default_headers(get_json_haeders());

    #[cfg(any(feature = "req_timeout_30", feature = "req_timeout_60"))]
    {
        req = req.connect_timeout(std::time::Duration::from_secs(TIME_OUT_CONNECT)).timeout(std::time::Duration::from_secs(TIME_OUT));
    }

    // .timeout(Duration::from_secs(TIME_OUT))
    let r = req.build()?.get(url)?.json::<T>()?;
    Ok(r)
}

#[test]
pub fn test_post() {
    let body = r##"{"error_info":null,"data":{"data_id":null,"account_id":"96693efe7f3840e7b5c34cc90c33a9df","now_id":660,"type_title":"登录","created_datetime":"2020-12-23 12:08:59","error_info":null,"created_data":1608696539,"start_date":null,"end_date":null,"json_data":"正常"},"account":{"account_id":"96693efe7f3840e7b5c34cc90c33a9df","user_id":null,"company_name":null,"account_name":"91430105MA4LJQY047","account_password":"cszj131419","status":"帐户正常","last_get_data":null,"run_time":1608696509,"updated_time":1608696539,"created_time":1608696539}}"##;
    let r = post_json::<serde_json::Value>("https://dsp.zgaic.com/fas/Tax/TaxpayerInformation".to_owned(), serde_json::from_str(body).unwrap());
    println!("test_post_vec: {}", r.unwrap().to_string());
}

pub fn get_vec(url: String) -> IResult<Vec<u8>> {
    let mut buf = vec![];

    #[allow(unused_mut)]
    let mut req = isahc::HttpClientBuilder::new().default_headers(get_haeders());

    #[cfg(any(feature = "req_timeout_30", feature = "req_timeout_60"))]
    {
        req = req.connect_timeout(std::time::Duration::from_secs(TIME_OUT_CONNECT)).timeout(std::time::Duration::from_secs(TIME_OUT));
    }

    // .timeout(Duration::from_secs(TIME_OUT))
    req.build()?.get(url)?.copy_to(&mut buf)?;
    Ok(buf)
}

pub fn get_file(url: String, path: impl Into<String>) -> IResult<()> {
    #[allow(unused_mut)]
    let mut req = isahc::HttpClientBuilder::new().default_headers(get_haeders());

    #[cfg(any(feature = "req_timeout_30", feature = "req_timeout_60"))]
    {
        req = req.connect_timeout(std::time::Duration::from_secs(TIME_OUT_CONNECT)).timeout(std::time::Duration::from_secs(TIME_OUT));
    }

    // .timeout(Duration::from_secs(TIME_OUT))
    req.build()?.get(url)?.copy_to_file(path.into())?;
    Ok(())
}

pub fn update_file<T: DeserializeOwned>(url: String, file_name: String, buff: &[u8]) -> IResult<T> {
    let file_name = percent_encoding::utf8_percent_encode(&file_name, percent_encoding::NON_ALPHANUMERIC).to_string();
    #[allow(unused_mut)]
    let mut req = isahc::HttpClientBuilder::new().default_header("file_name", file_name);

    #[cfg(any(feature = "req_timeout_30", feature = "req_timeout_60"))]
    {
        req = req.connect_timeout(std::time::Duration::from_secs(TIME_OUT_CONNECT)).timeout(std::time::Duration::from_secs(TIME_OUT));
    }

    let r = req.build()?.post(url, buff)?.json::<T>()?;
    Ok(r)
}

pub fn update_filepath<T: DeserializeOwned>(url: String, file_name: String, file_path: &Path) -> IResult<T> {
    let r = std::fs::read(file_path)?;
    update_file(url, file_name, r.as_slice())
}

#[test]
fn test_update_file() -> IResult<()> {
    let r = match std::fs::read("C:/Users/guoyu/OneDrive/大算盘/“金三”个人所得税系统扣缴申报业务和技术标准/个人所得税扣缴申报标准说明.doc") {
        Ok(v) => v,
        Err(e) => {
            eprintln!("std::fs::read: {:?}", &e);
            Err(e)?
        }
    };
    // let r = std::fs::read(
    //     "C:/Users/guoyu/OneDrive/桌面/才税之家企业服务有限公司_小企业会计准则财务报表_20200701_20200930 (1).xls",
    // )?;
    // 才税之家企业服务有限公司_小企业会计准则财务报表_20200701_20200930 (1).xls
    let r = update_file::<JsonV>("http://127.0.0.1:8081/etax/file/upload".to_owned(), "test/个人所得税扣缴申报标准说明.doc".to_owned(), r.as_slice());
    println!("update_file: {:?}", r);
    Ok(())
}

#[test]
fn test_get_vec() -> IResult<()> {
    use std::fs::File;
    use std::io::Write;
    let bytes = get_vec("https://necaptcha.nosdn.127.net/d0cee769c8fa476b957af7f222972f6c.jpg".to_owned())?;
    let mut file = File::create("测试0106.jpg").map_err(|e| format!("新建图片错误: {:?}", e))?;
    file.write_all(bytes.as_slice()).map_err(|e| format!("下载图片[write_all]错误: {:?}", e))?;
    Ok(())
}
