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

import cd.casic.ci.process.dto.req.report.ReportAssetTaskReq;
import cd.casic.ci.process.dto.req.vulInfo.SearchDto;
import cd.casic.ci.process.dto.req.vulInfo.VulInfoDto;
import cd.casic.ci.process.dto.resp.ScaVulInfoResp;
import cd.casic.ci.process.engine.context.ConstantContextHolder;
import cd.casic.ci.process.process.converter.VulInfoConverter;
import cd.casic.ci.process.process.dao.vulInfo.VulInfoDao;
import cd.casic.ci.process.process.dataObject.volumnInfo.VulInfo;
import cd.casic.ci.process.process.service.vulInfo.VulInfoService;
import cd.casic.ci.process.util.vulInfo.BeanUtil;
import cd.casic.ci.process.util.vulInfo.TimeUtils;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.pojo.PageResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import static cd.casic.ci.process.engine.worker.base.HttpWorker.getRestTemplateWithoutSANCheck;

@Service
@Slf4j
public class VulInfoServiceImpl extends ServiceImpl<VulInfoDao,VulInfo> implements VulInfoService {
    @Resource
    private VulInfoConverter converter;
    @Resource
    private VulInfoDao vulInfoDao;

    @Override
    public void scaToVulInfoSave(Integer scaTaskId,String targetType,String targetName,String city,String instanceId,String taskId,String taskType) {
        List<ScaVulInfoResp> scaVulInfoResps = null;
        try {
            scaVulInfoResps = scaVulListGet(scaTaskId);
        } catch (Exception e) {
            return;
        }
        System.out.println(scaVulInfoResps.size());
        System.out.println(scaVulInfoResps);
        List<VulInfo> vulInfos = converter.scaToVulInfo(scaVulInfoResps);
        vulInfos.forEach(item->{
            item.setTargetType(targetType);
            item.setTargetName(targetName);
            item.setCity(city);
            item.setInstanceId(instanceId);
            item.setTaskId(taskId);
            item.setTaskType(taskType);
        });
        saveBatch(vulInfos);
    }

    @Override
    public Integer scaVulCountGet(Integer scaTaskId) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        RestTemplate restTemplate= getRestTemplateWithoutSANCheck();
        String url = ConstantContextHolder.getScaIp() + "/openapi/v1/task/vul/list";
        JSONObject json = new JSONObject();
        json.put("taskId", scaTaskId);
        json.put("pageNo", 1);
        json.put("pageSize", 1);
        String body = json.toJSONString();
        HttpEntity<String> entity = new HttpEntity<>(body,createHeaders());
        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, String.class, new HashMap<>());
        String res = exchange.getBody();
        return JSONObject.parseObject(res).getInteger("total");
    }

    @Override
    public List<ScaVulInfoResp> scaVulListGet(Integer scaTaskId) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        HttpHeaders headers = createHeaders();
        RestTemplate restTemplate = getRestTemplateWithoutSANCheck();
        JSONObject json = new JSONObject();
        ReportAssetTaskReq req = new ReportAssetTaskReq();
        //报告维度 5-组件，默认为5-组件
        json.put("dimension", req.getDimension());
        json.put("reportTemplateId", req.getReportTemplateId());
        json.put("type", 4);
        json.put("reportName", req.getReportName());
        json.put("scaTaskId", scaTaskId);
        String generateUrl = ConstantContextHolder.getScaIp()+"/openapi/v1/asset/report/task";
        HttpEntity<String> entity = new HttpEntity<>(json.toJSONString(),headers);
        // 生成报告
        ResponseEntity<String> exchange = restTemplate.exchange(generateUrl, HttpMethod.POST, entity, String.class, new HashMap<>());
        String generateRes = exchange.getBody();
        JSONObject generateResObj = JSON.parseObject(generateRes);
        if ("success".equals(generateResObj.getString("message"))) {
            Integer id = generateResObj.getInteger("data");
            // 检查报告状态
            if (!checkScaReportStatus(id,restTemplate,headers)) {
                return List.of();
            }
            // 下载报告
            String downloadUrl = ConstantContextHolder.getScaIp()+"/openapi/v1/asset/report/downLoadReport/batch";
            JSONObject downloadBody = new JSONObject();
            downloadBody.put("reportIds", Collections.singletonList(id));
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> downloadEntity = new HttpEntity<>(downloadBody.toJSONString(),headers);
            ResponseEntity<byte[]> downloadExchange = restTemplate.exchange(downloadUrl, HttpMethod.POST, downloadEntity, byte[].class, new HashMap<>());
            byte[] downloadRes = downloadExchange.getBody();
            String reportString = new String(downloadRes, StandardCharsets.UTF_8);
            JSONObject reportObj = JSONObject.parseObject(reportString);
            // 解析报告
            String vulInfo = reportObj.getString("vulInfo");
            return JSONArray.parseArray(vulInfo, ScaVulInfoResp.class);
        }
        return List.of();
    }


    public void upload(VulInfo vulInfo) {
        vulInfo.setVulId(vulInfo.getTargetType() + TimeUtils.ConvertTimeToStringUtils());
        try {
            save(vulInfo);
        } catch (Exception e) {
            throw new ServiceException(500, e.getMessage());
        }
    }


    @Override
    public PageResult<VulInfoDto> getSearch(SearchDto searchDto) {
        Page<VulInfo> page = new Page<>(searchDto.getPageNo(), searchDto.getPageSize());
        String cwes = null;
        if (searchDto.getCwes() != null && !searchDto.getCwes().isEmpty()) {
            cwes = JSONObject.toJSONString(searchDto.getCwes());
        }
        QueryWrapper<VulInfo> queryWrapper = new QueryWrapper<>();
        if (searchDto.getVulId() != null && !searchDto.getVulId().isEmpty()) {
            queryWrapper.like("vul_id", searchDto.getVulId());
        }
        if (searchDto.getVulTitle() != null && !searchDto.getVulTitle().isEmpty()) {
            queryWrapper.like("vul_title", searchDto.getVulTitle());
        }
        if (cwes != null && !cwes.isEmpty()) {
            queryWrapper.like("cwes", cwes);
        }
        if (searchDto.getAffectProjectId() != null && !searchDto.getAffectProjectId().isEmpty()) {
            queryWrapper.like("affect_project_id", searchDto.getAffectProjectId());
        }
        if (searchDto.getVerifyStatus() != null && !searchDto.getVerifyStatus().isEmpty()) {
            queryWrapper.like("verify_status", searchDto.getVerifyStatus());
        }
        if (searchDto.getTargetName() != null && !searchDto.getTargetName().isEmpty()) {
            queryWrapper.like("target_name", searchDto.getTargetName());
        }
        if (searchDto.getUnaffectedVersions() != null && !searchDto.getUnaffectedVersions().isEmpty()) {
            queryWrapper.like("unaffected_versions", searchDto.getUnaffectedVersions());
        }
        if (searchDto.getAffectProductName() != null && !searchDto.getAffectProductName().isEmpty()) {
            queryWrapper.like("affect_product_name", searchDto.getAffectProductName());
        }
        Page<VulInfo> vulInfoPage = baseMapper.selectPage(page, queryWrapper);
        List<VulInfo> records = vulInfoPage.getRecords();
        List<VulInfoDto> vulInfoDtos = new ArrayList<>();
        if (records != null && !records.isEmpty()) {
            //VulInfo转VulInfoDto
            for (VulInfo vulInfo : records) {
                vulInfoDtos.add(BeanUtil.ConvertVulInfoToVulInfoDto(vulInfo));
            }
        }
        return new PageResult<>(vulInfoDtos,vulInfoPage.getTotal(),vulInfoPage.getCurrent(),vulInfoPage.getSize());
    }

    private HttpHeaders createHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("OpenApiUserToken", ConstantContextHolder.getScaToken());
        return headers;
    }
    private Boolean checkScaReportStatus(Integer reporterId,RestTemplate restTemplate,HttpHeaders headers){
        HttpEntity<String> checkEntity = new HttpEntity<>("",headers);
        String checkUrl = ConstantContextHolder.getScaIp()+"/openapi/v1/asset/report/status/"+reporterId;
        while (true){
            ResponseEntity<String> exchange = restTemplate.exchange(checkUrl, HttpMethod.POST, checkEntity, String.class, new HashMap<>());
            JSONObject res = JSONObject.parseObject(exchange.getBody());
            JSONObject data = res.getJSONObject("data");
            Integer status = data.getInteger("status");
            log.info("报告生成状态  -1-排队中 0-生成中 1-已生成 2-生成失败：{}",status);
            //报告状态 -1-排队中 0-生成中 1-已生成 2-生成失败
            if (status==null) {
                break;
            }
            if (status.equals(1)) {
                return true;
            }else if (status.equals(2)) {
                return false;
            }
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
            }
        }
        return false;
    }
}
