package com.rongwei.trainingcommon.sys.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.utils.StringUtils;
import com.rongwei.training.domain.ExamPaperDo;
import com.rongwei.training.domain.PaperSubjectAssignDo;
import com.rongwei.training.domain.PaperSubjectAutoDo;
import com.rongwei.training.domain.SubjectDo;
import com.rongwei.training.vo.TrainingPaperVo;
import com.rongwei.trainingcommon.sys.dao.ExamPaperDao;
import com.rongwei.trainingcommon.sys.dao.SubjectDao;
import com.rongwei.trainingcommon.sys.service.PaperSubjectAssignService;
import com.rongwei.trainingcommon.sys.service.PaperSubjectAutoService;
import com.rongwei.trainingcommon.sys.service.SubjectService;
import com.rongwei.trainingcommon.sys.service.TrainingExamPaperService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * TrainingExamPaperServiceImpl class
 *
 * @author XH
 * @date 2020/12/02
 */
@Service("trainingExamPaperService")
public class TrainingExamPaperServiceImpl extends ServiceImpl<ExamPaperDao, ExamPaperDo> implements TrainingExamPaperService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SubjectService subjectService;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private PaperSubjectAssignService paperSubjectAssignService;
    @Autowired
    private PaperSubjectAutoService paperSubjectAutoService;

    public static final Long ZERO= 0L;

    @Override
    public R questionCheck(TrainingPaperVo vo) {
        // 固定题目
        List<PaperSubjectAssignDo> paperSubjectAssignDos = vo.getPapersubjectassigndos();
        // 随机题目
        List<PaperSubjectAutoDo> paperSubjectAutoDos = vo.getPapersubjectautodos();
        logger.info("固定题目信息: {}", paperSubjectAssignDos);
        logger.info("随机题目信息: {}", paperSubjectAutoDos);
        // 当随机题目不为空时
        if (paperSubjectAutoDos == null || paperSubjectAutoDos.isEmpty()) {
            return R.ok();
        }
        // 存放考题类型和所需要的题目数量
        Map<String, Long> subjectTypeAndNum = paperSubjectAutoDos.stream()
                .filter(info->StringUtils.isNotBlank(info.getCoursethemeid()))
                .collect(Collectors.groupingBy(info -> info.getSubjecttype(),
                Collectors.summingLong(PaperSubjectAutoDo::getThemesubjectnum)));
        if (paperSubjectAssignDos != null && !paperSubjectAssignDos.isEmpty()) {
            Map<String, Long> collect = paperSubjectAssignDos.stream()
                    .filter(info->StringUtils.isNotBlank(info.getCourseid()))
                    .collect(Collectors.groupingBy(info -> info.getSubjecttype(),
                    Collectors.counting()));
            collect.forEach((key, value) -> subjectTypeAndNum.merge(key, value, (prev, one) -> prev + one));
        }
        // 获取课程Id
        List<String> courseThemeId = paperSubjectAutoDos.stream().map(PaperSubjectAutoDo::getCoursethemeid).collect(Collectors.toList());
        courseThemeId.addAll(paperSubjectAssignDos.stream().map(PaperSubjectAssignDo::getCourseid).collect(Collectors.toList()));
        // 获取随机题目中课程主题的所有题目信息
        List<SubjectDo> subjectDoList = subjectDao.selectInfoByCourseIds(courseThemeId);
        // 获取所有课程主题下 各类型题目的数量
        Map<String, Long> subjectMap = subjectDoList.stream().collect(Collectors.groupingBy(info -> info.getSubjecttype(), Collectors.counting()));

        for (Map.Entry<String, Long> entry : subjectTypeAndNum.entrySet()) {
            String k = entry.getKey();
            Long v = entry.getValue();
            if (v > subjectMap.getOrDefault(k, ZERO)) {
                return R.errorWithMsg("题目数量不够");
            }
        }
        // 校验题目数量是否足够
        String courseThemeName = questionCheck(paperSubjectAssignDos, paperSubjectAutoDos, subjectDoList);
        if (StringUtils.isNotBlank(courseThemeName)) {
         return R.errorWithMsg(courseThemeName + "的题目数不够");
        }
        return R.ok();
    }

    @Override
    public R saveorupdate(TrainingPaperVo vo) {
        logger.info("开始保存试卷信息和题目");
        // 固定题目
        List<PaperSubjectAssignDo> paperSubjectAssignDos = vo.getPapersubjectassigndos();
        // 随机题目
        List<PaperSubjectAutoDo> paperSubjectAutoDos = vo.getPapersubjectautodos();
        ExamPaperDo examPaperDo = new ExamPaperDo();
        BeanUtils.copyProperties(vo, examPaperDo);
        this.saveOrUpdate(examPaperDo);
        logger.info("试卷保存成功");
        if (paperSubjectAssignDos != null && !paperSubjectAssignDos.isEmpty()) {
            paperSubjectAssignDos.forEach(paperSubjectAssignDo -> {
                paperSubjectAssignDo.setPaperid(vo.getId());
            });
            paperSubjectAssignService.saveOrUpdateBatch(paperSubjectAssignDos, 10);
            logger.info("固定题目关联成功");
        }
        if (paperSubjectAutoDos != null && !paperSubjectAutoDos.isEmpty()) {
            paperSubjectAutoDos.forEach(paperSubjectAutoDo -> {
                paperSubjectAutoDo.setPaperid(vo.getId());
            });
            paperSubjectAutoService.saveOrUpdateBatch(paperSubjectAutoDos, 10);
            logger.info("随机题目关联成功");
        }
        return R.ok();
    }

    /**
     * 所需题目数校验
     *
     * @param paperSubjectAssignDos
     * @param paperSubjectAutoDos
     * @return
     */
    public String questionCheck(List<PaperSubjectAssignDo> paperSubjectAssignDos, List<PaperSubjectAutoDo> paperSubjectAutoDos, List<SubjectDo> subjectDoList) {

        logger.info("课程对应的题目信息: {}", subjectDoList);
        // 按照课程ID 和课程类型进行分组 获取每个课程和题目类型 所拥有的题目数量
        // 是否需要校验固定题目数量
        boolean assignSubjectCheck = paperSubjectAssignDos != null && !paperSubjectAssignDos.isEmpty();
        // 随机题目按照课程ID和 题目类型进行分组
        Map<String, List<PaperSubjectAutoDo>> collect = paperSubjectAutoDos.stream().collect(Collectors.groupingBy(autoSubject -> autoSubject.getCoursethemeid() + ";" + autoSubject.getSubjecttype()));
        for (Map.Entry<String, List<PaperSubjectAutoDo>> map : collect.entrySet()) {
            // 该考题所分配的数量
            int subjectNum = map.getValue().stream().mapToInt(PaperSubjectAutoDo::getThemesubjectnum).sum();
            // 题目类型
            String subjectType = map.getValue().get(0).getSubjecttype();
            // 课程Id
            String courseId = map.getValue().get(0).getCoursethemeid();
            String courseThemeName = map.getValue().get(0).getCoursethemename();
            // 校验固定题目中是否还有相同类型的题目 (1.课程主题一致,2.考题类型一致)
            int assignSubjectNum = 0;
            if (assignSubjectCheck) {
                // 获取固定题目中取出的题目数量
                assignSubjectNum = (int) paperSubjectAssignDos
                        .stream()
                        .filter(assignDo -> courseId.equals(assignDo.getCourseid()) && assignDo.getSubjecttype().equals(subjectType))
                        .count();
            }
            // 获取题库中当前课程主题下有多少道题目类型相同的题
            int count = (int) subjectDoList.stream().filter(subjectDo -> subjectDo.getSubjectcourseids().contains(courseId) && subjectDo.getSubjecttype().equals(subjectType)).count();
            logger.info("当前试卷从课程:{}从取出题目类型为:{}的随机题目: {}道，取出固定题目：{}道，当前题库中共有：{}道", courseThemeName, subjectType, subjectNum, assignSubjectNum, count);
            if (count < subjectNum + assignSubjectNum) {
                logger.error("{}题目数不够", courseThemeName);
                return courseThemeName;
            }
        }
        return "";
    }
}
