package cn.com.ctop.common.module.utils;

import cn.com.ctop.common.module.entity.HttpClientEntity;
import cn.com.ctop.common.module.entity.IpPool;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.*;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;
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.config.ConnectionConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

@Slf4j
public class HttpClientUtils {
    public CookieStore cookieStore = new BasicCookieStore();

    public CloseableHttpClient createSSLClientDefault(IpPool ipPool) {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                //信任所有证书
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            RequestConfig globalConfig = null;
            SSLConnectionSocketFactory sslFactory = null;
            ConnectionConfig connectionConfig = ConnectionConfig.custom()
                    .setBufferSize(4096)
                    .build();
            if (ipPool != null) {
                HttpHost proxy = new HttpHost(ipPool.getIp(), ipPool.getPort(), "http");
                globalConfig = RequestConfig.custom().setProxy(proxy).setConnectTimeout(60000).setSocketTimeout(60000).setCookieSpec(CookieSpecs.STANDARD).build();
                sslFactory = new SSLConnectionSocketFactory(sslContext);
            } else {
                globalConfig = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(60000).setCookieSpec(CookieSpecs.STANDARD).build();
                sslFactory = new SSLConnectionSocketFactory(sslContext);
            }
            return HttpClients.custom().setDefaultConnectionConfig(connectionConfig).setDefaultCookieStore(cookieStore).setDefaultRequestConfig(globalConfig).setConnectionReuseStrategy((response, context) -> false).setSSLSocketFactory(sslFactory).build();
        } catch (Exception e) {
            log.error("处理Https证书异常", e);
        }
        return HttpClients.createDefault();
    }

    public Boolean checkProxyIp(String ip, int port) {
        int status = 0;
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                //信任所有证书
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            ConnectionConfig connectionConfig = ConnectionConfig.custom()
                    .setBufferSize(4096)
                    .build();
            HttpHost proxy = new HttpHost(ip, port, "http");
            RequestConfig globalConfig = RequestConfig.custom().setProxy(proxy).setConnectTimeout(1000).setSocketTimeout(1000).setCookieSpec(CookieSpecs.STANDARD).build();
            SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext);

            HttpClient httpClient = HttpClients.custom().setDefaultConnectionConfig(connectionConfig).setDefaultCookieStore(cookieStore).setDefaultRequestConfig(globalConfig).setConnectionReuseStrategy((response, context) -> false).setSSLSocketFactory(sslFactory).build();
            HttpGet httpGet = new HttpGet("https://www.baidu.com");
            status = httpClient.execute(httpGet).getStatusLine().getStatusCode();
        } catch (Exception e) {
            log.info("ip: " + ip + " is not aviable");
        }
        if (status == 200) {
            return true;
        } else {
            return false;
        }
    }

    public String get(String urlStr) throws Exception {
        URL url = new URL(urlStr);
        URLConnection urlConnection = url.openConnection();
        // 获取输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line + "\n");
        }
        br.close();
        return sb.toString();
    }

    public HttpClientEntity httpGetRequest(HttpClientEntity httpClientEntity) throws Exception {
        String result = null;
        CookieStore cs = httpClientEntity.getCookieStore();
        if (cs != null) {
            for (Cookie ck : cs.getCookies()) {
                cookieStore.addCookie(ck);
            }
        }
        HttpResponse response = null;
        HttpGet httpGet = new HttpGet(httpClientEntity.getUrl());

        CloseableHttpClient httpClient = httpClientEntity.getCloseableHttpClient();
        response = httpClient.execute(httpGet);
        Header[] headers = response.getHeaders("Set-Cookie");
        if (headers != null && headers.length > 0) {
            for (Header header : headers) {
                String[] cookieArr = header.getValue().split(";");
                String[] ck = cookieArr[0].split("=");
                BasicClientCookie basicClientCookie = new BasicClientCookie(ck[0], ck[1]);
                Map<String, String> cookieMap = new HashMap<>();
                if (cookieArr.length > 1) {
                    for (int i = 1; i < cookieArr.length; i++) {
                        String[] ckParam = cookieArr[i].split("=");
                        if (ckParam.length > 1) {
                            cookieMap.put(ckParam[0].trim(), ckParam[1]);
                        }
                    }
                }

                basicClientCookie.setPath(cookieMap.get("Path"));
                if (cookieMap.get("Domain") == null || "".equals(cookieMap.get("Domain"))) {
                    if (httpClientEntity.getHeaders() != null && httpClientEntity.getHeaders().get("Origin") != null) {
                        basicClientCookie.setDomain(httpClientEntity.getHeaders().get("Origin").split("//")[1]);
                    }
                } else {
                    basicClientCookie.setDomain(cookieMap.get("Domain"));
                }
                basicClientCookie.setExpiryDate(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365));
                cookieStore.addCookie(basicClientCookie);
            }
        }
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
            String newUrl = response.getFirstHeader("Location").getValue();
            httpClientEntity.setUrl(newUrl);
            return httpGetRequest(httpClientEntity);
        } else if (statusCode == HttpStatus.SC_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            String line = null;
            StringBuilder builder = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            result = builder.toString();
        }
        log.info(httpClientEntity.getResult());
        httpClientEntity.setResult(result);
        httpClientEntity.setCookieStore(cookieStore);
        return httpClientEntity;
    }

    public HttpClientEntity httpPostParamRequest(HttpClientEntity httpClientEntity) throws Exception {
        String result = "";
        CookieStore cs = httpClientEntity.getCookieStore();
        if (cs != null) {
            for (Cookie ck : cs.getCookies()) {
                cookieStore.addCookie(ck);
            }
        }

        HttpPost httppost = new HttpPost(httpClientEntity.getUrl());
        for (String key : httpClientEntity.getHeaders().keySet()) {
            httppost.setHeader(key, httpClientEntity.getHeaders().get(key));
        }
        List<NameValuePair> paramList = new ArrayList<NameValuePair>();
        for (String key : httpClientEntity.getParams().keySet()) {
            BasicNameValuePair basicNameValuePair = new BasicNameValuePair(key, String.valueOf(httpClientEntity.getParams().get(key)));
            paramList.add(basicNameValuePair);
        }
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(paramList, "UTF-8");
        httppost.setEntity(formEntity);
        CloseableHttpClient httpClient = httpClientEntity.getCloseableHttpClient();
        HttpResponse response = httpClient.execute(httppost);
        Header[] headers = response.getHeaders("Set-Cookie");
        if (headers != null && headers.length > 0) {
            for (Header header : headers) {
                String[] cookieArr = header.getValue().split(";");
                String[] ck = cookieArr[0].split("=");
                BasicClientCookie basicClientCookie = new BasicClientCookie(ck[0], ck[1]);
                Map<String, String> cookieMap = new HashMap<>();
                if (cookieArr.length > 1) {
                    for (int i = 1; i < cookieArr.length; i++) {
                        String[] ckParam = cookieArr[i].split("=");
                        if (ckParam.length > 1) {
                            cookieMap.put(ckParam[0].trim(), ckParam[1]);
                        }
                    }
                }
                basicClientCookie.setPath(cookieMap.get("Path"));
                if (cookieMap.get("Domain") == null || "".equals(cookieMap.get("Domain"))) {
                    basicClientCookie.setDomain(httpClientEntity.getHeaders().get("Origin").split("//")[1]);
                } else {
                    basicClientCookie.setDomain(cookieMap.get("Domain"));
                }
                basicClientCookie.setExpiryDate(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365));
                cookieStore.addCookie(basicClientCookie);
            }
        }
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
            String newUrl = response.getFirstHeader("Location").getValue();
            httpClientEntity.setUrl(newUrl);
            result = EntityUtils.toString(response.getEntity());
            return httpPostParamRequest(httpClientEntity);
        } else if (statusCode == HttpStatus.SC_OK) {
            result = EntityUtils.toString(response.getEntity());
            log.info(result);
            httpClientEntity.setCloseableHttpClient(httpClient);
        }
        httpClientEntity.setResult(result);
        httpClientEntity.setCookieStore(cookieStore);
        return httpClientEntity;
    }

    public HttpClientEntity callingGraph(HttpClientEntity httpClientEntity, String json) throws Exception {
        CookieStore cs = httpClientEntity.getCookieStore();
        if (cs != null) {
            for (Cookie ck : cs.getCookies()) {
                cookieStore.addCookie(ck);
            }
        }
        HttpClient httpClient = httpClientEntity.getCloseableHttpClient();
        HttpResponse response = null;
        HttpPost httpPost = new HttpPost(httpClientEntity.getUrl());
        for (String key : httpClientEntity.getHeaders().keySet()) {
            httpPost.setHeader(key, httpClientEntity.getHeaders().get(key));
        }
        httpPost.setHeader("Content-Type", "application/json");
        StringEntity entity = new StringEntity(json, "utf-8");
        httpPost.setEntity(entity);
        httpPost.setProtocolVersion(HttpVersion.HTTP_1_0);
        httpPost.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
        response = httpClient.execute(httpPost);
        String result = EntityUtils.toString(response.getEntity(), "utf-8");
        Header[] headers = response.getHeaders("Set-Cookie");
        if (headers != null && headers.length > 0) {
            for (Header header : headers) {
                String[] cookieArr = header.getValue().split(";");
                String[] ck = cookieArr[0].split("=");
                BasicClientCookie basicClientCookie = new BasicClientCookie(ck[0], ck[1]);
                Map<String, String> cookieMap = new HashMap<>();
                if (cookieArr.length > 1) {
                    for (int i = 1; i < cookieArr.length; i++) {
                        String[] ckParam = cookieArr[i].split("=");
                        if (ckParam.length > 1) {
                            cookieMap.put(ckParam[0].trim(), ckParam[1]);
                        }
                    }
                }
                basicClientCookie.setPath(cookieMap.get("Path"));
                if (cookieMap.get("Domain") == null || "".equals(cookieMap.get("Domain"))) {
                    basicClientCookie.setDomain(httpClientEntity.getHeaders().get("Origin").split("//")[1]);
                } else {
                    basicClientCookie.setDomain(cookieMap.get("Domain"));
                }
                basicClientCookie.setExpiryDate(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365));
                cookieStore.addCookie(basicClientCookie);
            }
        }
        httpClientEntity.setResult(result);
        log.info(httpClientEntity.getResult());
        httpClientEntity.setCookieStore(cookieStore);
        return httpClientEntity;
    }
}
