package com.mooctest.service;

import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
import com.mooctest.dao.MasterReportDao;
import com.mooctest.data.BugDTO;
import com.mooctest.model.MasterReport;
import com.mooctest.util.Doc2VecUtil;
import org.jgrapht.alg.interfaces.VertexScoringAlgorithm;
import org.jgrapht.alg.scoring.PageRank;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.DirectedWeightedPseudograph;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class MasterReportService {
    @Autowired
    MasterReportDao masterReportDao;

    public String findMasterReport(Set<String> cluster, Map<String, BugDTO> bugMap) {
        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g = buildDirectedGraph(cluster, bugMap);

        VertexScoringAlgorithm<String, Double> pr = new PageRank<>(g, 0.85, 100, 0.0001);


        String masterId = pr.getScores().entrySet()
                .stream()
                .max(Comparator.comparing(Map.Entry::getValue))
                .get()
                .getKey();

        if (masterId.equals("10010000035194")) {
            System.out.println();
        }
        return masterId;
    }

    public DirectedWeightedPseudograph buildDirectedGraph(Set<String> cluster, Map<String, BugDTO> bugMap) {
        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g =
                new DirectedWeightedPseudograph<>(DefaultWeightedEdge.class);

        cluster.forEach(bugId -> g.addVertex(bugId));

        cluster.forEach(outBugId -> {
            cluster.forEach(inBugId -> {
                if (!outBugId.equals(inBugId) && !g.containsEdge(outBugId, inBugId)) {
                    g.setEdgeWeight(g.addEdge(outBugId, inBugId), getSim(outBugId, inBugId, bugMap));
                }
            });
        });
        return g;
    }
    public double getSim(String bugId1, String bugId2, Map<String, BugDTO> bugMap) {
        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
        return docVectorModel.similarity(bugMap.get(bugId1).getDescription(), bugMap.get(bugId2).getDescription());
    }

    public void saveMasterReport(String masterId, long examId, long caseId, Set<String> bugIds) {

        List<MasterReport> mrs = new ArrayList<>(bugIds.size() + 1);
        bugIds.forEach(bugId -> {

            MasterReport mr = MasterReport.builder()
                    .masterId(masterId)
                    .examId(examId)
                    .caseId(caseId)
                    .bugId(bugId)
                    .build();
            mrs.add(mr);
        });
        masterReportDao.save(mrs);
    }

    public long[] getExamIdAndCaseIdByMasterId(String masterId) {
        List<MasterReport> mrs = masterReportDao.findByMasterId(masterId);
        MasterReport mr = mrs.stream().findAny().get();
        long[] ids = new long[2];
        ids[0] = mr.getExamId();
        ids[1] = mr.getCaseId();
        return ids;
    }

    public List<String> getAllMasterIdByExamIdAndCaseId(long examId, long caseId) {
        List<MasterReport> mr = masterReportDao.findByExamIdAndCaseId(examId, caseId);
        return mr.stream()
                .map(MasterReport::getMasterId)
                .distinct()
                .collect(Collectors.toList());
    }

    public Map<String, List<String>> getMaster2BugIdsMap(List<String> masterIds) {
        List<MasterReport> mrs = masterReportDao.findByMasterIdIn(masterIds);
        return mrs.stream().collect(
                Collectors.groupingBy(
                        MasterReport::getMasterId,
                        Collectors.mapping(MasterReport::getBugId, Collectors.toList())));

    }

    public List<String> getAllBugIdsByMasterId(String masterId) {
        List<MasterReport> mrs = masterReportDao.findByMasterId(masterId);
        return mrs.stream().map(MasterReport::getBugId).collect(Collectors.toList());
    }

    public List<MasterReport> getByBugIds(List<String> bugIds) {
        return masterReportDao.findByBugIdIn(bugIds);

    }

    public MasterReport getByBugId(String bugId) {
        return masterReportDao.findByBugId(bugId);
    }

    public boolean isAggregated(long examId, long caseId) {
        long numOfAggReport = masterReportDao.countByExamIdAndCaseId(examId, caseId);
        return numOfAggReport > 0;
    }
    public void deleteAll(long examId, long caseId) {
        masterReportDao.deleteByExamIdAndCaseId(examId, caseId);
    }

    public long getAggNum(long examId, long caseId) {
        List<MasterReport> mrs = masterReportDao.findByExamIdAndCaseId(examId, caseId);
        return mrs.stream().map(MasterReport::getMasterId).distinct().count();
    }
}
