package net.northking.cctp.se.util;

import cn.hutool.core.io.IoUtil;
import net.northking.cctp.common.http.ResultWrapper;
import net.northking.cctp.element.core.exception.ExecuteException;
import net.northking.cctp.se.config.AtuServerConfig;
import net.northking.cctp.se.file.Attachment;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URI;
import java.util.Arrays;
import java.util.Map;

public class HttpUtils {

    private static final RestTemplate restTemplate;

    private static final RestTemplate downLoadRestTemplate;

    private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);

    static {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(30000);
        factory.setReadTimeout(30000);
        restTemplate = new RestTemplate(factory);

        SimpleClientHttpRequestFactory downloadFactory = new SimpleClientHttpRequestFactory();
        downloadFactory.setConnectTimeout(15000);
        downloadFactory.setReadTimeout(600000);
        downLoadRestTemplate = new RestTemplate(downloadFactory);
    }

    public static <T> T doPost(URI uri, HttpEntity<?> httpEntity, Class<T> responseType){
        ResponseEntity<T> response = null;
        try {
            response = restTemplate.exchange(uri, HttpMethod.POST, httpEntity, responseType);
        } catch (Exception e) {
            logger.error("请求出错,地址：{}，原因：{}",uri.getPath(),e);
            throw new ExecuteException(String.format("http请求【%s】出错", uri.getPath()));
        }
        return response.getBody();
    }

    public static <T> T doPost(String url, HttpEntity<?> httpEntity, Class<T> responseType){
        ResponseEntity<T> response = null;
        try {
            response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, responseType);
        } catch (Exception e) {
            logger.error("请求出错,地址：{}，原因：{}",url,e);
            throw new ExecuteException(String.format("http请求【%s】出错", url));
        }
        return response.getBody();
    }

    public static <T> T doGet(URI uri, Class<T> responseType){
        ResponseEntity<T> response = null;
        try {
            response = restTemplate.exchange(uri, HttpMethod.GET, null, responseType);
        } catch (Exception e) {
            logger.error("请求出错,地址：{}，原因：{}",uri.getPath(),e);
            throw new ExecuteException(String.format("http请求【%s】出错", uri.getPath()));
        }
        return response.getBody();
    }

    public static <T> T doGet(String url, Class<T> responseType){

        ResponseEntity<T> response = null;
        try {
            response = restTemplate.exchange(url, HttpMethod.GET, null, responseType);
        } catch (Exception e) {
            logger.error("请求出错,地址：{}，原因：{}",url,e);
            throw new ExecuteException(String.format("http请求【%s】出错", url));
        }
        return response.getBody();
    }

    public static void downloadFileToLocal(String sourceUrl,String targetDir,String fileName){
        final String[] installAddr = {""};
        RequestCallback callback = request -> request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
        ResponseExtractor responseExtractor = clientHttpResponse -> {
            File appFile = new File(targetDir + "/" + fileName);
            InputStream inputStream = clientHttpResponse.getBody();
            FileOutputStream outputStream = new FileOutputStream(appFile);
            byte[] data = new byte[1024 * 1024];
            int length = 0;
            while ((length = inputStream.read(data, 0, data.length)) > 0) {
                outputStream.write(data, 0, length);
            }
            installAddr[0] = appFile.getAbsolutePath();
            return appFile;
        };
        downLoadRestTemplate.execute(sourceUrl, HttpMethod.GET, callback, responseExtractor);
    }

    public static boolean doInstall(String url, HttpEntity<?> httpEntity){
        ResponseEntity<Boolean> response = null;
        try {
            response = downLoadRestTemplate.exchange(url, HttpMethod.POST, httpEntity, Boolean.class);
        } catch (Exception e) {
            logger.error("请求出错,地址：{}，原因：{}",url,e);
            throw new ExecuteException(String.format("http请求【%s】出错", url));
        }
        return response.getBody();
    }

    public static Attachment upload(String filePath, String tenantId, String objId, String businessCode) {
        return upload(filePath, tenantId, objId, businessCode, null);
    }

    /**
     * 上传资源
     * @param filePath
     * @param tenantId
     * @return
     */
    public static Attachment upload(String filePath, String tenantId, String objId, String businessCode, String attachId) {
        if (StringUtils.isBlank(tenantId)) {
            throw new ExecuteException("上传资源失败：缺少租户信息");
        }
        if (StringUtils.isBlank(filePath)) {
            throw new ExecuteException("上传资源失败：文件地址为空");
        }
        RestTemplate template = new RestTemplate();
        AtuServerConfig config = SpringUtils.getBean(AtuServerConfig.class);
        String url = config.getServerUrl() + config.getFileUploadPath();
        LinkedMultiValueMap<String, Object> multipartMap = new LinkedMultiValueMap<>();
        multipartMap.add("file", new FileSystemResource(filePath));
        multipartMap.add("tenantId", tenantId);
        multipartMap.add("objId", objId);
        multipartMap.add("businessCode", businessCode);
        if (StringUtils.isNotBlank(attachId)) {
            multipartMap.add("attachId", attachId);
        }
        FormHttpMessageConverter converter = new FormHttpMessageConverter();
        converter.addPartConverter(new ResourceHttpMessageConverter());
        template.getMessageConverters().add(converter);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(multipartMap, headers);
        Attachment result = null;
        try {
            ResultWrapper<Map<String, Object>> wrapper = template.postForObject(url, httpEntity, ResultWrapper.class);
            if (null != wrapper && wrapper.isSuccess()) {
                if (wrapper.getData() != null) {
                    result = new Attachment();
                    if (wrapper.getData().containsKey("id") && wrapper.getData().get("id") != null) {
                        result.setId(wrapper.getData().get("id").toString());
                    }
                    if (wrapper.getData().containsKey("urlPath") && wrapper.getData().get("urlPath") != null) {
                        result.setUrlPath(wrapper.getData().get("urlPath").toString());
                    }
                }
            } else {
                throw new ExecuteException("上传资源失败");
            }
        } catch (ExecuteException e) {
            throw e;
        } catch (Exception e) {
            throw new ExecuteException("上传资源失败：" + e.getMessage(), e);
        }
        return result;
    }

    public static InputStream download2Stream(String resource) {
        if (StringUtils.isBlank(resource)) {
            throw new ExecuteException("下载资源失败：文件地址为空");
        }
        RestTemplate template = new RestTemplate();
        AtuServerConfig config = SpringUtils.getBean(AtuServerConfig.class);
        String url = config.getServerUrl() + config.getFileDownloadPath() + resource;
        ResponseEntity<byte[]> resultEntity = null;
        try {
            resultEntity = restTemplate.getForEntity(url, byte[].class);
        } catch (HttpClientErrorException e) {
            if (HttpStatus.NOT_FOUND == e.getStatusCode()) {
                throw new ExecuteException("下载失败", e);
            }
            throw new ExecuteException("下载失败", e);
        }
        if (resultEntity.getBody() == null) {
            throw new ExecuteException("下载内容为空");
        }
        return IoUtil.toStream(resultEntity.getBody());
    }


}
