package org.wcs.plugin.webHttpClient;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.util.StopWatch;
import org.wcs.plugin.webHttpClient.intef.IHttpRequestEvent;
import org.wcs.plugin.webHttpClient.model.HttpAddressKeyItem;
import org.wcs.plugin.webHttpClient.model.HttpRequest;
import org.wcs.plugin.webHttpClient.model.HttpResponse;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * webApi请求类
 */
public class WebHttpClient {

    /**
     * 存放地址key的map
     */
    private static Map<String, String> addressKeyMap;

    private static List<IHttpRequestEvent> httpRequestEvents;

    /**
     * 设置地址key
     *
     * @param addressKeyList 地址key列表
     */
    public static synchronized void setAddressKey(List<HttpAddressKeyItem> addressKeyList) {
        addressKeyMap = new ConcurrentHashMap<>();
        if(addressKeyList == null) {
            throw new NullPointerException("传入的列表是 NULL (list is null)");
        }
        for (HttpAddressKeyItem item : addressKeyList) {
            if(item.getFatherKey() == null || item.getFatherKey().isEmpty()) {
                addressKeyMap.put(item.getKey(), item.getAddress());
                continue;
            }
            List<HttpAddressKeyItem> list = addressKeyList.stream().filter(item1 -> item1.getKey().equals(item.getFatherKey())).toList();
            if(list.isEmpty()) {
                addressKeyMap.put(item.getKey(), item.getAddress());
                continue;
            }
            addressKeyMap.put(item.getKey(), list.getFirst().getAddress() + item.getAddress());
        }
    }

    /**
     * 注册请求事件
     * @param event 请求事件
     */
    public static void registerHttpRequestEvent(IHttpRequestEvent event) {
        if(httpRequestEvents == null) {
            httpRequestEvents = new java.util.ArrayList<>();
        }
        httpRequestEvents.add(event);
    }

    /**
     * 请求调用
     * @param request 请求参数
     * @return 请求结果
     */
    public static HttpResponse httpRequest(HttpRequest request) {
        if(request == null) {
            return new HttpResponse(true, "请求参数不能为空", null);
        }
        if(request.getUrl() == null && request.getAddressKey() == null) {
            return new HttpResponse(true, "请求地址不能为空", null);
        }
        if(request.getMethod().equalsIgnoreCase("get")) {
            return httpGet(request);
        }
        if(request.getMethod().equalsIgnoreCase("post")) {
            return httpPost(request);
        }
        if(request.getMethod().equalsIgnoreCase("put")) {
            return httpPut(request);
        }
        if(request.getMethod().equalsIgnoreCase("delete")) {
            return httpDelete(request);
        }
        return new HttpResponse(true, "请求方法错误或者不支持的方法", request);
    }

    /**
     * get请求
     * @param request 请求对象
     * @return HttpResponse
     */
    private static HttpResponse httpGet(HttpRequest request) {
        HttpResponse response = new HttpResponse();
        response.setMethod("GET");
        response.setRequest(request);
        /* 构造URL */
        String url = request.getUrl();
        if(url == null) {
            url = addressKeyMap.get(request.getAddressKey());
        }
        response.setUrl(url);
        if(url == null) {
            response.setBaseDataError(true);
            response.setErrText("地址错误或者未配置");
            return response;
        }
        /* 构造 查询参数 */
        StringBuilder paramStringBuilder = new StringBuilder();
        Map<String, String> params = request.getParams();
        if(params != null && !params.isEmpty()) {
            paramStringBuilder.append("?");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                paramStringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            paramStringBuilder.deleteCharAt(paramStringBuilder.length() - 1);
        }
        response.setBaseDataError(false);
        try {
            HttpGet getRequest = new HttpGet(url + paramStringBuilder);
            /* 构造 Header */
            Map<String, String> headers = request.getHeaders();
            if(headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    getRequest.addHeader(entry.getKey(), entry.getValue());
                }
            }
            /* 设置请求类型 */
            if(request.getContentType() != null) {
                getRequest.setHeader("Content-Type", request.getContentType());
            }
            /* 设置超时时间 */
            getRequest.setConfig(RequestConfig.custom()
                    .setConnectionRequestTimeout(request.getTimeout())
                    .setConnectTimeout(request.getTimeout())
                    .setSocketTimeout(request.getTimeout()).build());
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.beforeRequest(request);
                    }
                }
            });
            /* 发送请求 */
            StopWatch watch = new StopWatch();
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            response.setRequestTime(LocalDateTime.now());
            watch.start();
            CloseableHttpResponse getResponse = httpClient.execute(getRequest);
            watch.stop();
            response.setResponseTime(LocalDateTime.now());
            response.setUseTime(watch.getTotalTimeMillis());
            response.setResponseCode(getResponse.getStatusLine().getStatusCode());
            BufferedReader reader = new BufferedReader(new InputStreamReader(getResponse.getEntity().getContent()));
            String line;
            StringBuilder result = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
            reader.close();
            httpClient.close();
            response.setSuccess(true);
            response.setResponseText(result.toString());
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.afterRequest(request, response);
                    }
                }
            });
            return response;
        } catch (Exception e) {
            response.setSuccess(false);
            response.setException(e);
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.afterRequest(request, response);
                    }
                }
            });
            return response;
        }
    }

    /**
     * post请求
     * @param request 请求对象
     * @return HttpResponse
     */
    private static HttpResponse httpPost(HttpRequest request) {
        HttpResponse response = new HttpResponse();
        response.setMethod("POST");
        response.setRequest(request);
        response.setRequestText(request.getBody());
        /* 构造URL */
        String url = request.getUrl();
        if(url == null) {
            url = addressKeyMap.get(request.getAddressKey());
        }
        response.setUrl(url);
        if(url == null) {
            response.setBaseDataError(true);
            response.setErrText("地址错误或者未配置");
            return response;
        }
        /* 构造 查询参数 */
        StringBuilder paramStringBuilder = new StringBuilder();
        Map<String, String> params = request.getParams();
        if(params != null && !params.isEmpty()) {
            paramStringBuilder.append("?");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                paramStringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            paramStringBuilder.deleteCharAt(paramStringBuilder.length() - 1);
        }
        response.setBaseDataError(false);
        try {
            HttpPost postRequest = new HttpPost(url + paramStringBuilder);
            /* 构造 Header */
            Map<String, String> headers = request.getHeaders();
            if(headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    postRequest.addHeader(entry.getKey(), entry.getValue());
                }
            }
            /* 设置请求类型 */
            if(request.getContentType() != null) {
                postRequest.setHeader("Content-Type", request.getContentType());
            }
            /* 设置超时时间 */
            postRequest.setConfig(RequestConfig.custom()
                    .setConnectionRequestTimeout(request.getTimeout())
                    .setConnectTimeout(request.getTimeout())
                    .setSocketTimeout(request.getTimeout()).build());
            /* 设置请求体 */
            if (request.getBody() != null) {
                postRequest.setEntity(new StringEntity(request.getBody(), request.getCharset()));
            }
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.beforeRequest(request);
                    }
                }
            });
            /* 发送请求 */
            StopWatch watch = new StopWatch();
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            response.setRequestTime(LocalDateTime.now());
            watch.start();
            CloseableHttpResponse getResponse = httpClient.execute(postRequest);
            watch.stop();
            response.setResponseTime(LocalDateTime.now());
            response.setUseTime(watch.getTotalTimeMillis());
            response.setResponseCode(getResponse.getStatusLine().getStatusCode());
            BufferedReader reader = new BufferedReader(new InputStreamReader(getResponse.getEntity().getContent()));
            String line;
            StringBuilder result = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
            reader.close();
            httpClient.close();
            response.setSuccess(true);
            response.setResponseText(result.toString());
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.afterRequest(request, response);
                    }
                }
            });
            return response;
        } catch (Exception e) {
            response.setSuccess(false);
            response.setException(e);
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.afterRequest(request, response);
                    }
                }
            });
            return response;
        }
    }

    /**
     * put请求
     * @param request 请求对象
     * @return HttpResponse
     */
    private static HttpResponse httpPut(HttpRequest request) {
        HttpResponse response = new HttpResponse();
        response.setMethod("PUT");
        response.setRequest(request);
        /* 构造URL */
        String url = request.getUrl();
        if(url == null) {
            url = addressKeyMap.get(request.getAddressKey());
        }
        response.setUrl(url);
        if(url == null) {
            response.setBaseDataError(true);
            response.setErrText("地址错误或者未配置");
            return response;
        }
        /* 构造 查询参数 */
        StringBuilder paramStringBuilder = new StringBuilder();
        Map<String, String> params = request.getParams();
        if(params != null && !params.isEmpty()) {
            paramStringBuilder.append("?");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                paramStringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            paramStringBuilder.deleteCharAt(paramStringBuilder.length() - 1);
        }
        response.setBaseDataError(false);
        try {
            HttpPut putRequest = new HttpPut(url + paramStringBuilder);
            /* 构造 Header */
            Map<String, String> headers = request.getHeaders();
            if(headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    putRequest.addHeader(entry.getKey(), entry.getValue());
                }
            }
            /* 设置请求类型 */
            if(request.getContentType() != null) {
                putRequest.setHeader("Content-Type", request.getContentType());
            }
            /* 设置超时时间 */
            putRequest.setConfig(RequestConfig.custom()
                    .setConnectionRequestTimeout(request.getTimeout())
                    .setConnectTimeout(request.getTimeout())
                    .setSocketTimeout(request.getTimeout()).build());
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.beforeRequest(request);
                    }
                }
            });
            /* 发送请求 */
            StopWatch watch = new StopWatch();
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            response.setRequestTime(LocalDateTime.now());
            watch.start();
            CloseableHttpResponse getResponse = httpClient.execute(putRequest);
            watch.stop();
            response.setResponseTime(LocalDateTime.now());
            response.setUseTime(watch.getTotalTimeMillis());
            response.setResponseCode(getResponse.getStatusLine().getStatusCode());
            BufferedReader reader = new BufferedReader(new InputStreamReader(getResponse.getEntity().getContent()));
            String line;
            StringBuilder result = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
            reader.close();
            httpClient.close();
            response.setSuccess(true);
            response.setResponseText(result.toString());
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.afterRequest(request, response);
                    }
                }
            });
            return response;
        } catch (Exception e) {
            response.setSuccess(false);
            response.setException(e);
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.afterRequest(request, response);
                    }
                }
            });
            return response;
        }
    }

    /**
     * delete请求
     * @param request 请求对象
     * @return HttpResponse
     */
    private static HttpResponse httpDelete(HttpRequest request) {
        HttpResponse response = new HttpResponse();
        response.setMethod("DELETE");
        response.setRequest(request);
        /* 构造URL */
        String url = request.getUrl();
        if(url == null) {
            url = addressKeyMap.get(request.getAddressKey());
        }
        response.setUrl(url);
        if(url == null) {
            response.setBaseDataError(true);
            response.setErrText("地址错误或者未配置");
            return response;
        }
        /* 构造 查询参数 */
        StringBuilder paramStringBuilder = new StringBuilder();
        Map<String, String> params = request.getParams();
        if(params != null && !params.isEmpty()) {
            paramStringBuilder.append("?");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                paramStringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            paramStringBuilder.deleteCharAt(paramStringBuilder.length() - 1);
        }
        response.setBaseDataError(false);
        try {
            HttpDelete deleteRequest = new HttpDelete(url + paramStringBuilder);
            /* 构造 Header */
            Map<String, String> headers = request.getHeaders();
            if(headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    deleteRequest.addHeader(entry.getKey(), entry.getValue());
                }
            }
            /* 设置请求类型 */
            if(request.getContentType() != null) {
                deleteRequest.setHeader("Content-Type", request.getContentType());
            }
            /* 设置超时时间 */
            deleteRequest.setConfig(RequestConfig.custom()
                    .setConnectionRequestTimeout(request.getTimeout())
                    .setConnectTimeout(request.getTimeout())
                    .setSocketTimeout(request.getTimeout()).build());
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.beforeRequest(request);
                    }
                }
            });
            /* 发送请求 */
            StopWatch watch = new StopWatch();
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            response.setRequestTime(LocalDateTime.now());
            watch.start();
            CloseableHttpResponse getResponse = httpClient.execute(deleteRequest);
            watch.stop();
            response.setResponseTime(LocalDateTime.now());
            response.setUseTime(watch.getTotalTimeMillis());
            response.setResponseCode(getResponse.getStatusLine().getStatusCode());
            BufferedReader reader = new BufferedReader(new InputStreamReader(getResponse.getEntity().getContent()));
            String line;
            StringBuilder result = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
            reader.close();
            httpClient.close();
            response.setSuccess(true);
            response.setResponseText(result.toString());
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.afterRequest(request, response);
                    }
                }
            });
            return response;
        } catch (Exception e) {
            response.setSuccess(false);
            response.setException(e);
            Thread.ofVirtual().start(() -> {
                if(httpRequestEvents != null) {
                    for (IHttpRequestEvent event : httpRequestEvents) {
                        event.afterRequest(request, response);
                    }
                }
            });
            return response;
        }
    }




}
