package com.xiaomai.cases.polar.utils;

import com.alibaba.fastjson.JSONObject;
import com.xiaomai.cases.polar.utils.Entity.SignatureVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.log4j.Logger;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Random;

/**
 * @Author zxy
 * @Description
 * @Date 2024/7/3 10:31
 */
@Slf4j
public class ResourceUtil {
    public static final Logger logger = Logger.getLogger(ResourceUtil.class);


    public static final String OSS_ACCESS_KEY_ID = "q-ak";
    public static final String POLICY = "policy";
    public static final String SIGNATURE = "q-signature";
    public static final String KEY = "key";
    public static final String SUCCESS_ACTION_STATUS = "success_action_status";
    public static final String FILE = "file";
    public static final String CALL_BACK = "x-cos-callback";
    public static final String EXT_ATTRS = "q-key-time";
    public static final String RESPONSE_STATUS = "200";
    public static final String CONTENT_TYPE = "multipart/form-data";


    /**
     * 上传文件留到阿里云oss
     *
     * @param inputStream 文件流
     * @param fileName 文件名称
     * @param signatureVO 临时访问阿里云授权签名
     * @return true 上传成功,false 失败
     * @throws IOException 关闭文件流或httpClient连接时可能会异常
     */
    public static boolean uploadFile(InputStream inputStream, String fileName,
                                     SignatureVO signatureVO, int timeout) throws IOException {
        CloseableHttpClient client = HttpClients.createDefault();

        RequestConfig requestConfig = RequestConfig.custom()
                //connectTimeout：指客户端和服务器建立连接的timeout，
                .setConnectTimeout(2000)
                //connectionRequestTimout：指从连接池获取连接的timeout
                .setConnectionRequestTimeout(2000)
                //socketTimeout：指客户端从服务器读取数据的timeout，超出后会抛出SocketTimeOutException,根据需要自定义
                .setSocketTimeout(timeout)
                .build();
        HttpPost post = new HttpPost(signatureVO.getHost());
        post.setConfig(requestConfig);
        BufferedReader br = null;
        try {

            // 参数顺序问题,该死的回调,千万要注意参数的顺序,死坑死坑
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

            StringBody algorithm = new StringBody(signatureVO.getAlgorithm(),
                    ContentType.APPLICATION_JSON);
            builder.addPart("q-sign-algorithm",algorithm);

            // 兼容key中的中文名称
            StringBody key = new StringBody(signatureVO.getKey(),
                    ContentType.APPLICATION_JSON);
            builder.addPart(KEY, key);
            StringBody accessKeyId = new StringBody(signatureVO.getAccessId(),
                    ContentType.MULTIPART_FORM_DATA);
            builder.addPart(OSS_ACCESS_KEY_ID, accessKeyId);

            StringBody policy = new StringBody(signatureVO.getPolicy(),
                    ContentType.MULTIPART_FORM_DATA);
            builder.addPart(POLICY, policy);

            StringBody signature = new StringBody(signatureVO.getSignature(),
                    ContentType.MULTIPART_FORM_DATA);
            builder.addPart(SIGNATURE, signature);

            StringBody successActionStatus = new StringBody(RESPONSE_STATUS,
                    ContentType.MULTIPART_FORM_DATA);
            builder.addPart(SUCCESS_ACTION_STATUS, successActionStatus);

            StringBody callBackStr = new StringBody(signatureVO.getCallback(),
                    ContentType.MULTIPART_FORM_DATA);
            builder.addPart(CALL_BACK, callBackStr);

            StringBody extAttrs = new StringBody(signatureVO.getExtAttrs(),
                    ContentType.MULTIPART_FORM_DATA);
            System.out.println("------------------"+extAttrs.toString());
            builder.addPart(EXT_ATTRS, extAttrs);


            builder.addBinaryBody(FILE, inputStream, ContentType.create(CONTENT_TYPE), fileName);




            HttpEntity entity = builder.build();
            post.setEntity(entity);

            //发送请求
            HttpResponse response = client.execute(post);
            int status = response.getStatusLine().getStatusCode();
            if (Integer.valueOf(RESPONSE_STATUS).equals(status)) {
                return true;
            } else {
                entity = response.getEntity();
                if (entity != null) {
                    inputStream = entity.getContent();
                    br = new BufferedReader(new InputStreamReader(inputStream, Consts.UTF_8));
                    StringBuilder message = new StringBuilder();
                    String body;
                    while ((body = br.readLine()) != null) {
                        message.append(body);
                    }
                    logger.error("文件上传失败!message:{}"+message);
                }
                return true;
            }
        } catch (Exception e) {
            logger.error("文件上传异常!", e);
        } finally {
            if (br != null){
                br.close();
            }
            inputStream.close();
            client.close();
        }
        return false;
    }

    public static boolean uploadFileContentToTencent(InputStream inputStream, String fileName, SignatureVO signatureVO, int timeout, String contentType) throws IOException {

        String boundary = generateBoundary();

        // 设置表单的body字段值
        JSONObject formFields = new JSONObject();
        formFields.put("q-sign-algorithm", "sha1");
        formFields.put("key", signatureVO.getKey());
        formFields.put("q-ak", signatureVO.getAccessId());
        formFields.put("policy", signatureVO.getPolicy());
        formFields.put("q-signature", signatureVO.getSignature());
        formFields.put("success_action_status", RESPONSE_STATUS);
        formFields.put("x-cos-callback", signatureVO.getCallback());
        formFields.put("x-cos-security-token", signatureVO.getSecurityToken());
        formFields.put("q-key-time", signatureVO.getExtAttrs());

        // 根据以上表单参数，构造最开始的body部分
        String formBody = buildPostObjectBody(boundary, formFields, fileName, contentType);
        HttpURLConnection conn = null;
        try {
            String urlStr = signatureVO.getHost();
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            conn.setDoOutput(true);
            conn.setDoInput(true);

            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // 写入表单的最开始部分
            out.write(formBody.getBytes());
            // 将文件内容写入到输出流中
            int readBytes;
            byte[] bytes = new byte[4096];
            while ((readBytes = inputStream.read(bytes)) != -1) {
                out.write(bytes, 0, readBytes);
            }
            inputStream.close();
            // 添加最后一个分割符，行首和行尾都是--
            byte[] endData = ("\r\n--" + boundary + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();
            // 读取响应头部
            if (Integer.valueOf(RESPONSE_STATUS).equals(conn.getResponseCode())) {
                return true;
            } else {
                log.error("文件上传失败!message:{}",conn.getResponseCode());
            }
            return true;
        } catch (Exception e) {
            log.error("文件上传异常!", e);
            return false;
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
            inputStream.close();
        }
    }
    private final static char[] MULTIPART_CHARS =
            "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    .toCharArray();
    private static String generateBoundary() {
        final StringBuilder buffer = new StringBuilder();
        final Random rand = new Random();
        final int count = rand.nextInt(11) + 30; // a random size from 30 to 40
        for (int i = 0; i < count; i++) {
            buffer.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
        }
        return buffer.toString();
    }
    static String buildPostObjectBody(String boundary, JSONObject formFields,
                                      String filename,
                                      String contentType) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String,Object> entry : formFields.entrySet()) {
            // 添加boundary行,行首以--开头
            sb.append("--").append(boundary).append("\r\n");
            // 字段名
            sb.append("Content-Disposition: form-data; name=\"").append(entry.getKey())
                    .append("\"\r\n\r\n");
            // 字段值
            sb.append(entry.getValue()).append("\r\n");
        }
        // 添加boundary行,行首以--开头
        sb.append("--").append(boundary).append("\r\n");
        // 文件名
        sb.append("Content-Disposition: form-data; name=\"file\"; " + "filename=\"").append(filename)
                .append("\"\r\n");
        // 文件类型
        sb.append("Content-Type: ").append(contentType).append("\r\n\r\n");
        return sb.toString();
    }
}
