package com.ruoyi.common.utils.http;

import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
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.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.springframework.http.MediaType;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * HttpClient工具类
 *
 * @author: xingxixingzhe
 * @date: 2023/9/25 14:18
 */
@Slf4j
public class HttpClientUtil {

    public static final String HTTP_CHARSET = "utf-8";
    private static final String CONTENTTYPE = "Content-Type";

    /**
     * get请求
     *
     * @param url     请求地址
     * @param headers 请求头，可以为null
     * @return String
     */
    public static String doGet(String url, Map<String, String> headers) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        log.info("request param info : {}", url);
        log.info("request header info : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpGet get = new HttpGet(url);
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        get.addHeader(key, headers.get(key));
                    });
                }
                response = httpClient.execute(get);
                String result = EntityUtils.toString(response.getEntity(), Charset.forName(HTTP_CHARSET));
                log.info("response info : {}", result);
                return result;
            } catch (IOException e) {
                log.error("get链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("get关闭response失败：" + e.getMessage());
        }
        return null;
    }

    /**
     * get请求
     *
     * @param url      请求地址
     * @param headers  请求头，可以为null
     * @param paramMap 请求参数
     * @return String
     */
    public static String doGetQueryParams(String url, Map<String, String> headers, Map<String, Object> paramMap) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        StringBuilder urlTemp = new StringBuilder(url);
        if (null != paramMap && paramMap.size() > 0) {
            int index = 0;
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                if (index == 0) {
                    urlTemp.append("?").append(entry.getKey()).append("=").append(entry.getValue());
                } else {
                    urlTemp.append("&").append(entry.getKey()).append("=").append(entry.getValue());
                }
                index++;
            }
        }
        url = urlTemp.toString();
        log.info("request param info : {}", url);
        log.info("request header info : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpGet get = new HttpGet(url);
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        get.addHeader(key, headers.get(key));
                    });
                }
                response = httpClient.execute(get);
                String result = EntityUtils.toString(response.getEntity(), Charset.forName(HTTP_CHARSET));
                log.info("response info : {}", result);
                return result;
            } catch (IOException e) {
                log.error("get链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("get关闭response失败：" + e.getMessage());
        }
        return null;
    }

    /**
     * get请求 下载文件保存在本地
     *
     * @param url          请求地址
     * @param headers      请求头，可以为null
     * @param downloadPath 下载地址
     * @return String
     */
    public static String doGetDownloadSaveLocal(String url, Map<String, String> headers, String downloadPath) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        log.info("request param info : {}", url);
        log.info("request header info : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpGet get = new HttpGet(url);
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        get.addHeader(key, headers.get(key));
                    });
                }
                response = httpClient.execute(get);
                // 获取下载文件流
                InputStream inputStream = response.getEntity().getContent();
                // 获取下载文件的文件名，此处的 File-Name 头信息，需要在服务端进行自定义
                Header header = response.getFirstHeader("Content-Disposition");
                String fileName = header.getValue();
                fileName = StringUtils.substringAfter(fileName, "=");
                fileName = System.currentTimeMillis() + fileName;
                log.info("下载的文件名称:" + fileName);
                File file = new File(downloadPath + fileName);
                file.getParentFile().mkdirs();
                FileOutputStream fileOut = new FileOutputStream(file);
                byte[] buffer = new byte[2048];
                int ch = 0;
                while ((ch = inputStream.read(buffer)) != -1) {
                    fileOut.write(buffer, 0, ch);
                }
                inputStream.close();
                fileOut.flush();
                fileOut.close();
                return file.getPath();
            } catch (IOException e) {
                log.error("get链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("get关闭response失败：" + e.getMessage());
        }

        return null;
    }

    /**
     * get请求 带时间配置请求
     *
     * @param url                      请求地址
     * @param headers                  请求头，可以为null
     * @param connectTimeout           连接超时时间
     * @param connectionRequestTimeout 建立连接超时时间，
     * @param socketTimeout            读取数据超时时间
     * @return String
     */
    public static String doGet(String url, Map<String, String> headers,
                               int connectTimeout, int connectionRequestTimeout, int socketTimeout) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        log.info("request param info : {}", url);
        log.info("request header info : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpGet get = new HttpGet(url);
                get.setConfig(RequestConfig.custom()
                        .setConnectTimeout(connectTimeout)
                        .setConnectionRequestTimeout(connectionRequestTimeout)
                        .setSocketTimeout(socketTimeout).build());
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        get.addHeader(key, headers.get(key));
                    });
                }
                response = httpClient.execute(get);
                String result = EntityUtils.toString(response.getEntity(), Charset.forName(HTTP_CHARSET));
                log.info("response info : {}", result);
                return result;
            } catch (IOException e) {
                log.error("get链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("get关闭response失败：" + e.getMessage());
        }
        return null;
    }

    /**
     * post请求 body为json 带时间配置请求
     *
     * @param url                      请求地址
     * @param headers                  请求头，可以为null
     * @param body                     json请求体
     * @param connectTimeout           连接超时时间
     * @param connectionRequestTimeout 建立连接超时时间，
     * @param socketTimeout            读取数据超时时间
     * @return String
     * @author: lll
     * @date: 2022年11月21日 14:11:49
     */
    public static String doPost(String url, Map<String, String> headers, String body,
                                int connectTimeout, int connectionRequestTimeout, int socketTimeout) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        log.info("request param info : {}", body);
        log.info("request header info : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpPost post = new HttpPost(url);
                post.setConfig(RequestConfig.custom()
                        .setConnectTimeout(connectTimeout)
                        .setConnectionRequestTimeout(connectionRequestTimeout)
                        .setSocketTimeout(socketTimeout)
                        .build());
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        post.addHeader(key, headers.get(key));
                    });
                }
                post.addHeader(HTTP.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
                // 封装请求体
                if (StringUtils.isNotBlank(body)) {
                    // 请求体主要封装在HttpEntity中
                    post.setEntity(new StringEntity(body, Charset.forName(HTTP_CHARSET)));
                }

                response = httpClient.execute(post);
                // 处理响应
                String result = EntityUtils.toString(response.getEntity(), Charset.forName(HTTP_CHARSET));
                log.info("response info : {}", result);
                return result;
            } catch (IOException e) {
                log.error("post链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("post关闭response失败：" + e.getMessage());
        }
        return null;
    }

    /**
     * post请求 body为json
     *
     * @param url     请求地址
     * @param headers 请求头，可以为null
     * @param body    json请求体
     * @return String
     */
    public static String doPost(String url, Map<String, String> headers, String body) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        log.info("request header url : {}", url);
        log.info("request param body : {}", body);
        log.info("request header headers : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpPost post = new HttpPost(url);
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        post.addHeader(key, headers.get(key));
                    });
                }
                post.addHeader(HTTP.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
                // 封装请求体
                if (StringUtils.isNotBlank(body)) {
                    // 请求体主要封装在HttpEntity中
                    post.setEntity(new StringEntity(body, Charset.forName(HTTP_CHARSET)));
                }

                response = httpClient.execute(post);
                // 处理响应
                String result = EntityUtils.toString(response.getEntity(), Charset.forName(HTTP_CHARSET));
                log.info("response result : {}", result);
                return result;
            } catch (IOException e) {
                log.error("post链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("post关闭response失败：" + e.getMessage());
        }
        return null;
    }

    /**
     * post请求 body为form
     * <p>
     * post请求 body为json 带时间配置请求
     *
     * @param url     请求地址
     * @param headers 请求头，可以为null
     * @param body    form请求体
     * @return String
     */
    public static String doPost(String url, Map<String, String> headers, Map<String, Object> body,
                                int connectTimeout, int connectionRequestTimeout, int socketTimeout) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        log.info("request param info : {}", body);
        log.info("request header info : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpPost post = new HttpPost(url);
                post.setConfig(RequestConfig.custom().setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).build());
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        post.addHeader(key, headers.get(key));
                    });
                }
                // 封装请求体
                List<NameValuePair> nvpList = new ArrayList<>();
                for (String name : body.keySet()) {
                    String value = String.valueOf(body.get(name));
                    nvpList.add(new BasicNameValuePair(name, value));
                }
                post.setEntity(new UrlEncodedFormEntity(nvpList));

                response = httpClient.execute(post);
                // 处理响应
                String result = EntityUtils.toString(response.getEntity(), Charset.forName(HTTP_CHARSET));
                log.info("response info : {}", result);
                return result;
            } catch (IOException e) {
                log.error("post链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("post关闭response失败：" + e.getMessage());
        }
        return null;
    }

    /**
     * post请求 body为form
     * <p>
     *
     * @param url     请求地址
     * @param headers 请求头，可以为null
     * @param body    json请求体
     * @return String
     */
    public static String doPost(String url, Map<String, String> headers, Map<String, Object> body) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        log.info("request param info : {}", body);
        log.info("request header info : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpPost post = new HttpPost(url);
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        post.addHeader(key, headers.get(key));
                    });
                }
                // 封装请求体
                List<NameValuePair> nvpList = new ArrayList<>();
                for (String name : body.keySet()) {
                    String value = String.valueOf(body.get(name));
                    nvpList.add(new BasicNameValuePair(name, value));
                }
                post.setEntity(new UrlEncodedFormEntity(nvpList,HTTP_CHARSET));

                response = httpClient.execute(post);
                // 处理响应
                String result = EntityUtils.toString(response.getEntity(), Charset.forName(HTTP_CHARSET));
                log.info("response info : {}", result);
                return result;
            } catch (IOException e) {
                log.error("post链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("post关闭response失败：" + e.getMessage());
        }
        return null;
    }

    /**
     * delete请求
     *
     * @param url     请求地址
     * @param headers 请求头，可以为null
     * @return String
     */
    public static String doDelete(String url, Map<String, String> headers) {
        // 创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建HttpResponse对象
        CloseableHttpResponse response = null;
        log.info("request param info : {}", url);
        log.info("request header info : {}", headers);
        try {
            try {
                // 创建HttpPost对象
                HttpDelete delete = new HttpDelete(url);
                // 封装请求头
                if (null != headers) {
                    headers.keySet().forEach(key -> {
                        delete.addHeader(key, headers.get(key));
                    });
                }
                response = httpClient.execute(delete);
                String result = EntityUtils.toString(response.getEntity(), Charset.forName(HTTP_CHARSET));
                log.info("response info : {}", result);
                return result;
            } catch (IOException e) {
                log.error("delete链接失败：" + e.getMessage());
            } finally {
                // 释放连接
                if (response != null) {
                    response.close();
                }
            }
        } catch (IOException e) {
            log.error("delete关闭response失败：" + e.getMessage());
        }
        return null;
    }

}
