package com.mooctest.controller;

import com.hankcs.hanlp.mining.cluster.ClusterAnalyzer;
import com.mooctest.data.BugDTO;
import com.mooctest.data.BugHistoryDTO;
import com.mooctest.data.ReportDTO;
import com.mooctest.service.BugHistoryService;
import com.mooctest.service.BugReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@RestController
public class HelloController {

    @Autowired
    BugReportService bugReportService;

    @Autowired
    BugHistoryService bugHistoryService;

    @RequestMapping("/hello")
    public List<Double> hello(@RequestParam String algorithm) {

        List<BugDTO> bugs = bugReportService.getAllBugs(2613, 1489);

        ClusterAnalyzer<String> analyzer = new ClusterAnalyzer<String>();
        bugs.forEach(bugDTO -> analyzer.addDocument(bugDTO.getId(), bugDTO.getDescription()));

        List<String> bugIds = bugs.stream().map(BugDTO::getId).collect(Collectors.toList());
        List<BugHistoryDTO> his = bugHistoryService.getBugHistory(bugIds);
//        System.out.println("kmeans:");
//        showClusterResult(analyzer.kmeans(25), bugs);

//        System.out.println("bisection:");
//        showClusterResult(analyzer.repeatedBisection(10), bugs);
//
//        System.out.println("bisection-auto:");
//        showClusterResult(analyzer.repeatedBisection(1.0), bugs);

        List<Set<String>> clusters = null;
        if (algorithm.equals("bi-auto")) {

            clusters = analyzer.repeatedBisection(1.0);
        } else if (algorithm.equals("kmeans")) {
            clusters = analyzer.kmeans(30);
        }
        List<Double> scores = evaluateCluster(clusters, his, bugs);
        return scores;
    }


    public void showClusterResult(List<Set<String>> results, List<BugDTO> bugs) {
        System.out.println("size: " + results.size());
        results.forEach(cluster -> {
            System.out.println("[");
            cluster.forEach(bugId -> {
                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
                System.out.println(result.get(0).getDescription());
            });
            System.out.println("]");
        });
    }

    public List<Double> evaluateCluster(List<Set<String>> clusters, List<BugHistoryDTO> his, List<BugDTO> bugs) {

        Map<String, Long> treeSize = his.stream().collect(Collectors.groupingBy(BugHistoryDTO::getRoot, Collectors.counting()));

        Map<String, String> treeRootMap = his.stream().collect(Collectors.toMap(BugHistoryDTO::getId, BugHistoryDTO::getRoot));
        return clusters.stream().map(cluster -> {

            System.out.println("[");

            cluster.forEach(bugId -> {
                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
                System.out.println(bugId + " " + result.get(0).getDescription());
            });
            System.out.println();

            Set<String> roots = cluster.stream()
                    .filter(bugId -> treeRootMap.get(bugId) != null)
                    .map(bugId -> treeRootMap.get(bugId))
                    .filter(rootId -> treeSize.get(rootId) > 1)
                    .collect(Collectors.toSet());

            roots.forEach(bugId -> {
                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
                System.out.println(bugId + " " + result.get(0).getDescription());
            });

            long totalTreeBugs = roots.stream()
                    .mapToLong(rootBugId -> treeSize.get(rootBugId))
                    .sum();
            if (totalTreeBugs == 0) {
                return 0.0;
            }
            long bugOfTreeCounts = cluster.stream()
                    .filter(bugId -> treeRootMap.get(bugId) != null)
                    .map(bugId -> treeRootMap.get(bugId))
                    .filter(rootId -> treeSize.get(rootId) > 1)
                    .count();

            System.out.println("result" + ((bugOfTreeCounts * 1.0) / totalTreeBugs));
            System.out.println("]");
            return (bugOfTreeCounts * 1.0) / totalTreeBugs;
        })
                .sorted((d1, d2) -> Double.compare(d2, d1))
                .collect(Collectors.toList());
    }

}
