package com.mooctest.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.common.Term;
import com.mooctest.data.BugDTO;
import com.mooctest.data.FinalReportDTO;
import com.mooctest.data.SupplementDTO;
import com.mooctest.data.TaskDTO;
import com.mooctest.model.MasterReport;
import com.mooctest.service.*;
import com.mooctest.util.NLPUtil;
import com.mooctest.util.ReportUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toMap;

@Controller
public class ReportController {

    @Autowired
    SupplementService supplementService;

    @Autowired
    BugReportService bugReportService;

    @Autowired
    MasterReportService masterReportService;

    @Autowired
    FinalReportService finalReportService;

    @Autowired
    BugReviewService bugReviewService;

    @Autowired
    TaskService taskService;

    @GetMapping(value = "/index")
    public String hello(HttpServletRequest request, @RequestParam(value = "name", required = false, defaultValue = "springboot-thymeleaf") String name) {
        request.setAttribute("name", name);
        return "index";
    }



    @GetMapping(value = "/report")
    public String showAggrReport(@RequestParam("masterId") String masterId,
                                 @RequestParam("examId") long examId,
                                 @RequestParam("caseId") long caseId,
                                 @RequestParam(value = "finalReportId", required = false) Long finalReportId,
                                 Model model) {
        Map<String, BugDTO> bugMap = bugReportService.getAllBugsMap(examId, caseId);
        BugDTO masterReport = bugMap.get(masterId);

        List<SupplementDTO> supplements = supplementService.getSupplementByMasterId(masterId, bugMap);

        List<BugDTO> bugs = new LinkedList<>();
        supplements.forEach(supplementDTO -> bugs.addAll(supplementDTO.getBugs()));
        List<BugDTO> sourceReports = bugs.stream().distinct().collect(Collectors.toList());
        Map<String, Long> categoryCounts = sourceReports.stream().collect(Collectors.groupingBy(BugDTO::getBugCategory, Collectors.counting()));
        Map<String, Long> severityCounts = sourceReports.stream()
                .map(BugDTO::getSeverity)
                .map((severityNum) -> ReportUtil.severity2String.get(severityNum))
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        List<FinalReportDTO> finalReports = finalReportService.getBySourceId(masterId);

        model.addAttribute("wordList", getWordCloudList(sourceReports));
        model.addAttribute("categoryCounts", categoryCounts);
        model.addAttribute("severityCounts", severityCounts);
        model.addAttribute("aggReportId", "ML-AG-" + masterId.substring(10));
        model.addAttribute("masterReport", masterReport);
        model.addAttribute("createTime", new Date(Long.parseLong(masterReport.getCreateTimeMillis())));
        model.addAttribute("supplements", supplements);
        model.addAttribute("finalReports", finalReports);
        model.addAttribute("category2String", ReportUtil.category2String);
        model.addAttribute("recurrent2String", ReportUtil.recurrent2String);
        model.addAttribute("severity2String", ReportUtil.severity2String);
        model.addAttribute("examId", examId);
        model.addAttribute("caseId", caseId);

        boolean bugReviewed = bugReviewService.isBugReviewed(masterId);
        model.addAttribute("reviewed", bugReviewed);
        if (finalReportId != null) {
            Optional<FinalReportDTO> finalReportDTO = finalReports.stream().filter(finalReport -> finalReport.getId()==finalReportId).findFirst();
            model.addAttribute("finalReportId", finalReportId);
            model.addAttribute("editReport", finalReportDTO.get());

        }
        return "agg_report_new";
    }

    private String getWordCloudList(List<BugDTO> sourceReports) {
        Map<String, Integer> wordCount = new HashMap<>();
        Set<String> stopWords = new HashSet<>();
        try {
            File file = ResourceUtils.getFile("classpath:stopwords.txt");
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String line;
            while ((line = reader.readLine()) != null) {
                stopWords.add(line.trim());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        sourceReports.forEach((bug) -> {
            Segment seg = NLPUtil.getDefaultSegment();
            List<Term> terms = seg.seg(bug.getDescription());
            for (Term term : terms) {
                if (stopWords.contains(term.word)) {
                    continue;
                }
                if (wordCount.get(term.word) == null) {
                    wordCount.put(term.word, 1);
                    continue;
                }
                int count = wordCount.get(term.word);
                wordCount.put(term.word, ++count);
            }
        });
        JSONArray wordList = new JSONArray();
        wordCount.forEach((word, count) -> {

            if (word.length() > 1) {

                JSONObject wordObj = new JSONObject();
                wordObj.fluentPut("text", word)
                        .fluentPut("weight", count * 10);
                wordList.add(wordObj);
            }

        });

        return wordList.toJSONString();
    }

    @GetMapping(value = "agg_report_list")
    public String showAggReportList(@RequestParam("examId") long examId,
                                    @RequestParam("caseId") long caseId,
                                    @RequestParam(value = "status", required = false, defaultValue = "-1") int status,
                                    Model model) {
        List<String> masterIds = masterReportService.getAllMasterIdByExamIdAndCaseId(examId, caseId);
        List<MasterReport> mrs = masterReportService.getByBugIds(masterIds);
        Map<String, MasterReport> mrMap = mrs.stream().collect(toMap(MasterReport::getBugId, Function.identity()));
        if (status >= 0) {
            masterIds = masterIds.stream().filter(masterId -> mrMap.get(masterId).getStatus() == status).collect(Collectors.toList());
        }

//        Map<String, List<String>> master2BugIdsMap = supplementService.getMaster2BugIdsMap(masterIds);
        Map<String, List<String>> master2BugIdsMap = masterReportService.getMaster2BugIdsMap(masterIds);
        Map<String, BugDTO> bugsMap = bugReportService.getAllBugsMap(examId, caseId);

//        Map<String, List<BugDTO>> masterBugMap = bugReportService.getMasterBugMap(master2BugIdsMap, bugsMap);
        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);


        masterIds.forEach(masterId -> {

            bugsMap.get(masterId).setStatus(mrMap.get(masterId).getStatus());
        });


        model.addAttribute("master2BugIdsMap", master2BugIdsMap);
        model.addAttribute("bugMap", bugsMap);
        model.addAttribute("examId", examId);
        model.addAttribute("caseId", caseId);
        model.addAttribute("task", task);
        model.addAttribute("aggNum", masterReportService.getAggNum(examId, caseId));
        return "agg_report_list";
    }
}
