package com.friday.executor.common.rest;


import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.http.HttpMethod;

import java.io.*;
import java.util.Map;
import java.util.Objects;

/**
 * @Author YaoYao
 * @Date Created In 11:55 2022/12/20
 * @Description OKHttp客户端
 * @Modified By
 */
@Component
@Slf4j
public class OkHttpService {

    @Autowired
    private OkHttpClient okHttpClient;

    private static final MediaType BODY_JSON = MediaType.parse("application/json; charset=utf-8");
    private static final MediaType FORM_DATA = MediaType.parse("application/octet-stream");

    public FridayHttpResponse doRequest(String method, String url, Map<String, Object> headers, String requestBody) {
        FridayHttpResponse response;
        if(HttpMethod.GET.matches(method)){
            response = syncGet(url, headers);
        } else if(HttpMethod.POST.matches(method)){
            response = syncPost(url, headers, requestBody);
        } else if(HttpMethod.PUT.matches(method)){
            response = syncPut(url, headers, requestBody);
        } else if(HttpMethod.DELETE.matches(method)){
            response = syncDelete(url, headers, requestBody);
        } else if(HttpMethod.PATCH.matches(method)){
            response = syncPatch(url, headers, requestBody);
        } else {
            return FridayHttpResponse.builder()
                    .success(false)
                    .message("不支持的请求类型")
                    .build();
        }
        return response;
    }

    public FridayHttpResponse doFormRequest(String url, Map<String, Object> headers, File file, String fileKey) {
        return syncPostFile(url, headers, file, fileKey);
    }

    private FridayHttpResponse syncGet(String url, Map<String, Object> headerMap) {
        Request request = buildGetRequest(url, headerMap);
        return curl(request);
    }

    public FridayHttpResponse syncDownload(String url, Map<String, Object> headerMap, String destFileDir, String destFileName) {
        Request request = buildGetRequest(url, headerMap);
        return curlDownload(request, destFileDir, destFileName);
    }

    private Request buildGetRequest(String url, Map<String, Object> headerMap) {
        Request request;
        final Request.Builder builder = new Request.Builder().url(url);
        if (!CollectionUtils.isEmpty(headerMap)) {
            for (String headerKey : headerMap.keySet()) {
                builder.addHeader(headerKey, (String) headerMap.get(headerKey));
            }
        }
        request = builder.build();
        return request;
    }


    private FridayHttpResponse syncPost(String url, Map<String, Object> headerMap, String requestBody) {
        return curlSyncPost(url, headerMap, RequestBody.create(BODY_JSON, requestBody));
    }

    private FridayHttpResponse syncPostFile(String url, Map<String, Object> headerMap, File file, String fileKey) {
        RequestBody fileBody = RequestBody.create(FORM_DATA, file);
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(fileKey, file.getName(), fileBody)
                .build();
        return curlSyncPost(url, headerMap, requestBody);
    }

    private FridayHttpResponse curlSyncPost(String url, Map<String, Object> headerMap, RequestBody requestBody) {
        Request request;
        final Request.Builder builder = new Request.Builder()
                .url(url)
                .post(requestBody);
        if (!CollectionUtils.isEmpty(headerMap)) {
            for (String headerKey : headerMap.keySet()) {
                builder.addHeader(headerKey, (String) headerMap.get(headerKey));
            }
        }
        request = builder.build();
        return curl(request);
    }

    private FridayHttpResponse syncPut(String url, Map<String, Object> headerMap, String requestBody) {
        RequestBody body = RequestBody.create(BODY_JSON, requestBody);
        Request request;
        final Request.Builder builder = new Request.Builder()
                .url(url)
                .put(body);
        if (!CollectionUtils.isEmpty(headerMap)) {
            for (String headerKey : headerMap.keySet()) {
                builder.addHeader(headerKey, (String) headerMap.get(headerKey));
            }
        }
        request = builder.build();
        return curl(request);
    }

    private FridayHttpResponse syncDelete(String url, Map<String, Object> headerMap, String requestBody) {
        RequestBody body = RequestBody.create(BODY_JSON, requestBody);
        Request request;
        final Request.Builder builder = new Request.Builder()
                .url(url)
                .delete(body);
        if (!CollectionUtils.isEmpty(headerMap)) {
            for (String headerKey : headerMap.keySet()) {
                builder.addHeader(headerKey, (String) headerMap.get(headerKey));
            }
        }
        request = builder.build();
        return curl(request);
    }

    private FridayHttpResponse syncPatch(String url, Map<String, Object> headerMap, String requestBody) {
        RequestBody body = RequestBody.create(BODY_JSON, requestBody);
        Request request;
        final Request.Builder builder = new Request.Builder()
                .url(url)
                .patch(body);
        if (!CollectionUtils.isEmpty(headerMap)) {
            for (String headerKey : headerMap.keySet()) {
                builder.addHeader(headerKey, (String) headerMap.get(headerKey));
            }
        }
        request = builder.build();
        return curl(request);
    }

    private FridayHttpResponse curl(Request request){
        FridayHttpResponse taieHttpResponse = FridayHttpResponse.builder().success(false).build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            if(Objects.nonNull(response)){
                taieHttpResponse.setHttpRetCode(response.code());
                taieHttpResponse.setMessage(response.message());
                taieHttpResponse.setSuccess(response.isSuccessful());
                if(response.isSuccessful() && Objects.nonNull(response.body())){
                    taieHttpResponse.setResult(response.body().string());
                } else if(Objects.nonNull(response.body())){
                    InputStream inputStream = response.body().source().inputStream();
                    ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int len;
                    while((len = inputStream.read(buffer)) != -1){
                        bytesOut.write(buffer, 0, len);
                    }
                    taieHttpResponse.setResult(bytesOut.toString());
                    bytesOut.close();
                    inputStream.close();
                }
            } else {
                taieHttpResponse.setMessage("http请求返回体为空");
            }
        } catch (Exception e) {
            log.error("http请求异常", e);
            taieHttpResponse.setMessage(e.getMessage());
        }
        return taieHttpResponse;
    }

    public FridayHttpResponse curlDownload(Request request, final String destFileDir, final String destFileName) {
        FridayHttpResponse taieHttpResponse = FridayHttpResponse.builder().success(false).build();
        // 异步请求
        Response response;
        InputStream is = null;
        byte[] buf = new byte[4096];
        int len = 0;
        FileOutputStream fos = null;
        try {
            response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                // 储存下载文件的目录
                File dir = new File(destFileDir);
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                File file = new File(dir, destFileName);
                is = response.body().byteStream();
                fos = new FileOutputStream(file);
                int size;
                long total = response.body().contentLength();
                while ((size = is.read(buf)) != -1) {
                    len += size;
                    fos.write(buf, 0, size);
                    int process = (int) Math.floor(((double) len / total) * 100);
                    log.info("下载进度" + process);
                }
                fos.flush();
                taieHttpResponse.setSuccess(true);
            } else {
                taieHttpResponse.setMessage(response.message());
            }
        } catch (IOException e) {
            log.error("OKHttp下载文件异常", e);
            taieHttpResponse.setMessage(e.getMessage());
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return taieHttpResponse;
    }
}
