package com.ynfy.buss.exam.examstatistics.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ynfy.buss.exam.exam.entity.Exam;
import com.ynfy.buss.exam.exam.enums.ExamOpenType;
import com.ynfy.buss.exam.exam.service.IExamService;
import com.ynfy.buss.exam.examstatistics.dto.ExamStatisticsDTO;
import com.ynfy.buss.exam.examstatistics.entity.ExamStatistics;
import com.ynfy.buss.exam.examstatistics.mapper.ExamStatisticsMapper;
import com.ynfy.buss.exam.examstatistics.service.IExamStatisticsService;
import com.ynfy.buss.exam.examuserstatistics.entity.ExamUserStatistics;
import com.ynfy.buss.exam.examuserstatistics.service.IExamUserStatisticsService;
import com.ynfy.buss.exam.userexamquestion.entity.UserExamQuestion;
import com.ynfy.buss.exam.userexamquestion.service.IUserExamQuestionService;
import org.apache.commons.lang.StringUtils;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

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

/**
 * @Description: 考试统计表
 * @Author: jeecg-boot
 * @Date: 2023-03-20
 * @Version: V1.0
 */
@Service
public class ExamStatisticsServiceImpl extends ServiceImpl<ExamStatisticsMapper, ExamStatistics> implements IExamStatisticsService {

    @Autowired
    private IExamService examService;

    @Autowired
    private ExamStatisticsMapper examStatisticsMapper;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IUserExamQuestionService userExamQuestionService;

    @Autowired
    private IExamUserStatisticsService examUserStatisticsService;

    /**
     * 计算考试各维度指标
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<ExamStatisticsDTO> calcExamDimension(String examId) {
        Exam exam = examService.getById(examId);
        //考试结果统计
        List<ExamStatisticsDTO> userExamList = examStatisticsMapper.calcExamDimension(examId);
        if (CollectionUtils.isEmpty(userExamList)) {
            return null;
        }
        List<String> userExamIds = userExamList.stream().map(ExamStatisticsDTO::getUserExamId).collect(Collectors.toList());
        List<UserExamQuestion> userExamQuestionList = userExamQuestionService.listByUserExamIds(userExamIds);
        //考试统计计算
        ExamStatistics examStatistics = calcExamStatistics(exam, userExamList, userExamQuestionList);
        //考试用户统计计算
        List<ExamUserStatistics> examUserStatisticsList = generareExamUserStatistics(userExamQuestionList, userExamList);
        removeByExamId(examId);
        examUserStatisticsService.removeByExamId(examId);
        save(examStatistics);
        examUserStatisticsService.saveBatch(examUserStatisticsList);
        return userExamList;
    }

    /**
     * 考试统计计算
     *
     * @param exam
     * @param userExamList
     * @return
     */
    public ExamStatistics calcExamStatistics(Exam exam, List<ExamStatisticsDTO> userExamList, List<UserExamQuestion> userExamQuestionList) {
        ExamStatistics examStatistics = new ExamStatistics();
        examStatistics.setExamId(exam.getId());
        examStatistics.setExamTitle(exam.getTitle());
        examStatistics.setExamState(exam.getState());
        examStatistics.setActualExaminee(userExamList.size());
        examStatistics.setMaxScore(userExamList.stream().mapToInt(ExamStatisticsDTO::getUserScore).max().getAsInt());
        examStatistics.setMinScore(userExamList.stream().mapToInt(ExamStatisticsDTO::getUserScore).min().getAsInt());
        examStatistics.setParticipant(userExamList.stream().mapToInt(ExamStatisticsDTO::getTryCount).sum());//参加人次
        examStatistics.setAvgScore(userExamList.stream().mapToDouble(ExamStatisticsDTO::getUserScore).average().getAsDouble());
        int passNum = userExamList.stream().filter(o -> o.getPassed().equals(1)).collect(Collectors.toList()).size();
        int noPassNum = userExamList.stream().filter(o -> o.getPassed().equals(0)).collect(Collectors.toList()).size();
        examStatistics.setPass(passNum);
        examStatistics.setNoPass(noPassNum);
        examStatistics.setPassPercent(NumberUtil.div(multi(passNum), userExamList.size(), 2));
        examStatistics.setNopassPercent(NumberUtil.div(multi(noPassNum), userExamList.size(), 2));
        //准确率
        examStatistics.setAccuracy(calcExamAccuracy(userExamQuestionList));
        if (StringUtils.isNotBlank(exam.getExaminer())) {
            String[] examer = exam.getExaminer().split(",");
            if (exam.getOpenType().equals(ExamOpenType.ASSIGN_DEPT)) {//指定部门
                List<SysUser> users = sysUserService.getUserByDepIds(Arrays.asList(examer), null);
                examStatistics.setMustExaminee(!CollectionUtils.isEmpty(users) ? users.size() : 0);
            } else if (exam.getOpenType().equals(ExamOpenType.ASSIGN_USER)) {
                examStatistics.setMustExaminee(examer.length);
            }
            if (!Objects.isNull(examStatistics.getMustExaminee())) {
                examStatistics.setActualPercent(NumberUtil.div(multi(examStatistics.getActualExaminee().intValue()),
                        examStatistics.getMustExaminee().intValue(), 2));
            }
        }
        if (!Objects.isNull(examStatistics.getMustExaminee()) && !Objects.isNull(examStatistics.getActualExaminee())) {
            int missNum = examStatistics.getMustExaminee() - examStatistics.getActualExaminee();
            examStatistics.setMissExaminee(missNum);
            examStatistics.setMissPercent(NumberUtil.div(multi(missNum), examStatistics.getMustExaminee().intValue(), 2));
        }
        return examStatistics;
    }


    /**
     * 考试用户统计
     *
     * @param userExamQuestionList
     * @param userExamList
     * @return
     */
    public List<ExamUserStatistics> generareExamUserStatistics(List<UserExamQuestion> userExamQuestionList, List<ExamStatisticsDTO> userExamList) {
        List<ExamUserStatistics> examUserStatisticsList = new ArrayList<>();
        Map<String, List<UserExamQuestion>> ueqMap = userExamQuestionList.stream().collect(Collectors
                .groupingBy(UserExamQuestion::getUserExamId, Collectors.toList()));
        int rank = 1;

        //查询用户所属机构
        List<String> userIdList = userExamList.stream().map(ExamStatisticsDTO::getUserId).collect(Collectors.toList());
        Map<String, String> userMap = sysUserService.getDepNamesByUserIds(userIdList);

        for (ExamStatisticsDTO dto : userExamList) {
            ExamUserStatistics examUserStatistics = new ExamUserStatistics();
            BeanUtils.copyProperties(dto, examUserStatistics);
            examUserStatistics.setAccuracy(calcUserAccuracy(ueqMap, dto));
            examUserStatistics.setScoreRate(calcScoreRate(ueqMap, dto));
            examUserStatistics.setOrgName(!Objects.isNull(userMap) ? userMap.get(dto.getUserId()) : null);
            examUserStatistics.setRank(rank);
            examUserStatistics.setPassedText(dto.getPassed() == 1 ? "通过" : "未通过");
            examUserStatistics.setId(null);
            examUserStatisticsList.add(examUserStatistics);
            rank++;
        }
        return examUserStatisticsList;
    }

    /**
     * 计算考试正确率
     *
     * @param userExamQuestionList
     * @return
     */
    public Double calcExamAccuracy(List<UserExamQuestion> userExamQuestionList) {
        if (CollectionUtils.isEmpty(userExamQuestionList)) {
            return null;
        }
        long rightNum = userExamQuestionList.stream().filter(o -> !Objects.isNull(o.getIsRight()) && o.getIsRight()).count();
        return NumberUtil.div(multi(rightNum), userExamQuestionList.size(), 2);
    }

    /**
     * 计算用户正确率
     *
     * @return
     */
    public Double calcUserAccuracy(Map<String, List<UserExamQuestion>> ueqMap, ExamStatisticsDTO dto) {
        List<UserExamQuestion> questions = ueqMap.get(dto.getUserExamId());
        if (!CollectionUtils.isEmpty(questions)) {
            long rightNum = questions.stream().filter(o -> !Objects.isNull(o.getIsRight()) && o.getIsRight()).count();
            return NumberUtil.div(multi(rightNum), questions.size(), 2);
        }
        return null;
    }

    /**
     * 计算得分率
     *
     * @return
     */
    public Double calcScoreRate(Map<String, List<UserExamQuestion>> ueqMap, ExamStatisticsDTO dto) {
        List<UserExamQuestion> questions = ueqMap.get(dto.getUserExamId());
        if (!CollectionUtils.isEmpty(questions)) {
            int userScoreTotal = questions.stream().filter(o -> !Objects.isNull(o.getIsRight()) && o.getIsRight())
                    .mapToInt(UserExamQuestion::getQuestionScore).sum();
            int scoreTotal = questions.stream().mapToInt(UserExamQuestion::getQuestionScore).sum();
            return NumberUtil.div(multi(userScoreTotal), scoreTotal, 2);
        }
        return null;
    }

    public void removeByExamId(String examId) {
        LambdaQueryWrapper<ExamStatistics> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamStatistics::getExamId, examId);
        this.remove(wrapper);
    }

    /**
     * 乘以100
     *
     * @param a
     * @return
     */
    public double multi(long a) {
        return NumberUtil.mul(a, 100);
    }
}
