package com.cm.common.utils.http;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
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.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.CharsetUtils;
import org.apache.http.util.EntityUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName: HttpClientUtil
 * @Description: Http Client
 * @Author: wenc
 * @Date: 2018/9/22 下午6:18
 * @Version: 1.0
 **/
public class HttpClientUtil {

    public static final String ENCODE_UTF8 = "UTF-8";
    public static final String APPLICATION_JSON = "application/json";
    public static final String APPLICATION_FORM = "application/x-www-form-urlencoded";
    public static final String TEXT_PLAIN = "text/plain, text/html";
    public static final int CONNECT_TIMEOUT = 80000;

    /**
     * post json传递
     *
     * @param url
     * @param json
     * @return
     */
    public static String sendJsonHttpPost(String url, String json) {

        CloseableHttpClient httpclient = HttpClients.createDefault();
        String responseInfo = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
            ContentType contentType = ContentType.create("application/json", CharsetUtils.get("UTF-8"));
            httpPost.setEntity(new StringEntity(json, contentType));
            CloseableHttpResponse response = httpclient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            int status = response.getStatusLine().getStatusCode();
            if (status >= 200 && status < 300) {
                if (null != entity) {
                    responseInfo = EntityUtils.toString(entity);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return responseInfo;
    }

    /**
     * GET 请求
     *
     * @param url
     * @param params
     * @return
     */
    public static String doGetForm(String url, Map<String, Object> params) {
        Map<String, String> header = new HashMap<>(1);
        header.put("Accept", APPLICATION_JSON);
        header.put("Accept-Charset", ENCODE_UTF8);
        return doGetForm(url, header, params);
    }

    /**
     * GET 请求
     *
     * @param url
     * @param header
     * @param params
     * @return
     */
    public static String doGetForm(String url, Map<String, String> header, Map<String, Object> params) {
        System.out.println(">>>> GET <<<<");
        System.out.println(">>>> url: " + url);
        System.out.println(">>>> header: " + header);
        System.out.println(">>>> params: " + params);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String result = null;
        try {
            URIBuilder uriBuilder = new URIBuilder(url);
            setGetParams(uriBuilder, params);
            HttpGet httpGet = new HttpGet(uriBuilder.build());
            setHeaders(httpGet, header);
            result = getResponse(httpClient, httpGet);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        return result;
    }

    /**
     * POST提交表单
     *
     * @param url
     * @param params
     * @return
     */
    public static String doPostForm(String url, Map<String, Object> params) {
        Map<String, String> header = new HashMap<>(1);
        header.put("Accept", APPLICATION_JSON);
        header.put("Accept-Charset", ENCODE_UTF8);
        header.put("Content-Type", APPLICATION_FORM);
        return doPostForm(url, header, params);
    }

    /**
     * POST提交表单
     *
     * @param url
     * @param header
     * @param params
     * @return
     */
    public static String doPostForm(String url, Map<String, String> header, Map<String, Object> params) {
        return doPost(url, header, params, false);
    }

    /**
     * POST提交JSON
     *
     * @param url
     * @param params
     * @return
     */
    public static String doPostJson(String url, Map<String, Object> params) {
        Map<String, String> header = new HashMap<>(1);
        header.put("Accept", APPLICATION_JSON);
        header.put("Accept-Charset", ENCODE_UTF8);
        header.put("Content-Type", APPLICATION_JSON);
        return doPostJson(url, header, params);
    }

    /**
     * POST提交JSON
     *
     * @param url
     * @param header
     * @param params
     * @return
     */
    public static String doPostJson(String url, Map<String, String> header, Map<String, Object> params) {
        return doPost(url, header, params, true);
    }

    /**
     * POST请求
     *
     * @param url
     * @param header
     * @param params
     * @param isJson
     * @return
     */
    public static String doPost(String url, Map<String, String> header, Map<String, Object> params, boolean isJson) {
        System.out.println(">>>> POST <<<<");
        System.out.println(">>>> url: " + url);
        System.out.println(">>>> header: " + header);
        System.out.println(">>>> params: " + params);
        System.out.println(">>>> isJson: " + isJson);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String result = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            setHeaders(httpPost, header);
            setPostParams(httpPost, params, isJson);
            result = getResponse(httpClient, httpPost);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        return result;
    }

    /**
     * post获取图片
     *
     * @param url
     * @param params
     * @return
     */
    public static byte[] doPostImg(String url, Map<String, String> header, Map<String, Object> params) throws Exception {
        System.out.println(">>>> POST <<<<");
        System.out.println(">>>> url: " + url);
        System.out.println(">>>> params: " + params);
        byte[] result = null;
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpClient client = HttpClients.createDefault();
        httpPost.addHeader("Content-Type", "application/json");
        try {
            JSONObject postData = new JSONObject();
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                postData.put(entry.getKey(), entry.getValue());
            }
            httpPost.setEntity(new StringEntity(postData.toString(), "UTF-8"));
            HttpResponse response = client.execute(httpPost);
            HttpEntity entity = response.getEntity();
            result = EntityUtils.toByteArray(entity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpPost.releaseConnection();
        }
        return result;
    }

    /**
     * form表单提交文件
     *
     * @param url
     * @param params
     * @param is
     * @param fileName
     * @return
     */
    public static String doPostFile(String url, Map<String, String> params, InputStream is, String fileName) {
        Map<String, String> header = new HashMap<>(1);
        header.put("Accept", APPLICATION_JSON);
        header.put("Accept-Charset", ENCODE_UTF8);
        return doPostFile(url, header, params, is, "file", fileName);
    }

    /**
     * form表单提交文件
     *
     * @param url
     * @param params
     * @param is
     * @return
     */
    public static String doPostFile(String url, Map<String, String> header,
                                    Map<String, String> params,
                                    InputStream is, String inputName, String fileName) {
        System.out.println(">>>> POST <<<<");
        System.out.println(">>>> url: " + url);
        System.out.println(">>>> params: " + params);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String result = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            setConfig(httpPost);
            setHeaders(httpPost, header);
            // 上传文件乱码问题
            multipartEntityBuilder.setCharset(Charset.forName(ENCODE_UTF8));
            multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            multipartEntityBuilder.addBinaryBody(inputName, is, ContentType.MULTIPART_FORM_DATA, fileName);
            if (null != params) {
                for (Map.Entry<String, String> kv : params.entrySet()) {
                    multipartEntityBuilder.addTextBody(kv.getKey(), kv.getValue());
                }
            }
            HttpEntity httpEntity = multipartEntityBuilder.build();
            httpPost.setEntity(httpEntity);
            result = getResponse(httpClient, httpPost);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 通过url下载文件
     *
     * @param url
     * @return
     */
    public static InputStream doDownLoadFile(String url) {
        InputStream is = null;
        try {
            HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(url).openConnection();
            httpURLConnection.setConnectTimeout(CONNECT_TIMEOUT);
            is = httpURLConnection.getInputStream();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return is;
    }


    /**
     * 获取响应
     *
     * @param httpClient
     * @param httpRequestBase
     * @return
     * @throws IOException
     */
    private static String getResponse(CloseableHttpClient httpClient, HttpRequestBase httpRequestBase) throws IOException {
        String result = null;
        CloseableHttpResponse httpResponse = httpClient.execute(httpRequestBase);
        if (HttpStatus.SC_OK == httpResponse.getStatusLine().getStatusCode()) {
            HttpEntity entity = httpResponse.getEntity();
            result = EntityUtils.toString(entity, Charset.forName(ENCODE_UTF8));
        }
        System.out.println(">>>> result: " + result);
        return result;
    }

    /**
     * 设置基础配置
     *
     * @param httpRequestBase
     */
    private static void setConfig(HttpRequestBase httpRequestBase) {
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(CONNECT_TIMEOUT).build();
        httpRequestBase.setConfig(requestConfig);
    }


    /**
     * 设置请求头
     *
     * @param httpRequestBase
     * @param headerMap
     */
    private static void setHeaders(HttpRequestBase httpRequestBase, Map<String, String> headerMap) {
        if (null == headerMap) {
            return;
        }
        for (Map.Entry<String, String> kv : headerMap.entrySet()) {
            httpRequestBase.setHeader(kv.getKey(), kv.getValue());
        }
    }

    /**
     * 设置GET参数
     *
     * @param uriBuilder
     * @param params
     */
    private static void setGetParams(URIBuilder uriBuilder, Map<String, Object> params) {
        if (null == params) {
            return;
        }
        for (Map.Entry<String, Object> kv : params.entrySet()) {
            uriBuilder.setParameter(kv.getKey(), StringUtils.isEmpty(kv.getValue()) ? "" : kv.getValue().toString());
        }
    }

    /**
     * 通过map获取form字符串，格式：k1=v1&k2=v2
     *
     * @param params
     * @return
     */
    public static String getGetParamsStr(Map<String, Object> params) {
        if (null == params) {
            return "";
        }
        StringBuilder getParamsStr = new StringBuilder();
        for (Map.Entry<String, Object> kv : params.entrySet()) {
            if (getParamsStr.length() > 0) {
                getParamsStr.append("&");
            }
            getParamsStr.append(kv.getKey()).append("=").append(kv.getValue());
        }
        return getParamsStr.toString();
    }

    /**
     * 设置POST参数
     *
     * @param httpPost
     * @param params
     * @param isJson
     */
    private static void setPostParams(HttpPost httpPost, Map<String, Object> params, boolean isJson) {
        if (null == params) {
            return;
        }
        if (isJson) {
            StringEntity entity = new StringEntity(JSONObject.toJSONString(params), Charset.forName(ENCODE_UTF8));
            entity.setContentEncoding(ENCODE_UTF8);
            entity.setContentType(APPLICATION_JSON);
            httpPost.setEntity(entity);
        } else {
            List<NameValuePair> nameValuePairs = new ArrayList<>();
            for (Map.Entry<String, Object> kv : params.entrySet()) {
                nameValuePairs.add(new BasicNameValuePair(kv.getKey(), StringUtils.isEmpty(kv.getValue()) ? "" : kv.getValue().toString()));
            }
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, Charset.forName(ENCODE_UTF8)));
        }
    }

}
