package com.ruoyi.spider.utils;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import okhttp3.*;
import okhttp3.FormBody.Builder;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * HTTP客户端工具类（支持HTTPS）
 */
public class HttpClientUtil {
    private static Logger log = LoggerFactory.getLogger(HttpClientUtil.class);

    public static final String UTF_8 = "UTF-8";
    private static final Map<String, List<Cookie>> cookieStore = new HashMap<>();

    public static void clearCookie(String url) {
        if (StringUtils.isNotBlank(url)) {
            cookieStore.remove(HttpUrl.get(url).host());
        } else {
            cookieStore.clear();
        }
    }

    /**
     * http的get请求
     *
     * @param url
     */
    public static String get(String url) {
        return get(url, UTF_8, null, null);
    }

    public static String get(String url, Dict params) {
        return get(url, UTF_8, params, null);
    }

    /**
     * http的get请求
     *
     * @param url
     */
    public static String get(String url, String charset, Dict params, Headers headers) {
        HttpUrl.Builder builder = HttpUrl.parse(url).newBuilder();
        if (MapUtil.isNotEmpty(params)) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                if (null != entry.getValue()) {
                    builder.addQueryParameter(entry.getKey(), Convert.toStr(entry.getValue()));
                }
            }
        }
        okhttp3.Request.Builder reqBuild = new Request.Builder().url(builder.build()).get();
        if (null != headers) {
            reqBuild.headers(headers);
        }
        return executeRequest(reqBuild.build(), charset);
    }

    /**
     * http的get请求，增加异步请求头参数
     *
     * @param url
     */
    public static String ajaxGet(String url) {
        return ajaxGet(url, UTF_8);
    }

    /**
     * http的get请求，增加异步请求头参数
     *
     * @param url
     */
    public static String ajaxGet(String url, String charset) {
        Request request = new Request.Builder().url(url).get().header("X-Requested-With", "XMLHttpRequest").build();
        return executeRequest(request, charset);
    }

    private static Builder mapToPostBody(Map<String, String> dataMap, String charset) {
        FormBody.Builder body = null;
        if (dataMap != null) {
            body = new FormBody.Builder(Charset.forName(charset));
            for (Map.Entry<String, String> entry : dataMap.entrySet()) {
                if (null != entry.getValue()) {
                    body.add(entry.getKey(), entry.getValue());
                }
            }
        }
        return body;
    }

    /**
     * http的post请求，传递map格式参数
     */
    public static String post(String url, Map<String, String> dataMap) {
        return post(url, dataMap, UTF_8);
    }

    /**
     * http的post请求，传递map格式参数
     */
    public static String post(String url, Map<String, String> dataMap, String charset) {
        Request.Builder build = new Request.Builder().url(url);
        Builder body = mapToPostBody(dataMap, charset);
        if (null != body) {
            build.post(body.build());
        }
        return executeRequest(build.build(), charset);
    }

    public static String post(String url, Dict params, Map<String, String> dataMap, Headers headers) {
        HttpUrl.Builder builder = HttpUrl.parse(url).newBuilder();
        if (MapUtil.isNotEmpty(params)) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                if (null != entry.getValue()) {
                    builder.addQueryParameter(entry.getKey(), Convert.toStr(entry.getValue()));
                }
            }
        }
        okhttp3.Request.Builder reqBuild = new Request.Builder().url(builder.build());
        if (null != headers) {
            reqBuild = reqBuild.headers(headers);
        }
        Builder body = mapToPostBody(dataMap, UTF_8);
        if (null != body) {
            reqBuild = reqBuild.post(body.build());
        }
        return executeRequest(reqBuild.build(), UTF_8);
    }

    /**
     * @param url
     * @param content
     * @param contentType
     * @return
     */
    public static String post(String url, String content, String contentType) {
        RequestBody body = RequestBody.create(MediaType.parse(contentType), content);
        Request request = new Request.Builder().url(url).post(body).build();
        return executeRequest(request, UTF_8);
    }

    /**
     * http的post请求，增加异步请求头参数，传递map格式参数
     */
    public static String ajaxPost(String url, Map<String, String> dataMap) {
        return ajaxPost(url, dataMap, UTF_8);
    }

    /**
     * http的post请求，增加异步请求头参数，传递map格式参数
     */
    public static String ajaxPost(String url, Map<String, String> dataMap, String charset) {
        Request.Builder build = new Request.Builder().url(url).addHeader("X-Requested-With", "XMLHttpRequest");
        Builder body = mapToPostBody(dataMap, charset);
        if (null != body) {
            build.post(body.build());
        }
        return executeRequest(build.build(), charset);
    }

    /**
     * http的post请求，增加异步请求头参数，传递json格式参数
     */
    public static String ajaxPostJson(String url, String jsonString) {
        return ajaxPostJson(url, jsonString, UTF_8);
    }

    public static String ajaxPostJson(String url, JSON json) {
        return ajaxPostJson(url, json.toJSONString(), UTF_8);
    }

    /**
     * http的post请求，增加异步请求头参数，传递json格式参数
     */
    public static String ajaxPostJson(String url, String jsonString, String charset) {
        return ajaxPostJson(url, jsonString, UTF_8, null);
    }

    /**
     * http的post请求，增加异步请求头参数，传递json格式参数
     */
    public static String ajaxPostJson(String url, Dict body, String charset) {
        return ajaxPostJson(url, JSON.toJSONString(body), UTF_8, null);
    }

    /**
     * http的post请求，增加异步请求头参数，传递json格式参数
     */
    public static String ajaxPostJson(String url, String jsonString, String charset, Headers headers) {
        Request.Builder build = new Request.Builder().url(url).addHeader("X-Requested-With", "XMLHttpRequest");
        if (null != headers) {
            build.headers(headers);
        }
        build.post(RequestBody.create(MediaType.parse("application/json"), jsonString));
        return executeRequest(build.build(), charset);
    }

    /**
     * 执行一个http请求，传递HttpGet或HttpPost参数
     */
    public static String executeRequest(Request httpRequest) {
        return executeRequest(httpRequest, UTF_8);
    }

    public static CookieJar cookieJar() {
        return new CookieJar() {

            @Override
            public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                cookieStore.put(url.host(), cookies);
            }

            @Override
            public List<Cookie> loadForRequest(HttpUrl url) {
                List<Cookie> cookies = cookieStore.get(url.host());
                return cookies != null ? cookies : new ArrayList<Cookie>();
            }
        };
    }

    /**
     * 执行一个http请求，传递HttpGet或HttpPost参数
     *
     * @throws Exception
     */
    public static String executeRequest(Request request, String charset) {
        try {
            OkHttpClient okHttpClient = null;
            if (request.isHttps()) {
                SSLContext sc = SSLContext.getInstance("SSL");
                TrustManager[] tm = new TrustManager[]{new TrustAllCerts()};
                sc.init(null, tm, new SecureRandom());
                OkHttpClient.Builder builder = new OkHttpClient.Builder();
                builder.cookieJar(cookieJar());
                builder.sslSocketFactory(sc.getSocketFactory(), (X509TrustManager) tm[0]);
                builder.hostnameVerifier(new TrustAllHostnameVerifier());
                okHttpClient = builder.build();
            } else {
                okHttpClient = new OkHttpClient.Builder().cookieJar(cookieJar()).build();

            }
            Response response = okHttpClient.newCall(request).execute();
//            log.info("response code:{},message:{}", response.code(), response.message());
            if (response.isSuccessful()) {
                Headers headers = response.headers();
                for (int i = 0; i < headers.size(); i++) {
                    log.debug("header:[{}:{}]", headers.name(i), headers.value(i));
                }
                String strResult = IOUtils.toString(response.body().byteStream(), charset);
                log.debug("post result : {}", strResult);
                return strResult;
            }
        } catch (Exception e) {
            log.error("exec failed : {}", e);
            throw new RuntimeException(e);
        }
        return null;

    }

    private static class TrustAllCerts implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    private static class TrustAllHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

}
