package cd.casic.ci.process.process.service.shuimu.impl;

import cd.casic.ci.process.dto.req.shuimu.*;
import cd.casic.ci.process.dto.resp.shuimu.*;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.service.pipeline.PipelineService;
import cd.casic.ci.process.process.service.shuimu.ShuiMuService;
import cd.casic.ci.process.process.service.target.TargetVersionService;
import cd.casic.ci.process.properties.ShuiMuProperties;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.commons.util.object.BeanUtils;
import cd.casic.framework.redis.core.RedisTemplateUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.*;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

import static cd.casic.ci.process.constant.ShuiMuUrlConstant.*;

@Service
@Slf4j
public class ShuiMuServiceImpl implements ShuiMuService {
    @Resource
    private ShuiMuProperties shuiMuProperties;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private RedisTemplateUtils redisTemplateUtils;
    private static final String REDIS_SHUI_MU_TOKEN_KEY = "REDIS_SHUI_MU_TOKEN_KEY";
    private static final String SHUI_MU_TOKEN_PREFIX = "Bearer ";
    private static final String SHUI_MU_IMAGE_LIST_FILTER = "wfuzz-built";
    @Resource
    private TargetVersionService targetVersionService;
    @Resource
    private PipelineService pipelineService;
    private ShuiMuTokenResp getTokenRemote(){
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String,String>> httpEntity = new HttpEntity<>(buildMapReq(),httpHeaders);
        ResponseEntity<String> exchange = restTemplate.exchange(shuiMuProperties.getBaseUrl() +getToken, HttpMethod.POST, httpEntity, String.class, new HashMap<>());
        String body = exchange.getBody();
        JSONObject bodyObject = JSON.parseObject(body);
        ShuiMuTokenResp tokenResp = new ShuiMuTokenResp();
        tokenResp.setAccessToken(bodyObject.getString("access_token"));
        tokenResp.setExpiresIn(bodyObject.getInteger("expires_in"));
        tokenResp.setRefreshToken(bodyObject.getString("refresh_token"));
        tokenResp.setTokenType(bodyObject.getString("token_type"));
        return tokenResp;
    }
    private MultiValueMap<String,String> buildMapReq(){
        MultiValueMap<String,String> req = new LinkedMultiValueMap<>();
        req.add("username",shuiMuProperties.getUsername());
        req.add("password",shuiMuProperties.getPassword());
        req.add("grant_type",shuiMuProperties.getGrantType());
        req.add("client_id",shuiMuProperties.getClientId());
        return req;
    }

    @Override
    public String getToken() {
        Object o = redisTemplateUtils.get(REDIS_SHUI_MU_TOKEN_KEY);
        String token = o instanceof String ? ((String) o) : "";
        if (StringUtils.isEmpty(token)) {
            synchronized(this){
                o = redisTemplateUtils.get(REDIS_SHUI_MU_TOKEN_KEY);
                token = o instanceof String ? ((String) o) : "";
                if (StringUtils.isEmpty(token)) {
                    ShuiMuTokenResp tokenRemote = getTokenRemote();
                    String accessToken = tokenRemote.getAccessToken();
                    redisTemplateUtils.set(REDIS_SHUI_MU_TOKEN_KEY,accessToken,tokenRemote.getExpiresIn());
                    token = accessToken;
                }
            }
        }
        return SHUI_MU_TOKEN_PREFIX+token;
    }

    @Override
    public List<String> imageList(String label) {

        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl()+imageList).queryParam("label", label).toUriString();
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        JSONObject jsonObject = JSONObject.parseObject(exchange.getBody());
        JSONArray objects = JSONArray.parseArray(jsonObject.getString("data"));
        List<String> res = new ArrayList<>(objects.size());
        for (int i = 0; i < objects.size(); i++) {
            JSONObject item = objects.getJSONObject(i);
            String name = item.getString("name");
            if (StringUtils.isNotEmpty(name)) {
                res.add(name);
            }
        }
        return res.stream().filter(item->!item.startsWith(SHUI_MU_IMAGE_LIST_FILTER)).toList();
    }

    @Override
    public String createProject(ShuiMuProjectCreateReq req) {
        MultiValueMap<String,Object> body = new LinkedMultiValueMap<>();
        body.add("projectName","应用检测_"+ UUID.randomUUID().toString().replaceAll("-",""));
        body.add("language",req.getLanguage());
        body.add("env",req.getEnv());
        body.add("envSpecs",req.getEnvSpecs());
        PipPipeline pipeline = pipelineService.getById(req.getPipelineId());
        String targetVersionId = pipeline.getTargetVersionId();
        TargetVersion targetVersion = targetVersionService.getById(targetVersionId);
        File targetFile = new File(targetVersion.getFilePath());
        if (!targetFile.exists()) {
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"找不到目标文件");
        }
        String fileName = targetVersion.getFileName();
        String fileType = fileName.substring(fileName.indexOf(".")+1);
        body.add("vcs",fileType);
        FileSystemResource resource = new FileSystemResource(targetFile);
        body.add("file",resource);
        HttpHeaders headers = getHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String,Object>> entity = new HttpEntity<>(body, headers);
        ResponseEntity<String> exchange = restTemplate.exchange(shuiMuProperties.getBaseUrl() + createProject, HttpMethod.POST, entity, String.class, new HashMap<>());
        HttpStatusCode statusCode = exchange.getStatusCode();
        if (statusCode.isError()) {
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"创建项目失败");
        }
        JSONObject response = JSONObject.parseObject(exchange.getBody());
        return response.getString("data");
    }

    @Override
    public String readWfuzzJsonFile(String projectId) {
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + readWfuzzJsonFile)
                .queryParam("projectId", projectId).toUriString();
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        return exchange.getBody();
    }

    @Override
    public String readHelpersJsonFile(String projectId) {
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + readHelpersJsonFile)
                .queryParam("projectId", projectId).toUriString();
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        return exchange.getBody();
    }

    @Override
    public ShuiMuProjectVersionResp getProjectVersion(String projectId) {
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + getProjectVersion)
                .queryParam("projectId", projectId).toUriString();
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        if (exchange.getStatusCode().isError()) {
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"保存并且构建失败");
        }
        String data = JSON.parseObject(exchange.getBody()).getString("data");
        return JSON.parseObject(data, ShuiMuProjectVersionResp.class);
    }

    @Override
    public ShuiMuProjectInfoResp getProjectInfo(String projectId) {
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + getProjectById +projectId)
                .toUriString();
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        if (exchange.getStatusCode().isError()) {
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"保存并且构建失败");
        }
        return JSON.parseObject(JSON.parseObject(exchange.getBody()).getString("data"), ShuiMuProjectInfoResp.class);
    }

    @Override
    public void buildAndSaveConfig(ShuiMuBuildAndSaveReq req) {
        MultiValueMap<String,String> body = new LinkedMultiValueMap<>();
        body.add("projectId",req.getProjectId());
        body.add("env",req.getEnv());
        body.add("fileName",req.getFileName());
        HttpHeaders headers = getHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String,String>> entity = new HttpEntity<>(body, headers);
        ResponseEntity<String> exchange = restTemplate.exchange(shuiMuProperties.getBaseUrl() + buildAndSaveConfig, HttpMethod.POST, entity, String.class, new HashMap<>());
        if (exchange.getStatusCode().isError()) {
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"保存并且构建失败");
        }
    }

    @Override
    public void uploadWfuzzJson(ShuiMuUpdateWFuzzJsonReq req) {
        ShuiMuProjectInfoResp projectInfo = getProjectInfo(req.getProjectId());
        String projectName = projectInfo.getName();
        Map<String,Object> restReq = new HashMap<>();
        restReq.put("project",projectName);
        restReq.put("product",projectInfo.getProduct());
        restReq.put("language",projectInfo.getLanguage());
        restReq.put("build",JSON.parseObject(req.getBuild()));
        String tempDir = System.getProperty("java.io.tmpdir");

        File tempFile = new File(tempDir,"wfuzz.json");


        try {
            FileOutputStream fos = new FileOutputStream(tempFile);
            fos.write(JSON.toJSONString(restReq).getBytes());
            fos.flush();
            tempFile.setReadable(true,false);
            FileSystemResource resource = new FileSystemResource(tempFile);
            MultiValueMap<String,Object> body = new LinkedMultiValueMap<>();
            body.add("projectId",req.getProjectId());
            body.add("file",resource);
            HttpHeaders headers = getHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            HttpEntity<MultiValueMap<String,Object>> entity = new HttpEntity<>(body, headers);
            ResponseEntity<String> exchange = restTemplate.exchange(shuiMuProperties.getBaseUrl() + uploadWfuzzJson, HttpMethod.POST, entity, String.class, new HashMap<>());
            if (exchange.getStatusCode().isError()) {
                throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"更新配置文件失败");
            }
            tempFile.deleteOnExit();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 获取projectversion
        ShuiMuProjectVersionResp projectVersion = getProjectVersion(req.getProjectId());
        ShuiMuProjectVersionResp.Repo repo = projectVersion.getRepo();
        ShuiMuBuildAndSaveReq shuiMuBuildAndSaveReq = new ShuiMuBuildAndSaveReq();
        BeanUtils.copyProperties(repo,shuiMuBuildAndSaveReq);
        shuiMuBuildAndSaveReq.setProjectId(req.getProjectId());
        shuiMuBuildAndSaveReq.setFileName(repo.getFilename());
        buildAndSaveConfig(shuiMuBuildAndSaveReq);
    }

    @Override
    public void executeAllEntrypointsTest(String projectId,Integer fuzzMinutes) {
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + executeAllEntrypointsTest)
                .queryParam("projectId",projectId)
                .queryParam("arch","x86")
                .queryParam("fuzzMinutes",fuzzMinutes)
                .toUriString();
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.POST, entity, String.class, new HashMap<>());
        if (exchange.getStatusCode().isError()) {
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"执行测试失败");
        }
    }

    @Override
    public ShuiMuProjectResourceResp getProjectResource (String projectId) {
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + getProjectResource ).queryParam("projectId",projectId)
                .toUriString();
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        if (exchange.getStatusCode().isError()) {
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"获取项目执行信息失败");
        }
        String data = JSON.parseObject(exchange.getBody()).getString("data");
        try {
            List<ShuiMuProjectResourceResp> shuiMuProjectResourceResps = JSONArray.parseArray(data, ShuiMuProjectResourceResp.class);

            return shuiMuProjectResourceResps.get(0);
        } catch (Exception e){
            return null;
        }
    }

    @Override
    public PageResult<ShuiMuTestProblemResp> problemsOfTest(ShuiMuTestProblemReq req) {
        HttpHeaders headers = getHeaders();
        HttpEntity<String> entity = new HttpEntity<>(null,headers);
        String skip = String.valueOf((req.getPageNo()-1)*req.getPageSize());
        String limit = String.valueOf(req.getPageSize());
        String product = "code";
        String projectId = req.getProjectId();
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + problemsOfTest)
                .queryParam("skip", skip)
                .queryParam("limit", limit)
                .queryParam("product", product)
                .queryParam("projectId", projectId).toUriString();
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        JSONObject jsonObject = JSON.parseObject(exchange.getBody());
        String data = jsonObject.getString("data");
        List<ShuiMuTestProblemResp> shuiMuTestProblemResps = JSONArray.parseArray(data, ShuiMuTestProblemResp.class);
        shuiMuTestProblemResps.forEach(item ->{
            String createAt = item.getCreateAt();
            LocalDateTime date = Instant.ofEpochMilli(Long.parseLong(createAt))
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
            item.setCreateTime(date);
        });
        String countUrlString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + problemsOfTestCount)
                .queryParam("skip", skip)
                .queryParam("limit", limit)
                .queryParam("product", product)
                .queryParam("projectId", projectId).toUriString();
        ResponseEntity<String> countExchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        JSONObject countResp = JSON.parseObject(countExchange.getBody());
        Long count = jsonObject.getLong("data");
        Long pageNo = Long.parseLong(String.valueOf(req.getPageNo()));
        Long pageSize = Long.parseLong(String.valueOf(req.getPageSize()));
        PageResult<ShuiMuTestProblemResp> result = new PageResult<>(shuiMuTestProblemResps,count,pageNo,pageSize);
        return result;
    }
    @Override
    public ShuiMuProjectReportResp getProjectReport(String projectId) {
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + getProjectReport )
                .queryParam("skip",0)
                .queryParam("limit",1)
                .queryParam("product","code")
                .queryParam("projectId",projectId)
                .queryParam("showMine",0)
                .toUriString();
        ResponseEntity<String> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, String.class, new HashMap<>());
        if (exchange.getStatusCode().isError()) {
            throw new ServiceException(GlobalErrorCodeConstants.PIPELINE_ERROR.getCode(),"保存并且构建失败");
        }
        String data  = JSON.parseObject(exchange.getBody()).getString("data");

        List<ShuiMuProjectReportResp> list = JSON.parseArray(data, ShuiMuProjectReportResp.class);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public ShuiMuWebFuzzProjectCreateResp createWebFuzzProject(ShuiMuWebFuzzProjectCreateUpdateReq req) {
        MultiValueMap<String,Object> map = new LinkedMultiValueMap<>();
        map.add("projectName",req.getProjectName());
        map.add("hostAddress",req.getHostAddress());
        map.add("projectAddress",req.getProjectAddress());
        map.add("crawl",req.getCrawl());
        map.add("config",req.getConfig());
        map.add("crawlOpened",req.getCrawlOpened());
        map.add("modeType",req.getModeType());
        map.add("crawlAddress",req.getCrawlAddress());
        HttpHeaders headers = getHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String,Object>> entity = new HttpEntity<>(map, headers);
        ResponseEntity<ShuiMuWebFuzzProjectCreateResp> exchange = restTemplate.exchange(shuiMuProperties.getBaseUrl() + createWebFuzzProject, HttpMethod.POST, entity, ShuiMuWebFuzzProjectCreateResp.class, new HashMap<>());
        return exchange.getBody();
    }
    @Override
    public void updateWebFuzzProject(ShuiMuWebFuzzProjectCreateUpdateReq req) {
        MultiValueMap<String,Object> map = new LinkedMultiValueMap<>();
        map.add("projectName",req.getProjectName());
        map.add("hostAddress",req.getHostAddress());
        map.add("projectAddress",req.getProjectAddress());
        map.add("crawl",req.getCrawl());
        map.add("config",req.getConfig());
        map.add("crawlOpened",req.getCrawlOpened());
        map.add("modeType",req.getModeType());
        map.add("crawlAddress",req.getCrawlAddress());
        HttpHeaders headers = getHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String,Object>> entity = new HttpEntity<>(map, headers);
        ResponseEntity<String> exchange = restTemplate.exchange(shuiMuProperties.getBaseUrl() + updateWebFuzzProject, HttpMethod.POST, entity, String.class, new HashMap<>());

    }

    @Override
    public void createWebFuzzTest(String projectId) {
        MultiValueMap<String,Object> multiValueMap = new LinkedMultiValueMap<>();
        ShuiMuWebFuzzProjectResp webFuzzProjectById = getWebFuzzProjectById(projectId);
        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(webFuzzProjectById));
        for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
            if (entry.getKey().equals("id")) {
                multiValueMap.add("projectId",entry.getValue());
                continue;
            }
            multiValueMap.add(entry.getKey(),entry.getValue());
        }
        HttpHeaders headers = getHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String,Object>> entity = new HttpEntity<>(multiValueMap, headers);
        ResponseEntity<ShuiMuWebFuzzProjectCreateResp> exchange = restTemplate.exchange(shuiMuProperties.getBaseUrl() + createWebFuzzTest, HttpMethod.POST, entity, ShuiMuWebFuzzProjectCreateResp.class, new HashMap<>());
        log.info("请求结果{}",exchange.getBody());
    }

    @Override
    public ShuiMuWebFuzzProjectResp getWebFuzzProjectById(String id) {
        HttpEntity<String> entity = new HttpEntity<>(null,getHeaders());
        String uriString = UriComponentsBuilder.fromUriString(shuiMuProperties.getBaseUrl() + getWebFuzzProjectById + id).toUriString();
        ResponseEntity<ShuiMuWebFuzzProjectResp> exchange = restTemplate.exchange(uriString, HttpMethod.GET, entity, ShuiMuWebFuzzProjectResp.class, new HashMap<>());
        return exchange.getBody();
    }

    public void updateWebFuzzProject(){

    }

    private HttpHeaders getHeaders(){
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.set("authorization",getToken());
        return httpHeaders;
    }

}
