package net.educoder.ecsonar.services;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import net.educoder.ecsonar.constant.Constant;
import net.educoder.ecsonar.dao.CloudTaskInfoDao;
import net.educoder.ecsonar.dao.CloudTaskInfoDetailDao;
import net.educoder.ecsonar.dao.ProjectDao;
import net.educoder.ecsonar.exception.BusinessException;
import net.educoder.ecsonar.model.CloudTaskInfo;
import net.educoder.ecsonar.model.CloudTaskInfoDetail;
import net.educoder.ecsonar.model.IssuesMetrics;
import net.educoder.ecsonar.model.Project;
import net.educoder.ecsonar.model.api.QualityInspectIsCompleted;
import net.educoder.ecsonar.model.dto.CloudBrainQualityInspectDTO;
import net.educoder.ecsonar.model.vo.*;
import net.educoder.ecsonar.task.CloudBrainQualityInspectRunnable;
import net.educoder.ecsonar.utils.IdUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
 * @Author: youys
 * @Date: 2022/7/5
 * @Description:
 */
@Service
public class CloudBrainService {

    @Autowired
    private CloudTaskInfoDao cloudTaskInfoDao;

    @Autowired
    private CloudTaskInfoDetailDao cloudTaskInfoDetailDao;

    @Autowired
    private SonarService sonarService;

    @Autowired
    private DbOperateService dbOperateService;

    @Autowired
    private ProjectDao projectDao;

    @Autowired
    @Qualifier("sonarScannerPool")
    private ExecutorService sonarScannerPool;

    @Autowired
    @Qualifier("sonarQueryResultPool")
    private ExecutorService sonarQueryResultPool;

    @Value("${sonar.host}")
    private String sonarHost;


    @Transactional(rollbackFor = Exception.class)
    public List<CloudBrainQualityInspectDTO> startQualityInspect(List<CloudBrainQualityInspectVO> cloudBrainQualityInspectVO) {

        List<CloudBrainQualityInspectDTO> inspectDTOList = new ArrayList<>(cloudBrainQualityInspectVO.size());

        for (CloudBrainQualityInspectVO brainQualityInspectVO : cloudBrainQualityInspectVO) {

            // 创建taskInfo----一个人对应一个taskId
            CloudTaskInfo cloudTaskInfo = new CloudTaskInfo();
            cloudTaskInfo.setId(IdUtils.nextStrId());
            cloudTaskInfo.setPeopleNumber(1);
            cloudTaskInfoDao.insertCloudTaskInfo(cloudTaskInfo);

            inspectDTOList.add(new CloudBrainQualityInspectDTO(cloudTaskInfo.getId(), brainQualityInspectVO.getProjectId()));

            // taskId-projectId
            String finalProjectName = String.format("%s-%s", cloudTaskInfo.getId(), brainQualityInspectVO.getProjectId());

            // 创建taskInfoDetail
            CloudTaskInfoDetail cloudTaskInfoDetail = new CloudTaskInfoDetail();
            cloudTaskInfoDetail.setId(IdUtils.nextStrId());
            cloudTaskInfoDetail.setTaskId(cloudTaskInfo.getId());
            cloudTaskInfoDetail.setLanguage(brainQualityInspectVO.getLanguage());
            cloudTaskInfoDetail.setProjectName(finalProjectName);
            cloudTaskInfoDetail.setProjectId(brainQualityInspectVO.getProjectId());
            cloudTaskInfoDetail.setGitUrl(brainQualityInspectVO.getGitUrl());
            cloudTaskInfoDetailDao.insertCloudTaskInfoDetail(cloudTaskInfoDetail);

            // 创建一个扫描任务
            CloudBrainQualityInspectRunnable runnable = new CloudBrainQualityInspectRunnable(cloudTaskInfoDetail, sonarService, dbOperateService, sonarQueryResultPool);

            sonarScannerPool.execute(runnable);
        }

        return inspectDTOList;
    }

    public QualityInspectIsCompleted cloudQualityInspectIsCompleted(String taskId) {

        CloudTaskInfo cloudTaskInfo = cloudTaskInfoDao.queryById(taskId);
        if (cloudTaskInfo == null) {
            throw new BusinessException(2, "任务id不存在");
        }

        if (cloudTaskInfo.getStatus() == 1) {
            return new QualityInspectIsCompleted(taskId, cloudTaskInfo.getStatus());
        }

        Integer taskNumber = cloudTaskInfoDetailDao.selectCountByTaskId(taskId);
        int completed = cloudTaskInfo.getPeopleNumber().equals(taskNumber) ? 1 : 0;

        // 数据库未更新状态，但sonar任务已经全部执行完，更新task_info状态
        if (cloudTaskInfo.getStatus() == 0 && completed == 1) {
            cloudTaskInfoDao.updateCloudTaskInfoStatus(cloudTaskInfo.getId(), 1);

            // 并且删除文件 /tmp/$taskId  /tmp/homeworkId/*
//            String command = String.format("rm -rf /tmp/%s && rm -rf /tmp/%s/*", taskId, taskInfo.getHomeworkId());
//            SystemUtil.executeAndGetExitStatus(command);
        }

        QualityInspectIsCompleted qualityInspectIsCompleted = new QualityInspectIsCompleted(taskId, completed);
        return qualityInspectIsCompleted;
    }

    public CloudQualityInspectResultVO cloudQualityInspectResult(String taskId) {

        QualityInspectIsCompleted qualityInspectIsCompleted = cloudQualityInspectIsCompleted(taskId);

        CloudQualityInspectResultVO resultVO = new CloudQualityInspectResultVO();
        resultVO.setTaskId(taskId);
        resultVO.setCompleted(qualityInspectIsCompleted.getCompleted());
        if (qualityInspectIsCompleted.getCompleted() == 0) {
            return resultVO;
        }

        CloudTaskInfo cloudTaskInfo = cloudTaskInfoDao.queryById(taskId);

        if (cloudTaskInfo == null) {
            return resultVO;
        }

        String projectName = cloudTaskInfoDetailDao.selectProjectNamesByTaskId(taskId);
        Project project = projectDao.findByName(projectName);
        if(project == null){
            return resultVO;
        }

        IssuesMetrics issuesMetrics = projectDao.selectIssuesMetrics(project.getProject_uuid());
        resultVO.setTaskName(projectName);
        resultVO.setBugs(issuesMetrics.getBugs());
        resultVO.setVulnerability(issuesMetrics.getVulnerability());
        resultVO.setCodeSmell(issuesMetrics.getCodeSmell());
        resultVO.setCodeLines(issuesMetrics.getCodeLines());

        return resultVO;
    }


    /**
     * issues 搜索
     *
     * @param searchVO
     * @return
     */
    public List<IssuesVO> issuesSearch(IssuesSearchVO searchVO) {
        List<IssuesVO> issues = doGetIssues(searchVO.getTaskName(), searchVO.getType());
        return issues;
    }


    /**
     * 获取源码
     *
     * @param component
     * @return
     */
    public List<SourceCodeVO> getSourceCode(String component) {
        return doGetSourceCode(component);
    }


    /**
     * 获取issues
     *
     * @param taskName 任务名称
     * @param type 类型
     * @return
     */
    private List<IssuesVO> doGetIssues(String taskName, String type) {

        if (Constant.ALL.equals(type)) {
            type = StringUtils.join(Constant.BUG, ",", Constant.VULNERABILITY, ",", Constant.CODE_SMELL);
        }

        StringBuilder sb = new StringBuilder();
        sb.append("/api/issues/search?componentKeys=").append(taskName)
                .append("&s=FILE_LINE&resolved=false&types=").append(type)
                .append("&ps=500&organization=default-organization&facets=severities%2Ctypes&additionalFields=_all");

        String url = sonarHost + sb.toString();

        String result = HttpUtil.get(url);
        if (StringUtils.isEmpty(result)) {
            return new ArrayList<>(0);
        }
        JSONArray issuesArray = JSONObject.parseObject(result).getJSONArray("issues");
        List<IssuesVO> issuesVOS = new ArrayList<>(issuesArray.size());
        for (Object o : issuesArray) {
            JSONObject issueObj = (JSONObject) o;

            IssuesVO vo = new IssuesVO();
            vo.setComponent(issueObj.getString("component"));
            vo.setLine(issueObj.getIntValue("line"));
            vo.setMessage(issueObj.getString("message"));
            vo.setSeverity(issueObj.getString("severity"));
            vo.setStatus(issueObj.getString("status"));

            issuesVOS.add(vo);
        }
        return issuesVOS;
    }


    /**
     * 获取问题源代码
     *
     * @param component
     * @return
     */
    private List<SourceCodeVO> doGetSourceCode(String component) {

        StringBuilder sb = new StringBuilder();
        sb.append("/api/sources/lines?key=").append(component)
                .append("&from=1&to=50100");
        String url = sonarHost + sb.toString();

        String result = HttpUtil.get(url);
        if (StringUtils.isEmpty(result)) {
            return new ArrayList<>(0);
        }
        JSONArray sourcesArrays = JSONObject.parseObject(result).getJSONArray("sources");
        List<SourceCodeVO> sourceCodeVOS = new ArrayList<>(sourcesArrays.size());
        for (Object o : sourcesArrays) {
            JSONObject issueObj = (JSONObject) o;

            SourceCodeVO vo = new SourceCodeVO();
            vo.setCode(issueObj.getString("code"));
            vo.setLine(issueObj.getInteger("line"));
            sourceCodeVOS.add(vo);
        }
        return sourceCodeVOS;
    }


}
