package com.mooctest.service;

import com.mooctest.cluster.ClusterAnalyzer;
import com.mooctest.cluster.Group;
import com.mooctest.data.BugDTO;
import com.mooctest.data.DiffImg;
import com.mooctest.data.DiffText;
import com.mooctest.data.ReportDTO;
import com.mooctest.image.ImageDownload;
import com.mooctest.nlp.DistanceMatrix;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

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

@Service
public class AggregationService {
    @Autowired
    BugReportService bugReportService;

    @Autowired
    MasterReportService masterReportService;

    @Autowired
    DiffTextService diffTextService;

    @Autowired
    DiffImgService diffImgService;

    @Autowired
    SupplementService supplementService;

    public void aggregate(long examId, long caseId) {
        downImg(examId, caseId);
        List<BugDTO> bugs = bugReportService.getAllBugs(examId, caseId);

        ClusterAnalyzer<String> analyzer = new ClusterAnalyzer<>();
        List<String> bugIds = bugs.stream().map(BugDTO::getId).collect(Collectors.toList());
        double[][] distMatrix = DistanceMatrix.genHybridDist(bugs);
        List<Set<String>> clusters = analyzer.HAC(distMatrix, bugIds, 0.23);

        Map<String, BugDTO> bugMap = bugs.stream().collect(toMap(BugDTO::getId, Function.identity()));
        bugs = null;
        Map<String, Set<String>> masterClusterMap = new HashMap<>();
        masterReportService.deleteAll(examId, caseId);
        for (Set<String> cluster : clusters) {
            String masterReport = masterReportService.findMasterReport(cluster, bugMap);
            masterReportService.saveMasterReport(masterReport, examId, caseId, cluster);
            masterClusterMap.put(masterReport, cluster);
        }
        clusters = null;

        showClusterResult(masterClusterMap, bugMap);

        //gen diff text
        Map<String, List<DiffText>> masterDiffTextMap = diffTextService.genMasterDiffTextMap(masterClusterMap, bugMap);

        showTextDiffResult(masterDiffTextMap, bugMap);

        //gen diff img
        Map<String, List<DiffImg>> masterDiffImgMap = diffImgService.genMasterDiffImgMap(masterClusterMap, bugMap);

        //cluster diff text
        Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap = diffTextService.genDiffTextClusters(masterDiffTextMap);

        //cluster diff img
        Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap = diffImgService.genDiffImgClusters(masterDiffImgMap);

        //combine cluster
        combineCluster(masterDiffTextClustersMap, masterDiffImgClustersMap);

        //top
        supplementService.deleteAll(examId, caseId);
        supplementService.rankAndStoreDiffText(masterDiffTextClustersMap);
        supplementService.rankAndStoreDiffImg(masterDiffImgClustersMap);
    }

    private void combineCluster(Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap,
                                Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap) {
        double LINK_THRESHOLD = 0.2;
        masterDiffTextClustersMap.forEach((masterId, diffTextClusters) -> {
            List<Group<String, DiffImg>> diffImgClusters = masterDiffImgClustersMap.get(masterId);
            if (diffImgClusters != null) {

                for (int i = 0; i < diffTextClusters.size(); i++) {
                    Set<String> textBugIds = diffTextClusters.get(i).getCluster().stream().map(DiffText::getBugId).collect(Collectors.toSet());
                    for (int j = 0; j < diffImgClusters.size(); j++) {
                        Set<String> imgBugIds = diffImgClusters.get(j).getCluster().stream().map(DiffImg::getBugId).collect(Collectors.toSet());
                        int inter = CollectionUtils.intersection(textBugIds, imgBugIds).size();
                        int union = CollectionUtils.union(textBugIds, imgBugIds).size();
                        double dist = 1.0 - (1.0 * inter) / (1.0 * union);
                        if (dist > LINK_THRESHOLD) {
                            diffImgClusters.get(j).setId(diffTextClusters.get(i).getId());
                        }
                    }
                }
            }
        });
    }

    private void downImg(long examId, long caseId) {

        String taskId = examId + "_" + caseId;
        List<BugDTO> bugs = bugReportService.getAllBugs(examId, caseId);

        bugs.forEach(bug -> {
            if (bug.getImgUrls() != null && bug.getImgUrls().length > 0) {
                String[] imgUrls = bug.getImgUrls();
                for (int i = 0; i < imgUrls.length; i++) {
                    if (imgUrls[i] == null || !imgUrls[i].startsWith("http")) {
                        continue;
                    }

                    String fileName = bug.getId() + "_" + i;
                    System.out.println("正在下载 " + fileName);
                    try {

                        ImageDownload.createImage(imgUrls[i], taskId, fileName);
                    } catch (Exception e) {
                        System.out.println(imgUrls[i]);
                        e.printStackTrace();
                    }
                }

            }
        });
    }

    private void showClusterResult(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
        System.out.println("showMasterReportResult:");
        masterClusterMap.entrySet().forEach(entry -> {
            System.out.println("[");
            System.out.println("master:");
            System.out.println(entry.getKey() + " " + bugMap.get(entry.getKey()).getDescription());
            System.out.println();

            entry.getValue().forEach(bugId -> {
                System.out.println(bugId + " " + bugMap.get(bugId).getDescription());
            });
            System.out.println("]");
        });

    }


    private void showTextDiffResult(Map<String, List<DiffText>> masterDiffTextMap, Map<String, BugDTO> bugMap) {
        System.out.println("showDiffResult:");
        masterDiffTextMap.entrySet().forEach(entry -> {
            System.out.println("[");
            System.out.println("master:");
            System.out.println(entry.getKey() + " " + bugMap.get(entry.getKey()).getDescription());
            System.out.println();

            entry.getValue().forEach(diffText -> {
                System.out.println(diffText.getBugId() + "_" + diffText.getIndex() + diffText.getSentence());
            });
            System.out.println("]");
        });

    }
    private void showClusterResult(List<Set<String>> results, Map<String, BugDTO> bugMap) {
        System.out.println("size: " + results.size());
        results.forEach(cluster -> {
            System.out.println("[");
            cluster.forEach(bugId -> {
                System.out.println(bugId + " " + bugMap.get(bugId).getDescription());
            });
            System.out.println("]");
        });
    }
}
