package com.microservices.pms.productLibrary.controller;

import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.microservices.common.core.web.controller.BaseController;
import com.microservices.pms.productLibrary.domain.PmsProductlibJyrjd;
import com.microservices.pms.productLibrary.domain.PmsProductlibJyrldLib;
import com.microservices.pms.productLibrary.service.IPmsProductlibJyrjdService;
import com.microservices.pms.productLibrary.service.IPmsProductlibJyrldLibService;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
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.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Controller
public class ProductLibraryProxyController extends BaseController {

    @Value("${nexus.proxy.targetAddr}")
    private String targetAddr;
    @Value("${nexus.proxy.userName}")
    private String userName;
    @Value("${nexus.proxy.password}")
    private String password;
    @Value("${nexus.proxy.authorization}")
    private String authorization;
    @Resource
    private IPmsProductlibJyrjdService pmsProductlibJyrjdService;
    @Resource
    private IPmsProductlibJyrldLibService pmsProductlibJyrldLibService;
    private RestTemplate restTemplate = new RestTemplate();

    /**
     * 代理所有请求
     *
     * @param request
     * @throws Exception
     */
//    @CrossOrigin(origins = {"*", "null"})
    @RequestMapping(value = "/productLibrary/**", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public Object proxy(HttpServletRequest request) throws IOException, URISyntaxException, ServletException {
        URI uri = new URI(request.getRequestURI());
        String path = uri.getPath();
        String query = request.getQueryString();
        URI newUri = null;
        boolean isJyrjd = false;
        boolean isJyrjdLib = false;
        String url = targetAddr + path.replace("/productLibrary", "");
        String jyrjdLibName = "";
        if (path.contains("repositories/xxxx")) {
            isJyrjdLib = true;
            //ns中只有raw类型，把jyrjd改成raw
            jyrjdLibName = query.substring(query.indexOf('=') + 1);
            query = null;
            url = targetAddr + "/service/rest/v1/repositories/raw/hosted";
        }

        Pattern pattern1 = Pattern.compile("^/productLibrary/service/extdirect/");
        if (pattern1.matcher(path).find()) {
            if (StringUtils.equals(path, "/productLibrary/service/extdirect/xxxx")) {
                isJyrjd = true;
            }
            url = targetAddr + "/service/extdirect/";
        }
        Pattern pattern2 = Pattern.compile("^/productLibrary/service/rest/v1/components/");
        if (pattern2.matcher(path).find()) {
            url = targetAddr + "/service/rest/v1/components/";
        }
        String querylonger = StringUtils.isNoneBlank(query) ? "?" + query : "";
        newUri = new URI(url + querylonger);
        // 执行代理查询
        String methodName = request.getMethod();
        HttpMethod httpMethod = HttpMethod.resolve(methodName);
        if (httpMethod == null) {
            return error("httpMethod is null");
        }
        // 检查请求是否为multipart/form-data类型
        if (request.getContentType() != null && request.getContentType().startsWith("multipart/form-data")) {
            HttpPost httpPost = new HttpPost(newUri);
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            // 创建一个MultipartEntityBuilder
            MultipartEntityBuilder builder = MultipartEntityBuilder.create().setContentType(ContentType.MULTIPART_FORM_DATA).setCharset(Charset.forName("UTF-8"));
            // 将所有的表单数据添加到MultipartEntityBuilder中
            String jyrjdPath = null, name = null, jyrjdAttributes = null;
            for (Map.Entry<String, String[]> entry : multipartRequest.getParameterMap().entrySet()) {

                if (StringUtils.equals(entry.getKey(), "raw.directory")) {
                    jyrjdPath = entry.getValue()[0];
                    builder.addPart(entry.getKey(), new StringBody(jyrjdPath, ContentType.MULTIPART_FORM_DATA));
                } else if (StringUtils.equals(entry.getKey(), "raw.asset1.filename")) {
                    name = entry.getValue()[0];
                    builder.addPart(entry.getKey(), new StringBody(name, ContentType.MULTIPART_FORM_DATA));
                } else if (StringUtils.equals(entry.getKey(), "xxxxAttributes")) {
                    jyrjdAttributes = entry.getValue()[0];
                } else if (StringUtils.equals(entry.getKey(), "repository")) {
                    continue;
                } else {
                    builder.addTextBody(entry.getKey(), entry.getValue()[0]);
                }
            }
            // 将所有的文件添加到MultipartEntityBuilder中
            for (Map.Entry<String, MultipartFile> entry : multipartRequest.getFileMap().entrySet()) {
//                builder.addPart(entry.getKey(), new InputStreamBody(entry.getValue().getInputStream(), ContentType.MULTIPART_FORM_DATA, entry.getValue().getOriginalFilename()));
                String encodedFilename = URLEncoder.encode(Objects.requireNonNull(entry.getValue().getOriginalFilename()), StandardCharsets.UTF_8.toString());
                builder.addBinaryBody(entry.getKey(), entry.getValue().getBytes()
                        , ContentType.DEFAULT_BINARY, encodedFilename);
            }
            // 创建一个HttpEntity
            org.apache.http.HttpEntity entity = builder.build();
            // 将HttpEntity的内容写入到delegate的body中
            httpPost.setEntity(entity);
            HashMap<String, String> headers = new HashMap<>();
            headers.put("Authorization", authorization);
            headers.forEach(httpPost::setHeader);
            CloseableHttpClient httpClient = HttpClients.createDefault();
            // Execute the request
            HttpResponse response = httpClient.execute(httpPost);
            if (StringUtils.equals(path, "/productLibrary/service/rest/v1/components/xxxx") && httpMethod.matches("POST") && response.getStatusLine().getStatusCode() == 204) {
                Map params = request.getParameterMap();
                PmsProductlibJyrjd pmsProductlibJyrjd = new PmsProductlibJyrjd();
                pmsProductlibJyrjd.setName(query.substring(query.indexOf('=') + 1));
                pmsProductlibJyrjd.setFormat("xxxx");
                pmsProductlibJyrjd.setJyrjdAttributes(jyrjdAttributes);
                pmsProductlibJyrjd.setPath(jyrjdPath + "/" + name);
                pmsProductlibJyrjdService.insert(pmsProductlibJyrjd);
            }
            return response;
        }
        // 如果不是multipart/form-data类型的请求，直接将请求内容写入到delegate的body中

        ClientHttpRequest delegate = new SimpleClientHttpRequestFactory().createRequest(newUri, httpMethod);
        Enumeration<String> headerNames = request.getHeaderNames();
        // 设置请求头
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            Enumeration<String> v = request.getHeaders(headerName);
            List<String> arr = new ArrayList<>();
            while (v.hasMoreElements()) {
                arr.add(v.nextElement());
            }
            if (!headerName.contains("forwarded")
                    && !headerName.contains("cookie")
                    && !headerName.contains("authorization")
                    && !headerName.contains("user")) {
                delegate.getHeaders().addAll(headerName, arr);
            }
        }
        // Add username and password to request headers
        delegate.getHeaders().setBasicAuth(userName, password);
        StreamUtils.copy(request.getInputStream(), delegate.getBody());

        ClientHttpResponse clientHttpResponse = delegate.execute();
        String bufferedReader = "";
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(clientHttpResponse.getBody(), "UTF-8")).lines().collect(Collectors.joining(""));
        } catch (IOException e) {
            logger.error("读取body异常", e);
            InputStream body = clientHttpResponse.getBody();
            byte[] responseBodyBytes = IOUtils.toByteArray(body);
            String errorMsg = new String(responseBodyBytes);
            if (errorMsg.contains("repository_repository_name_idx")) {
                errorMsg = "制品库名称已存在";
            }
            return error(errorMsg);
        }
        //处理/v1/repositories List查询
        Pattern pattern = Pattern.compile("/v1/repositories$");
        Gson gson = new Gson();
        Object result = bufferedReader;
        //在后台处理数据
        if (pattern.matcher(path).find() && httpMethod.matches("GET")) {
            //检查列表，如果列表中的仓库名能在PmsProductlib里面找到，那就是xxxx软件段，把Format全部改成jyrjd再返回

            List<Map> repositories = gson.fromJson(bufferedReader, List.class);

            for (int i = 0; i < repositories.size(); i++) {
                Map map = repositories.get(i);
                if (StringUtils.equals((String) map.get("format"), "raw")) {
                    PmsProductlibJyrldLib pmsProductlibJyrldLib = pmsProductlibJyrldLibService.queryByName((String) map.get("name"));
                    if (pmsProductlibJyrldLib != null) {
                        map.put("format", "xxxx");
                    }
                }
            }
            result = repositories;
        }
        if (isJyrjdLib) {
            PmsProductlibJyrldLib lib = new PmsProductlibJyrldLib();
            lib.setName(jyrjdLibName);
            pmsProductlibJyrldLibService.insert(lib);
        }

        if (isJyrjd) {
            Map jsonM = gson.fromJson(bufferedReader, Map.class);
            Map rs = (Map) jsonM.get("result");
            Map data = (Map) rs.get("data");
            data.put("format", "xxxx");
            PmsProductlibJyrjd lib = new PmsProductlibJyrjd();
            lib.setName((String) data.get("repositoryName"));
            lib.setFormat((String) data.get("format"));
            lib.setPath((String) data.get("name"));
            PmsProductlibJyrjd pmsProductlibJyrjd = pmsProductlibJyrjdService.queryByPmsProductlibJyrjd(lib);
            if (pmsProductlibJyrjd != null) {
                data.put("jyrjdAttributes", pmsProductlibJyrjd.getJyrjdAttributes());
            }
            //修改展示列表
            result = jsonM;
        }
        if (StringUtils.equals(path, "/productLibrary/service/rest/v1/components/xxxx") && httpMethod.matches("DELETE")) {
            //删除jyrjd
            Map params = request.getParameterMap();
            pmsProductlibJyrjdService.deleteByPath((String) params.get("jyrjdPath"));
        }
        return success(result);
    }
}
