package com.house365.web.util;

import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.house365.beans.entity.WxUserEntity;
import com.house365.rest.exception.ServiceException;
import com.house365.rest.parameter.House365RestResponse;
import net.sf.json.JSONObject;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
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.utils.URIBuilder;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.hibernate.validator.internal.util.privilegedactions.GetMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.*;

public class HttpUtil {
    private static final Logger LOG = LoggerFactory.getLogger("HttpUtil");
    private static final String DEFAULT_ENCODING = "UTF-8";

    private final static int DEFAULT_CONNECT_TIMEOUT = 5000; // 设置连接超时时间，单位毫秒
    private final static int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 1000;// 设置从connect Manager获取Connection 超时时间，单位毫秒
    private final static int DEFAULT_SOCKET_TIMEOUT = 5000;// 请求获取数据的超时时间，单位毫秒 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用


    /**
     *新:get请求
     * @param url
     * @param timeOut
     * @param charSet
     * @return
     * @throws IOException
     */
    public static String getHttpRequest(String url, Map<String, String> map , int timeOut, String charSet) throws IOException {

        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse httpResponse = null;
        long beginTime = System.currentTimeMillis();
        try {
            HttpGet httpGet = new HttpGet();
            URIBuilder builder = new URIBuilder(url);
            httpGet.setURI(builder.build());
            if(StringUtils.isNotBlank(map.get("version"))){
                httpGet.addHeader("version", "v3.0");
            }
            if(StringUtils.isNotBlank(map.get("access-token"))){
                httpGet.addHeader("access-token", map.get("access-token"));
            }
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeOut).setConnectTimeout(timeOut).build();//设置请求和传输超时时间
            httpGet.setConfig(requestConfig);
            httpResponse = httpClient.execute(httpGet);
            HttpEntity httpEntity = httpResponse.getEntity();

            String body = null;
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK && httpEntity != null) {
                if (StringUtils.isNotBlank(charSet)) {
                    body = EntityUtils.toString(httpEntity, charSet);
                } else {
                    body = EntityUtils.toString(httpEntity, DEFAULT_ENCODING);
                }
                EntityUtils.consume(httpEntity);
            }
            if (LOG.isInfoEnabled()) {
                logUrlInfo(beginTime, url);
            }
            return body;
        } catch (Exception e) {
            LOG.error(e.toString(), e);
        } finally {
            if (httpResponse != null) {
                try {
                    httpResponse.close();
                } catch (IOException e) {
                    LOG.error(e.toString(), e);
                }
            }

            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    LOG.error(e.toString(), e);
                }
            }
        }
        return null;
    }

    public static String doPostWithHeader(String url, List<NameValuePair> params, String accessToken, String charSet) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse httpResponse = null;
        long beginTime = System.currentTimeMillis();
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
            httpPost.addHeader("version", "v3.0");
            httpPost.addHeader("access-token", accessToken);

            httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            LOG.info("*****StatusCode*******"+httpResponse.getStatusLine().getStatusCode());
            String body = null;
            if (httpEntity != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK ) {
                if (org.apache.commons.lang3.StringUtils.isNotBlank(charSet)) {
                    body = EntityUtils.toString(httpEntity, charSet);
                } else {
                    body = EntityUtils.toString(httpEntity, DEFAULT_ENCODING);
                }
                EntityUtils.consume(httpEntity);
            }

            logUrlInfo(beginTime, url);

            return body;
        } catch (Exception e) {
            LOG.error(e.toString(), e);
        } finally {
            if (httpResponse != null) {
                try {
                    httpResponse.close();
                } catch (IOException e) {
                    LOG.error(e.toString(), e);
                }
            }

            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    LOG.error(e.toString(), e);
                }
            }
        }
        return null;
    }

    private static void logUrlInfo(long beginTime, String url) {
        if (System.currentTimeMillis() - beginTime > 1000) {
            LOG.info("call url [{}] , use [{}] ms", url, System.currentTimeMillis() - beginTime);
        }
    }

    /**
     * 生成signature
     * @return
     */
    public static String getSignature(String deciceId, String randStr, String timestamp){
        //获取signature
        List<NameValuePair> signatureInParam = new ArrayList<>();
        signatureInParam.add(new BasicNameValuePair("app_id", "12558119"));
        signatureInParam.add(new BasicNameValuePair("app_secret", "OHuJNOfHSMixNeoedRwScEmzcDAuxnJw"));
        signatureInParam.add(new BasicNameValuePair("device_id", deciceId));
        signatureInParam.add(new BasicNameValuePair("rand_str", randStr));
        signatureInParam.add(new BasicNameValuePair("timestamp", timestamp));
        List<String> newParams = new ArrayList<>();
        for (NameValuePair pair : signatureInParam) {
            newParams.add(pair.getName() + "=" + pair.getValue());
        }
        String newStr = Joiner.on("&").join(newParams);
        String signature = MD5Util.MD5(newStr);
        return signature;
    }

    public static String getSignature2(String deciceId, String randStr, String timestamp){
        //获取signature
        List<NameValuePair> signatureInParam = new ArrayList<>();
        signatureInParam.add(new BasicNameValuePair("app_id", "89962055"));
        signatureInParam.add(new BasicNameValuePair("app_secret", "pMHTUWAoOGSjaToIhHKwmQJKWZcAAvjN"));
        signatureInParam.add(new BasicNameValuePair("device_id", deciceId));
        signatureInParam.add(new BasicNameValuePair("rand_str", randStr));
        signatureInParam.add(new BasicNameValuePair("timestamp", timestamp));
        List<String> newParams = new ArrayList<>();
        for (NameValuePair pair : signatureInParam) {
            newParams.add(pair.getName() + "=" + pair.getValue());
        }
        String newStr = Joiner.on("&").join(newParams);
        String signature = MD5Util.MD5(newStr);
        return signature;
    }

    public static String getAccessToken(HashMap<String, String> tokenMap, String timestamp, String randStr, String signature, String deciceId, House365RestResponse response){
        //获取acceToken接口URl
        String getAccessTokenUrl = "http://tel400.house365.com/api/5aaf0c48ed105";
        List<NameValuePair> tokenInParam = new ArrayList<>();

        tokenInParam.add(new BasicNameValuePair("timestamp", timestamp));
        tokenInParam.add(new BasicNameValuePair("app_id", "12558119"));
        tokenInParam.add(new BasicNameValuePair("rand_str", randStr));
        tokenInParam.add(new BasicNameValuePair("signature", signature));
        tokenInParam.add(new BasicNameValuePair("device_id", deciceId));
        List<String> newTokenParams = new ArrayList<>();
        for (NameValuePair pair : tokenInParam) {
            newTokenParams.add(pair.getName() + "=" + pair.getValue());
        }
        String newTokenUrl = getAccessTokenUrl + "?" + Joiner.on("&").join(newTokenParams);
        String tokenResult = "";
        try {
            tokenResult = HttpUtil.getHttpRequest(newTokenUrl, tokenMap, 100000, "utf-8");
            if (Strings.isNullOrEmpty(tokenResult)) {
                throw new ServiceException("get token failed");
            }
            JSONObject json = JSONObject.fromObject(tokenResult);
            JSONObject jo = json.getJSONObject("data");
            String accessToken = jo.getString("access_token");
            return accessToken;
        }catch (Exception e){
            LOG.error(e.getMessage(), e);
            response.setResult("0");
            response.setMsg(e.getMessage());
        }
        return null;
    }

    public static String postWithJson(JSONObject jsonObj, String url, String token) {
        HttpPost post = null;
        try {
            HttpClient httpClient = new DefaultHttpClient();

            post = new HttpPost(url);
            // 构造消息头
            post.setHeader("access_token", token);

            // 构建消息实体
            StringEntity entity = new StringEntity(jsonObj.toString(), Charset.forName("UTF-8"));
            entity.setContentEncoding("UTF-8");
            // 发送Json格式的数据请求
            entity.setContentType("application/json");
            post.setEntity(entity);

            HttpResponse response = httpClient.execute(post);

            // 检验返回码
            int statusCode = response.getStatusLine().getStatusCode();
            HttpEntity httpEntity = response.getEntity();
            String body = null;
            if (httpEntity != null && statusCode == HttpStatus.SC_OK ) {
                if (org.apache.commons.lang3.StringUtils.isNotBlank(DEFAULT_ENCODING)) {
                    body = EntityUtils.toString(httpEntity, DEFAULT_ENCODING);
                } else {
                    body = EntityUtils.toString(httpEntity, DEFAULT_ENCODING);
                }
                EntityUtils.consume(httpEntity);
            }
            return body;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (post != null) {
                try {
                    post.releaseConnection();
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 简单get请求传输
     * @param url
     * @param paramMap
     * @param encoding
     * @return
     */
    public static String simpleGet(String url, Map<String,String> paramMap, String encoding){
        String body = "";
        encoding = StringUtils.isBlank(encoding)?DEFAULT_ENCODING:encoding;
        //1、创建CloseableHttpClient对象
        CloseableHttpClient client = HttpClients.createDefault();

        //2、创建get请求
        HttpGet httpGet = new HttpGet(url);
        //装填参数
        List<NameValuePair> lists = new ArrayList<NameValuePair>();
        if(paramMap != null){
            //每个key-value构成一个entrySet对象
            Set<Map.Entry<String, String>> setMap = paramMap.entrySet();
            //遍历对象  将值保存list集合种
            for (Map.Entry<String, String> entry:setMap) {
                lists.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }
        //将传递参数  编码化
        String param = URLEncodedUtils.format(lists, encoding);
        LOG.info("simpleGet------->"+param);
        //设置数据
        httpGet.setURI(URI.create(url+"?"+param));
        LOG.info("simpleGet --- url------->"+httpGet.getURI().toString());
        //配置连接参数信息
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT).setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)
                .setSocketTimeout(DEFAULT_SOCKET_TIMEOUT).build();
        httpGet.setConfig(requestConfig);

        //执行请求操作，并拿到结果（同步阻塞）
        CloseableHttpResponse response = null;
        try {
            //5、调用CloseableHttpClient对象的execute(HttpUriRequest request)发送请求，该方法返回一个CloseableHttpResponse。
            response = client.execute(httpGet);
            //6、调用HttpResponse的getEntity()方法可获取HttpEntity对象，该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容；调用CloseableHttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头。
            StatusLine status = response.getStatusLine();
            LOG.info("get请求回调状态               ："+status);
            //获取结果实体
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                //按指定编码转换结果实体为String类型
                body = EntityUtils.toString(entity, encoding);
                LOG.info("get请求回调数据               ："+body);
            }
            //7、释放连接。无论执行方法是否成功，都必须释放连接
            EntityUtils.consume(entity);
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
            LOG.error("简单get请求遇到UnSpEcode异常",e);
        } catch (IOException e) {
            e.printStackTrace();
            LOG.error("简单get请求遇到IO异常",e);
        } catch (ParseException e) {
            e.printStackTrace();
            LOG.error("简单get请求遇到PE异常",e);
            throw new ParseException();
        } finally{
            //释放链接
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return body;
    }
}
