package com.fzm.mall.server.admin.util;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author kyo lyz
 * @create 2018/7/12 14:10
 */
public class HttpUtil {

    private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);

    private static CloseableHttpClient client = null;

    private static CloseableHttpClient httpsClient = null;
    //请求参数
    private static RequestConfig requestConfig = null;

    private static final String DEFAULT_CHARSET = "utf-8";

    private static final int DEFAULT_TIME_OUT = 200000;

    static {
        //初始化
        client = HttpClientBuilder.create().build();
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        //设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(DEFAULT_TIME_OUT);
        // 设置连接超时
        configBuilder.setConnectTimeout(DEFAULT_TIME_OUT);
        //设置读取超时
        configBuilder.setSocketTimeout(DEFAULT_TIME_OUT);
        requestConfig = configBuilder.build();
        //带有证书的ssl请求createSSLCertInsecureClient(certPath, certPassword);
        //忽略证书的
        httpsClient = createSSLInsecureClient();
    }

    /**
     * 获取HttpServletRequest的请求体信息
     *
     * @param req
     * @return
     */
    public static String getRequestBody(HttpServletRequest req) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(req.getInputStream()))) {
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            return sb.toString();
        } catch (IOException ioe) {
            log.error("解析请求信息出错：", ioe);
            return null;
        }
    }

    public static String httpGet(String url) {
        return httpGet(url, null, DEFAULT_CHARSET);
    }

    public static String httpGet(String url, Map<String, Object> map) {
        return httpGet(url, map, DEFAULT_CHARSET);
    }

    /**
     * httpGet 请求
     *
     * @param url
     * @param map
     * @return
     */
    public static String httpGet(String url, Map<String, Object> map, String chartset) {
        String content = null;
        HttpGet get = new HttpGet(url);
        try {
            get.setConfig(requestConfig);
            if (map != null && map.size() != 0) {
                setGetParams(get, map);
            }
            HttpResponse response = client.execute(get);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, chartset);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            get.releaseConnection();
        }
        return content;
    }

    /**
     * httpGet 请求
     *
     * @param url
     * @param map
     * @return
     */
    public static String httpGetHeader(String url, Map<String, Object> map) {
        String content = null;
        HttpGet get = new HttpGet(url);
        try {
            get.setConfig(requestConfig);
            if (map != null && map.size() != 0) {
                setGetHeaderParams(get, map);
            }
            HttpResponse response = client.execute(get);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            get.releaseConnection();
        }
        return content;
    }


    public static String httpPost(String url) {
        return httpPost(url, null, DEFAULT_CHARSET);
    }

    public static String httpPost(String url, Map<String, Object> map) {
        return httpPost(url, map, DEFAULT_CHARSET);
    }

    public static String httpPost(String url, Map<String, Object> paramterMap, Map<String, Object> headerMap) {
        return httpPostWithHeader(url, paramterMap, headerMap, DEFAULT_CHARSET);
    }

    /**
     * httpPost请求
     *
     * @param url
     * @param map
     * @return
     */
    public static String httpPost(String url, Map<String, Object> map, String charset) {
        String content = null;
        HttpPost post = new HttpPost(url);
        try {
            post.setConfig(requestConfig);
            if (map != null && map.size() != 0) {
                setPostParams(post, map, charset);
            }
            HttpResponse response = client.execute(post);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, charset);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            post.releaseConnection();
        }
        return content;
    }

    /**
     * httpPost请求携带header
     *
     * @param url
     * @param paramterMap,headerMap
     * @return
     */
    public static String httpPostWithHeader(String url, Map<String, Object> paramterMap, Map<String, Object> headerMap, String charset) {
        String content = null;
        HttpPost post = new HttpPost(url);
        try {
            post.setConfig(requestConfig);
            if (paramterMap != null && paramterMap.size() != 0) {
                setPostParams(post, paramterMap, charset);
            }
            if (headerMap != null && headerMap.size() != 0) {
                setPostHeaderParams(post, headerMap);
            }
            HttpResponse response = client.execute(post);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, charset);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            post.releaseConnection();
        }
        return content;
    }

    /**
     * https client 证书初始化
     *
     * @param certPath
     * @param certPassword
     */
    @SuppressWarnings("unused")
    private static CloseableHttpClient createSSLCertInsecureClient(String certPath, String certPassword) {
        CloseableHttpClient sslClient = null;
        KeyStore keyStore = null;
        SSLContext sslcontext = null;
        try {
            keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream inputStream = new FileInputStream(new File(certPath));
            keyStore.load(inputStream, certPassword.toCharArray());
            sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, certPassword.toCharArray()).build();
        } catch (Exception e) {
        }

        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());

        sslClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        ;

        requestConfig = RequestConfig.custom().setSocketTimeout(DEFAULT_TIME_OUT).setConnectTimeout(DEFAULT_TIME_OUT).setConnectionRequestTimeout(DEFAULT_TIME_OUT).build();
        return sslClient;
    }

    /**
     * 创建一个SSL信任所有证书的httpClient对象
     *
     * @return
     */
    @SuppressWarnings("deprecation")
    public static CloseableHttpClient createSSLInsecureClient() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 默认信任所有证书
                public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    return true;
                }
            }).build();
            // AllowAllHostnameVerifier: 这种方式不对主机名进行验证，验证功能被关闭，是个空操作(域名验证)
            SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(sslContext,
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            return HttpClients.custom().setSSLSocketFactory(sslcsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return HttpClients.createDefault();
    }

    public static String httpsGet(String url) {
        return httpsGet(url, null, DEFAULT_CHARSET);
    }

    public static String httpsGet(String url, Map<String, Object> map) {
        return httpsGet(url, map, DEFAULT_CHARSET);
    }

    /**
     * httpGet 请求
     *
     * @param url
     * @param map
     * @return
     */
    public static String httpsGet(String url, Map<String, Object> map, String chartset) {
        String content = null;
        HttpGet get = new HttpGet(url);
        try {
            get.setConfig(requestConfig);
            if (map != null && map.size() != 0) {
                setGetParams(get, map);
            }
            HttpResponse response = httpsClient.execute(get);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, chartset);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            get.releaseConnection();
        }
        return content;
    }

    /**
     * httpGet 请求
     *
     * @param url
     * @param map
     * @return
     */
    public static HttpEntity httpsGetEntity(String url, Map<String, Object> map, String chartset) {
        HttpEntity httpEntity = null;
        HttpGet get = new HttpGet(url);
        try {
            get.setConfig(requestConfig);
            if (map != null && map.size() != 0) {
                setGetParams(get, map);
            }
            HttpResponse response = httpsClient.execute(get);
            httpEntity = response.getEntity();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            get.releaseConnection();
        }
        return httpEntity;
    }


    public static String httpsPost(String url) {
        return httpsPost(url, null, DEFAULT_CHARSET);
    }

    public static String httpsPost(String url, Map<String, Object> map) {
        return httpsPost(url, map, DEFAULT_CHARSET);
    }

    /**
     * httpPost请求
     *
     * @param url
     * @param map
     * @return
     */
    public static String httpsPost(String url, Map<String, Object> map, String charset) {
        String content = null;
        HttpPost post = new HttpPost(url);
        try {
            post.setConfig(requestConfig);
            if (map != null && map.size() != 0) {
                setPostParams(post, map, charset);
            }
            HttpResponse response = httpsClient.execute(post);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, charset);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            post.releaseConnection();
        }
        return content;
    }

    private static String getContent(HttpEntity entity, String charset) {
        String content = null;
        if (entity != null) {
            try {
                InputStream in = entity.getContent();
                InputStreamReader inputStreamReader = new InputStreamReader(in, charset);
                BufferedReader reader = new BufferedReader(inputStreamReader);
                StringBuffer stringBuffer = new StringBuffer();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    stringBuffer.append(line);
                    stringBuffer.append("\r\n");
                }
                content = stringBuffer.toString();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return content;
    }

    /**
     * 设置post参数
     *
     * @param post
     * @param map
     */
    private static void setPostParams(HttpPost post, Map<String, Object> map, String charset) {
        List<NameValuePair> valueList = new ArrayList<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            BasicNameValuePair valuePair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
            valueList.add(valuePair);
        }
        try {
            post.setEntity(new UrlEncodedFormEntity(valueList, charset));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 设置get参数
     *
     * @param get
     * @param map
     */
    private static void setGetParams(HttpGet get, Map<String, Object> map) {
        String path = get.getURI().toString();
        if (map != null && map.size() != 0) {
            StringBuilder stringBuilder = new StringBuilder(path + "?");
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                stringBuilder.append(entry.getKey() + "=" + entry.getValue().toString() + "&");
            }
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            try {
                get.setURI(new URI(stringBuilder.toString()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置get参数 Header
     *
     * @param get
     * @param map
     */
    private static void setGetHeaderParams(HttpGet get, Map<String, Object> map) {
        if (map != null && map.size() != 0) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                get.addHeader(entry.getKey(), entry.getValue() + "");
            }
        }
    }

    /**
     * 设置post参数 Header
     *
     * @param post
     * @param map
     */
    private static void setPostHeaderParams(HttpPost post, Map<String, Object> map) {
        if (map != null && map.size() != 0) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                post.addHeader(entry.getKey(), entry.getValue() + "");
            }
        }
    }

    public static String httpPostBody(String url, String jsonString) {
        String content = null;
        HttpPost post = new HttpPost(url);
        try {
            post.setConfig(requestConfig);
            post.addHeader("Content-Type", "application/json");
            post.setEntity(new StringEntity(jsonString));
            HttpResponse response = client.execute(post);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            post.releaseConnection();
        }
        return content;
    }


    public static String httpGet(String logisticsUrl, Map<String, Object> params, Map<String, String> header) {
        String content = null;
        HttpGet get = new HttpGet(logisticsUrl);
        get.setHeader("Authorization", header.get("Authorization"));
        try {
            get.setConfig(requestConfig);
            if (params != null && params.size() != 0) {
                setGetParams(get, params);
            }
            HttpResponse response = client.execute(get);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            get.releaseConnection();
        }
        return content;
    }


    public static String httpsPostXML(String url, String xmlData) {
        String content = null;
        HttpPost post = new HttpPost(url);
        try {
            post.setConfig(requestConfig);
            if (!StringUtils.isEmpty(xmlData)) {
                post.setEntity(new StringEntity(xmlData));
            }
            HttpResponse response = httpsClient.execute(post);
            HttpEntity entity = response.getEntity();
            content = getContent(entity, DEFAULT_CHARSET);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            post.releaseConnection();
        }

        return content;
    }

    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}

