package net.educoder.ecsonar.services;


import net.educoder.ecsonar.dao.ProjectDao;
import net.educoder.ecsonar.model.Metrics;
import net.educoder.ecsonar.model.Project;
import net.educoder.ecsonar.model.api.Person;
import net.educoder.ecsonar.model.api.SonarRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

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

@Service
public class EcsonarService {

    Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private ExecutorService executorService;

    @Autowired
    ProjectDao projectDao;

    @Autowired
    SonarService sonarService;

    @Autowired
    ReportService reportService;

    @Value("${zip.save.path}")
    String zipSavePath;

    @Value("${force.parse:false}")
    boolean forceParse;

    public static class Row {
        public int i;
        public Person person;
        public String key;
    }

    public void sonar(SonarRequest sonarRequest) {
        String zipUsePath = String.format("%s%d/", zipSavePath, sonarRequest.getHomeworkId());

        if (!new File(zipUsePath).exists()) {
            new File(zipUsePath).mkdir();
        }

        String csvPath = zipUsePath + String.format("%d.csv", sonarRequest.getHomeworkId());

        List<String> uids = readAllUids(csvPath);

        List<Row> rows = new ArrayList<>();

        executorService.execute(() -> {
            int i = 0;
            for (Person person : sonarRequest.getPersonList()) {
                i++;

                //数据库如果有就不检测了

                log.info("{}/{} 开始处理: {} ", i, sonarRequest.getPersonList().size(), person);
                if (person.getDownloadUrl().startsWith("http")) {
                    try {
                        //毕业设计项目完整代码

                        String key = String.format("%d-%s", sonarRequest.getHomeworkId(), person.getUid());
                        if (forceParse || (!isChecked(uids, person.getUid())) ) {


                            Row row = new Row();
                            row.i = i;
                            row.key = key;
                            row.person = person;
                            rows.add(row);


                            if (isSonared(key)){
                                writeResult(csvPath, row.i, row.person, row.key, Boolean.FALSE);
                            } else {
                                sonarService.scan(
                                        zipUsePath,
                                        person.getDownloadUrl(),
                                        sonarRequest.getHomeworkId(),
                                        person.getUid(), 1);

                                //毕业设计项目个人开发代码
                                sonarService.scan(
                                        zipUsePath,
                                        person.getDownloadUrl(),
                                        sonarRequest.getHomeworkId(),
                                        person.getUid(),
                                        2);


                                writeResult(csvPath, row.i, row.person, row.key, Boolean.FALSE);
                            }
                        }

                    } catch (Exception e) {
                        log.error("sonar scan error: ", e);
                        log.error("检测出错: {}-{}, 原因: {}",
                                person.getName(),
                                person.getUid(),
                                e.getMessage());

                        writeFailResult(csvPath, i, person, e.getMessage(), Boolean.FALSE);
                    }


                } else {
                    log.error("未发现附件：{}", person);
                    writeFailResult(csvPath, i, person, "没有上传附件", Boolean.FALSE);
                }
            }


        });
    }

    public void sonarSingle(SonarRequest sonarRequest) {
        String codeUsePath = String.format("%s%d/", zipSavePath, sonarRequest.getHomeworkId());

        if (!new File(codeUsePath).exists()) {
            new File(codeUsePath).mkdir();
        }

        String csvPath = codeUsePath + String.format("%d.csv", sonarRequest.getHomeworkId());

        List<String> uids = readAllUids(csvPath);

        executorService.execute(() -> {
            int i = 0;
            for (Person person : sonarRequest.getPersonList()) {
                i++;

                log.info("{}/{} 开始处理: {} ", i, sonarRequest.getPersonList().size(), person);
                if (person.getDownloadUrl().startsWith("http")) {
                    try {

                        String key = String.format("%d-%s", sonarRequest.getHomeworkId(), person.getUid());
                        if (forceParse || (!isChecked(uids, person.getUid())) ) {

                            Row row = new Row();
                            row.i = i;
                            row.key = key;
                            row.person = person;

                            if (isSonaredSingle(key)){

                                //数据库如果有就不检测直接写结果
                                writeResult(csvPath, row.i, row.person, row.key, Boolean.TRUE);
                            } else {
                                sonarService.scanSingle(
                                        codeUsePath,
                                        person.getDownloadUrl(),
                                        sonarRequest.getHomeworkId(),
                                        person.getUid(), key);

                                writeResult(csvPath, row.i, row.person, row.key, Boolean.TRUE);
                            }
                        }
                    } catch (Exception e) {
                        log.error("sonar scan error: ", e);
                        log.error("检测出错: {}-{}, 原因: {}",
                                person.getName(),
                                person.getUid(),
                                e.getMessage());

                        writeFailResult(csvPath, i, person, e.getMessage(), Boolean.TRUE);
                    }
                } else {
                    log.error("未发现附件：{}", person);
                    writeFailResult(csvPath, i, person, "没有上传附件", Boolean.TRUE);
                }
            }
        });
    }

    /**
     * 是否提交过sonar结果
     * @param key
     * @return
     */
    private boolean isSonared(String key) {
        Project project = projectDao.findByName(key+"-2");
        return project!=null;
    }

    private boolean isSonaredSingle(String key) {
        Project project = projectDao.findByName(key);
        return project!=null;
    }

    private void writeFailResult(String filePath, int i, Person person, String message, Boolean isSingle) {
        try {
            StringBuffer stringBuffer = getFailString(i, person, message, isSingle);

            FileWriter fileWritter = new FileWriter(filePath, true);
            fileWritter.write(stringBuffer.toString());
            fileWritter.close();
        } catch (Exception e) {
            log.error("文件写入出错: {}-{}, 原因: {}",
                    person.getName(),
                    person.getUid(),
                    e.getMessage());
        }
    }

    private StringBuffer getFailString(int i, Person person, String message, Boolean isSingle) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(i);
        stringBuffer.append(",");
        stringBuffer.append(person.getUid());
        stringBuffer.append(",");
        stringBuffer.append(person.getName());
        if (isSingle) {
            stringBuffer.append(",,,,,,,,,,,,,,,,,,");
        } else {
            stringBuffer.append(",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,");
        }
        stringBuffer.append(message);
        stringBuffer.append("\n");
        return stringBuffer;
    }

    private void writeResult(String filePath, int i, Person person, String key, Boolean isSingle) {
        try {
            StringBuffer stringBuffer;
            if (isSingle) {
                stringBuffer = getSinglePersonLine(i, person, key);
            } else {
                stringBuffer = getPersonLine(i, person, key);
            }

            FileWriter fileWritter = new FileWriter(filePath, true);
            fileWritter.write(stringBuffer.toString());
            fileWritter.close();
        } catch (Exception e) {
            log.error("文件写入出错: {}-{}, 原因: {}",
                    person.getName(),
                    person.getUid(),
                    e.getMessage());

            writeFailResult(filePath, i, person, e.getMessage(), isSingle);
        }
    }

    private StringBuffer getSinglePersonLine(int i, Person person, String key) {
        Metrics metrics = reportService.getMetrics(key);

        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(i);
        stringBuffer.append(",");
        stringBuffer.append(person.getUid());
        stringBuffer.append(",");
        stringBuffer.append(person.getName());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getViolations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCode_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getComplexity());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getLines());
        stringBuffer.append("\n");

        return stringBuffer;
    }

    private StringBuffer getPersonLine(int i, Person person, String key) {
        Metrics metrics = reportService.getMetrics(key + "-1");

        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(i);
        stringBuffer.append(",");
        stringBuffer.append(person.getUid());
        stringBuffer.append(",");
        stringBuffer.append(person.getName());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getViolations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCode_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getComplexity());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getLines());


        metrics = reportService.getMetrics(key + "-2");
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_bugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBugs());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getViolations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getBlock_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCritical_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMajor_violations());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getMinor_code_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getCode_smells());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getComplexity());
        stringBuffer.append(",");
        stringBuffer.append(metrics.getLines());
        stringBuffer.append("\n");
        return stringBuffer;
    }

    private boolean isChecked(List<String> uids, String uid) {
        for (String s : uids) {
            if (StringUtils.equals(s, uid)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 读取所有的uid
     *
     * @param csvPath
     * @return
     */
    private List<String> readAllUids(String csvPath) {
        List<String> objects = new ArrayList<>();

        if (!new File(csvPath).exists()) return objects;

        try {
            // 使用一个字符串集合来存储文本中的路径 ，也可用String []数组
            FileInputStream fis = new FileInputStream(csvPath);
            // 防止路径乱码   如果utf-8 乱码  改GBK     eclipse里创建的txt  用UTF-8，在电脑上自己创建的txt  用GBK
            InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
            BufferedReader br = new BufferedReader(isr);
            String line = "";
            while ((line = br.readLine()) != null) {
                String[] split = line.split(",");
                if (split.length > 1) {
                    objects.add(split[1]);
                }
            }
            br.close();
            isr.close();
            fis.close();
        } catch (Exception e) {
            log.error("读取uids出错", e);
        }

        return objects;
    }


    /**
     * 修正已有的结果
     * @param fileName
     */
    public void fit(String fileName, String homeworkId) throws Exception {
        String filePath = String.format("%s%s", zipSavePath, fileName);
        if(!new File(filePath).exists()){
            throw new Exception("找不到文件:"+filePath);
        }


        List<String> lines = new ArrayList<>();

        try {
            // 使用一个字符串集合来存储文本中的路径 ，也可用String []数组
            FileInputStream fis = new FileInputStream(filePath);
            // 防止路径乱码   如果utf-8 乱码  改GBK     eclipse里创建的txt  用UTF-8，在电脑上自己创建的txt  用GBK
            InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
            BufferedReader br = new BufferedReader(isr);
            String line = "";
            while ((line = br.readLine()) != null) {
                String[] split = line.split(",");

                if (split.length<3){
                    continue;
                }

                Person person = new Person();
                person.setUid(split[1]);
                person.setName(split[2]);

                int i = Integer.parseInt(split[0]);

                String key = String.format("%s-%s", homeworkId, split[1]);

                if (StringUtils.isNoneEmpty(split[3])) { //有结果
                    //修正结果

                    log.info("开始处理: {}", key);

                    StringBuffer stringBuffer = getPersonLine(
                            i,
                            person,
                            key
                    );
                    lines.add(stringBuffer.toString());
                } else {
                    log.info("重新找查: {}", key);
                    try{
                        StringBuffer stringBuffer = getPersonLine(
                                i,
                                person,
                                key
                        );
                        lines.add(stringBuffer.toString());
                    } catch (Exception e){
                        StringBuffer failString = getFailString(i, person, split[split.length - 1], Boolean.FALSE);
                        lines.add(failString.toString());
                    }

                }

            }
            br.close();
            isr.close();
            fis.close();
        } catch (Exception e) {
            log.error("读取uids出错", e);
        }

        //重新写正确结果
        String newFilePath = String.format("%s%s.new", zipSavePath, fileName);
        try {
            FileWriter fileWritter = new FileWriter(newFilePath, true);

            for (String line : lines) {
                fileWritter.write(line);
            }

            fileWritter.close();
        } catch (Exception e) {
            log.error("文件写入出错 原因: {}",
                    e.getMessage());

        }


    }

    public void scanExcel(String excelPath){
        sonarService.scanExcel(excelPath);
    }

}
