package com.artfess.portal.util;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
* @Description: http公共类
* @Author: wh
* @Date: 2020/7/8 13:10
*/
@Slf4j
public class HttpUtil {

    // 默认连接配置参数
    private static final int CONNECT_TIME_OUT = 30000;
    private static final int READ_TIME_OUT = 30000;
    private static final String CHARSET = "UTF-8";
    private static final String CONTENT_TYPE = "application/json";

    /**
     * 支持的Http method
     */
    private enum HttpMethod {
        POST, DELETE, GET, PUT, HEAD
    }

    @SuppressWarnings({"rawtypes"})
    private static String invokeUrl(String url, Map<String, Object> params, Map<String, String> headers, String content_type, int connectTimeout, int readTimeout, String encoding, HttpMethod method) {
        //构造请求参数字符串
        StringBuilder paramsStr = null;
        if (params != null) {

            paramsStr = new StringBuilder();
            Set<Entry<String, Object>> entries = params.entrySet();
            //Set<Map.Entry> entries = params.entrySet();
            for (Entry entry : entries) {
                String value = (entry.getValue() != null) ? (String.valueOf(entry.getValue())) : "";
                paramsStr.append(entry.getKey() + "=" + value + "&");
            }
            //只有POST方法才能通过OutputStream(即form的形式)提交参数
            if (method != HttpMethod.POST) {
                url += "?" + paramsStr.toString();
            }
        }

        URL uUrl = null;
        HttpURLConnection conn = null;
        BufferedWriter out = null;
        BufferedReader in = null;
        if (encoding == null || encoding.trim().equals("")) {
            encoding = CHARSET;
        }
        if (content_type == null || content_type.trim().equals("")) {
            content_type = CONTENT_TYPE;
        }
        try {
            //创建和初始化连接
            uUrl = new URL(url);
            conn = (HttpURLConnection) uUrl.openConnection();
            conn.setRequestProperty("content-type", content_type);
            conn.setRequestMethod(method.toString());
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //设置连接超时时间
            if (connectTimeout == 0) {
                conn.setConnectTimeout(CONNECT_TIME_OUT);
            } else {
                conn.setConnectTimeout(connectTimeout);
            }

            //设置读取超时时间

            if (readTimeout == 0) {
                conn.setConnectTimeout(READ_TIME_OUT);
            } else {
                conn.setReadTimeout(readTimeout);
            }
            //指定请求header参数
            if (headers != null && headers.size() > 0) {
                Set<String> headerSet = headers.keySet();
                for (String key : headerSet) {
                    conn.setRequestProperty(key, headers.get(key));
                }
            }

            if (paramsStr != null && method == HttpMethod.POST && !content_type.toLowerCase().equals("application/json")) {
                //发送请求参数
                out = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), encoding));
                out.write(paramsStr.toString());
                out.flush();
            }
            if (params != null && params.size() > 0 && method == HttpMethod.POST && content_type.toLowerCase().equals("application/json")) {
                JSONObject jsons = new JSONObject(params);//JSONObject.parseObject(params.toString());
                out = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), encoding));
                out.write(jsons.toString());
                out.flush();
            }
            //接收返回结果
            StringBuilder result = new StringBuilder();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), encoding));
            if (in != null) {
                String line = "";
                while ((line = in.readLine()) != null) {
                    result.append(line);
                }
            }
            return result.toString();
        } catch (Exception e) {
            log.error("调用接口[" + url + "]失败！请求URL：" + url + "，参数：" + params, e);
            //处理错误流，提高http连接被重用的几率
            try {
                byte[] buf = new byte[100];
                InputStream es = conn.getErrorStream();
                if (es != null) {
                    while (es.read(buf) > 0) {
                    }
                    es.close();
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            //关闭连接
            if (conn != null) {
                conn.disconnect();
            }
        }
        return null;
    }

    /**
     * POST方法提交Http请求，语义为“增加” <br/>
     * 注意：Http方法中只有POST方法才能使用body来提交内容
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param content_type   内容类型
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String post(String url, Map<String, Object> params, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, null, content_type, connectTimeout, readTimeout, charset, HttpMethod.POST);
    }

    /**
     * POST方法提交Http请求，语义为“增加” <br/>
     * 注意：Http方法中只有POST方法才能使用body来提交内容
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param headers        请求头参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String post(String url, Map<String, Object> params, Map<String, String> headers, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, headers, content_type, connectTimeout, readTimeout, charset, HttpMethod.POST);
    }

    /**
     * GET方法提交Http请求，语义为“查询”
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @return
     */
    public static String get(String url) {
        return invokeUrl(url, null, null, null, 5000, 5000, "utf-8", HttpMethod.GET);
    }

    /**
     * GET方法提交Http请求，语义为“查询”
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @return
     */
    public static String get(String url, Map<String, Object> params) {
        return invokeUrl(url, params, null, null, 5000, 5000, "utf-8", HttpMethod.GET);
    }

    /**
     * GET方法提交Http请求，语义为“查询”
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String get(String url, Map<String, Object> params, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, null, content_type, connectTimeout, readTimeout, charset, HttpMethod.GET);
    }

    /**
     * GET方法提交Http请求，语义为“查询”
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param headers        请求头参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String get(String url, Map<String, Object> params, Map<String, String> headers, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, headers, content_type, connectTimeout, readTimeout, charset, HttpMethod.GET);
    }

    /**
     * PUT方法提交Http请求，语义为“更改” <br/>
     * 注意：PUT方法也是使用url提交参数内容而非body，所以参数最大长度收到服务器端实现的限制，Resin大概是8K
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String put(String url, Map<String, Object> params, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, null, content_type, connectTimeout, readTimeout, charset, HttpMethod.PUT);
    }

    /**
     * PUT方法提交Http请求，语义为“更改” <br/>
     * 注意：PUT方法也是使用url提交参数内容而非body，所以参数最大长度收到服务器端实现的限制，Resin大概是8K
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param headers        请求头参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String put(String url, Map<String, Object> params, Map<String, String> headers, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, headers, content_type, connectTimeout, readTimeout, charset, HttpMethod.PUT);
    }

    /**
     * DELETE方法提交Http请求，语义为“删除”
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String delete(String url, Map<String, Object> params, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, null, content_type, connectTimeout, readTimeout, charset, HttpMethod.DELETE);
    }

    /**
     * DELETE方法提交Http请求，语义为“删除”
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param headers        请求头参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String delete(String url, Map<String, Object> params, Map<String, String> headers, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, headers, content_type, connectTimeout, readTimeout, charset, HttpMethod.DELETE);
    }

    /**
     * HEAD方法提交Http请求，语义同GET方法  <br/>
     * 跟GET方法不同的是，用该方法请求，服务端不返回message body只返回头信息，能节省带宽
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String head(String url, Map<String, Object> params, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, null, content_type, connectTimeout, readTimeout, charset, HttpMethod.HEAD);
    }

    /**
     * HEAD方法提交Http请求，语义同GET方法  <br/>
     * 跟GET方法不同的是，用该方法请求，服务端不返回message body只返回头信息，能节省带宽
     *
     * @param url            资源路径（如果url中已经包含参数，则params应该为null）
     * @param params         参数
     * @param headers        请求头参数
     * @param content_type   内容类型
     * @param connectTimeout 连接超时时间（单位为ms）
     * @param readTimeout    读取超时时间（单位为ms）
     * @param charset        字符集（一般该为“utf-8”）
     * @return
     */
    public static String head(String url, Map<String, Object> params, Map<String, String> headers, String content_type, int connectTimeout, int readTimeout, String charset) {
        return invokeUrl(url, params, headers, content_type, connectTimeout, readTimeout, charset, HttpMethod.HEAD);
    }




//    public static void timer1() {
//
//        Timer timer = new Timer();
//        timer.schedule(new TimerTask() {
//            public void run() {
//                System.out.println("-------设定要指定任务--------");
//                Map<String, Object> params = new HashMap<String, Object>();
//                params.put("args", "A50446004258100971110B0F3FB33333BE4CCCCD3E4CCCCD000000");
//
//
//                Map<String, String> headers = new HashMap<String, String>();
//                headers.put("api-key", "1f9Lc0Ksw8YcO2YPQSVWh7gsu=w=");
//                String url = "http://api.heclouds.com/nbiot/execute/offline?imei=869975035081630&obj_id=3200&obj_inst_id=0&res_id=5750&timeout=40&expired_time=2019-09-25T15:00:00";
//                String str = HttpUtil.post(url, params, headers, "application/json", 30000, 30000, "UTF-8");
//                System.out.println(str);
//            }
//        }, 2000, 60000 * 6);// 设定指定的时间time,此处为2000毫秒
//
//    }
//
    public static void main(String[] args) throws UnsupportedEncodingException {
        String entity=get("http://localhost:8098/actuator/health");
        //JSONArray jsonArray=JSONArray.parseArray(JSONObject.parseObject(entity).getString("components"));
        System.out.println(entity);
//        JSONObject jsonObject= JSONObject.parseObject(entity);
//        String systemStatus=jsonObject.getString("status");
//        System.out.println(systemStatus);
//        JSONObject json=jsonObject.getJSONObject("components");
//        for(String str : json.keySet()){
//            System.out.println(str+"***"+json.getJSONObject(str).getString("status"));
//        }
    }

}
