package com.zd.exam.service.impl;

import com.zd.common.core.constant.HttpStatus;
import com.zd.common.core.constant.SecurityConstants;
import com.zd.common.core.domain.R;
import com.zd.common.core.domain.per.PerPrefix;
import com.zd.common.core.exception.NoRollException;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.*;
import com.zd.common.datascope.annotation.DataScope;
import com.zd.common.security.service.TokenService;
import com.zd.exam.domain.*;
import com.zd.exam.domain.vo.ChapterLearnVo;
import com.zd.exam.domain.vo.ElPaperAssessVo;
import com.zd.exam.enums.ConvertType;
import com.zd.exam.enums.PaperState;
import com.zd.exam.enums.QuType;
import com.zd.exam.enums.ScopeType;
import com.zd.exam.mapper.*;
import com.zd.exam.service.*;
import com.zd.exam.service.convert.BonusPointsService;
import com.zd.exam.service.convert.ConvertTimingService;
import com.zd.system.api.RemoteUserService;
import com.zd.system.api.domain.SysUser;
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 org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 试卷管理Service业务层处理
 *
 * @author liubo
 * @date 2021-08-31
 */
@Service
public class ElPaperServiceImpl implements IElPaperService {
    private static final Logger logger = LoggerFactory.getLogger(ElPaperServiceImpl.class);
    @Autowired
    private ElPaperMapper elPaperMapper;
    @Autowired
    private ElExamService elExamService;
    @Autowired
    private ElExamRepoService elExamRepoService;
    @Autowired
    private IElExamQuService examQuService;
    @Autowired
    private ElQuService elQuService;
    @Autowired
    private ElQuAnswerService elQuAnswerService;
    @Autowired
    private ElPaperQuMapper elPaperQuMapper;
    @Autowired
    private IElPaperQuService elPaperQuService;
    @Autowired
    private IElUserExamService elUserExamService;
    @Autowired
    private ElUserBookMapper elUserBookMapper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private IElPointsRecordService pointsRecordService;
    @Autowired
    private IElUserCertService userCertService;
    @Autowired
    private IElSafeTrainService safeTrainService;
    @Autowired
    private IElSafeTrainRecordService safeTrainRecordService;
    @Autowired
    private IElConvertRecordService convertRecordService;
    @Autowired
    private ElCourseChapterMapper courseChapterMapper;
    @Autowired
    private BonusPointsService bonusPointsService;
    @Autowired
    private RemoteUserService remoteUserService;
    @Autowired
    private ElCourseChapterQuMapper elCourseChapterQuMapper;
    @Autowired
    private ElCourseChapterQuAnswerMapper elCourseChapterQuAnswerMapper;
    @Autowired
    private ConvertTimingService convertTimingService;
    @Autowired
    private FileConfigUtils fileConfigUtils;

    /**
     * 查询试卷管理
     *
     * @param id 试卷管理主键
     * @return 试卷管理
     */
    @Override
    public ElPaper selectElPaperById(Long id) {
        // 试题基本信息
        ElPaper elPaper = elPaperMapper.selectElPaperById(id);
        if (elPaper == null) {
            throw new ServiceException("未查询到试卷，ID无效");
        }
        elPaper.setElPaperQuList(null);

        // 查找题目列表
        ElPaperQu elPaperQu = new ElPaperQu();
        elPaperQu.setPaperId(id);
        List<ElPaperQu> list = elPaperQuMapper.selectElPaperQuList(elPaperQu);

        List<ElPaperQu> radioList = new ArrayList<>();
        List<ElPaperQu> multiList = new ArrayList<>();
        List<ElPaperQu> judgeList = new ArrayList<>();
        for (ElPaperQu item : list) {
            if (QuType.RADIO.equals(item.getQuType())) {
                radioList.add(item);
            }
            if (QuType.MULTI.equals(item.getQuType())) {
                multiList.add(item);
            }
            if (QuType.JUDGE.equals(item.getQuType())) {
                judgeList.add(item);
            }
        }

        elPaper.setRadioList(radioList);
        elPaper.setMultiList(multiList);
        elPaper.setJudgeList(judgeList);

        elPaper.setExamConfig(elExamRepoService.selectSumScoreByExamId(elPaper.getExamId()));
        return elPaper;
    }

    /**
     * 查询试卷管理列表
     *
     * @param elPaper 试卷管理
     * @return 试卷管理
     */
    @Override
    @DataScope(deptAlias = "p", userAlias = "p", permi = PerPrefix.EXAM_PAPER)
    public List<ElPaper> selectElPaperList(ElPaper elPaper) {
        return elPaperMapper.selectElPaperList(elPaper);
    }

    /**
     * 新增试卷管理
     *
     */
    public ElPaper insertElPaper(ElExam exam, ElCourseChapter courseChapter) {
        SysUser user = tokenService.getLoginUser().getSysUser();
        ElPaper paper = new ElPaper();

        if(exam != null){
            paper.setExamId(exam.getId());
            paper.setTitle(exam.getTitle());
            paper.setTotalScore(exam.getTotalScore());
            paper.setTotalTime(exam.getTotalTime());
            paper.setQualifyScore(exam.getQualifyScore());
            // 截止时间
            Calendar cl = Calendar.getInstance();
            cl.setTimeInMillis(System.currentTimeMillis());
            cl.add(Calendar.MINUTE, exam.getTotalTime());
            paper.setLimitTime(cl.getTime());
        }

        if(courseChapter != null){
            paper.setCourseChapterId(courseChapter.getId());
            paper.setTitle(courseChapter.getAssessName());
            paper.setTotalScore(-1);
            paper.setTotalTime(-1);
            paper.setQualifyScore(-1);
        }

        paper.setUserTime(0);
        paper.setUserScore(0);
        paper.setObjScore(0);
        paper.setJoinUserId(user.getUserId());

        paper.setState(PaperState.ING);
        paper.setHasSaq(0);

        paper.setDeptId(user.getDeptId());
        if(user.getDept() != null){
            paper.setDeptName(user.getDept().getDeptName());
        }
        paper.setUserId(user.getUserId());
        paper.setCreateBy(user.getNickName());
        paper.setCreateTime(DateUtils.getNowDate());

        elPaperMapper.insertElPaper(paper);
        return paper;
    }

    /**
     * 修改试卷管理
     *
     * @param elPaper 试卷管理
     * @return 结果
     */
    @Transactional
    @Override
    public int updateElPaper(ElPaper elPaper) {
        elPaper.setUpdateTime(DateUtils.getNowDate());
        elPaperMapper.deleteElPaperQuByPaperId(elPaper.getId());
        insertElPaperQu(elPaper);
        return elPaperMapper.updateElPaper(elPaper);
    }

    /**
     * 批量删除试卷管理
     *
     * @param ids 需要删除的试卷管理主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteElPaperByIds(Long[] ids) {
        elPaperMapper.deleteElPaperQuByPaperIds(ids);
        return elPaperMapper.deleteElPaperByIds(ids);
    }

    /**
     * 删除试卷管理信息
     *
     * @param id 试卷管理主键
     * @return 结果
     */
    @Override
    public int deleteElPaperById(Long id) {
        elPaperMapper.deleteElPaperQuByPaperId(id);
        return elPaperMapper.deleteElPaperById(id);
    }

    @Override
    @Transactional
    public Long createPaper(Long examId) {
        // 查找考试
        ElExam exam = elExamService.queryById(examId);

        if (exam == null) {
            throw new ServiceException("考试不存在！");
        }

        // 2.1 需求 各类考试随时都可以参加，先注释掉
        // 区别点，用户不在违规项 考试不处理违规
        /*if (exam.getScopeType() != 3) {
            R<Object> data = remoteLaboratoryService.userBlacklist(SecurityUtils.getUserId());
            if (data.getData() != null) {
                List<Map<String, Object>> list = (List<Map<String, Object>>) data.getData();
                if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(list)) {
                    throw new ServiceException("只能参加黑名单考试！");
                }
            }
        }*/

        // 2.1 需求删除关联培训，改为关联资源
        /*Long safeTrainId = exam.getSafeTrainId();
        if (safeTrainId != null) {
            ElSafeTrain safeTrain = safeTrainService.selectElSafeTrainById(safeTrainId);
            if (safeTrain != null) {
                // 考试绑定有效安全培训，则必须先完成学习
                ElSafeTrainRecord elSafeTrainRecord = new ElSafeTrainRecord();
                elSafeTrainRecord.setSafeTrainId(safeTrainId);
                elSafeTrainRecord.setJoinUserId(SecurityUtils.getUserId());
                List<ElSafeTrainRecord> safeTrainRecords = safeTrainRecordService.selectElSafeTrainRecordList(elSafeTrainRecord);
                if (CollectionUtils.isEmpty(safeTrainRecords)) {
                    throw new ServiceException("请先完成安全培训【" + safeTrain.getName() + "】学习！", HttpStatus.SEE_OTHER, safeTrainId);
                }
            }
        }*/

        // 查询绑定学习完成记录
        String courseIds = exam.getCourseIds();
        if (StringUtils.isNotBlank(courseIds)) {
            // 考试目前只关联一个学习资源
            Long courseId = Long.parseLong(courseIds);
            // 学习查询该学习资源的所有章节是否都学习完成
            ChapterLearnVo chapterLearnVo = new ChapterLearnVo();
            chapterLearnVo.setJoinUserId(SecurityUtils.getUserId());
            chapterLearnVo.setCourseId(courseId);
            List<ChapterLearnVo> chapterLearnList = courseChapterMapper.selectChapterLearnByCourseId(chapterLearnVo);

            chapterLearnList.forEach(c -> {
                if(0 != c.getChapterType()){
                    if(c.getJoinUserId() == null || 0 == c.getLearnStatus()){
                        Map<String,Object> map = new HashMap<>();
                        map.put("courseId", c.getCourseId());
                        throw new ServiceException("请先完成学习资料【" + c.getCourseTitle() + "】学习！", HttpStatus.SEE_OTHER, map);
                    }
                }
            });
        }


        // 考试状态 1 考试中， 0 已结束
        if (0 == exam.getState()) {
            throw new ServiceException("考试状态不正确！");
        }

        // 考试题目列表
        List<ElPaperQu> quList;
        Long paperId;

        // 按题库组卷的
        if (1 == exam.getJoinType()) {
            //查找规则选定的题库
            quList = this.generateByRepo(examId, exam.getLevel());
            if (CollectionUtils.isEmpty(quList)) {
                throw new ServiceException("规则不正确，无对应的考题！");
            }

            //保存试卷内容
            paperId = this.savePaper(exam, quList);
        }else {
            // 手动组卷查询
            paperId = this.savePaperByJoin(exam);
        }
        return paperId;
    }

    /**
     * 交卷
     * @return
     */
    @Override
    @Transactional(noRollbackFor = NoRollException.class)
    public Map<String, Object> handPaper(ElPaper paper, HttpServletRequest request) {
        Long violationId = paper.getViolationId();
        //获取试卷信息
        paper = elPaperMapper.selectElPaperById(paper.getId());

        //如果不是正常的，抛出异常
        if (!PaperState.ING.equals(paper.getState())) {
            throw new ServiceException("您已交卷，请勿重复提交！");
        }

        // 客观分
        int objScore = elPaperQuService.sumObjective(paper.getId());
        paper.setObjScore(objScore);
        paper.setUserScore(objScore);

        // 是否通过
        boolean passed = objScore >= paper.getQualifyScore();
        String userCertUrl = null;
        if (passed) {
            /*// 考试通过则记录考试所得证书
            userCertService.insertOrUpdateBatchElUserCert(paper.getExamId());
            // 如果是通过违规参加的考试则修改违规处理状态
            if (violationId != null) {
                Map<String, Object> params = new HashMap<>();
                params.put("id", violationId);
                params.put("isHandle", 1);
                remoteLaboratoryService.editViolation(params);
            }*/
            // 2.1 新需求
            // 2 如果是负面清单和黑名单考试且用户也在其中，则处理该违规，并回复信用分，否则不处理

//            R<Object> data = remoteLaboratoryService.userBlacklist(SecurityUtils.getUserId());
//            if (data.getData() != null) {
//                List<Map<String, Object>> list = (List<Map<String, Object>>) data.getData();
                // 违规或者黑名单考试 都不得积分
                // if (org.apache.commons.collections4.CollectionUtils.isEmpty(list) && violationId == null) {

                  ElExam exam = elExamService.queryById(paper.getExamId());
                  if(Objects.equals(exam.getScopeType(), ScopeType.SCOPE_1.getType())){
                      // 安全准入考试 考试通过根据证书模板生成且只生成一次，如果是第一次则返回证书
                      ElUserCert elUserCert = new ElUserCert();
                      elUserCert.setExamId(paper.getExamId());
                      elUserCert.setJoinUserId(paper.getJoinUserId());
                      elUserCert = userCertService.insertElUserCert(elUserCert,request);
                      if(null!=elUserCert){
                          userCertUrl = elUserCert.getCertUrl();
                      }
                  }else if (Objects.equals(exam.getScopeType(), ScopeType.SCOPE_4.getType())) {
                    // 2.1 考试通过 只有模拟考试获得奖励分

                    // 考试通过 计算考试得分换算积分保存记录
                    /*double points = objScore * exam.getConversion();
                    if (points > 0) {
                        ElPointsRecord elPointsRecord = new ElPointsRecord();
                        elPointsRecord.setPoints((long) (points));
                        elPointsRecord.setMode(0);
                        elPointsRecord.setRemark("考试：“ " + exam.getTitle() + "“ 中获取");
                        elPointsRecord.setJoinUserId(paper.getJoinUserId());
                        elPointsRecord.setUserId(paper.getUserId());
                        elPointsRecord.setRecordType(PointRecordType.GET);
                        elPointsRecord.setDeptId(paper.getDeptId());
                        elPointsRecord.setDeptName(paper.getDeptName());
                        elPointsRecord.setCreateTime(DateUtils.getNowDate());
                        elPointsRecord.setCreateBy(paper.getCreateBy());
                        pointsRecordService.insertElPointsRecord(elPointsRecord);
                    }*/

                    // 考试完成添加换算记录
                  if(paper.getUserScore() == null && paper.getUserScore() > 0){
                      ElConvertRecord elConvertRecord = new ElConvertRecord();
                      elConvertRecord.setType(ConvertType.EXAMPAPER);
                      // 此处业务ID 为试卷ID
                      elConvertRecord.setBusinessId(paper.getId());
                      elConvertRecord.setBusinessNum(paper.getUserScore().longValue());
                      elConvertRecord.setStatus(0);
                      elConvertRecord.setUseNum(0L);

                      convertRecordService.insertElConvertRecord(elConvertRecord);
                  }

                }else if(Objects.equals(exam.getScopeType(), ScopeType.SCOPE_2.getType())){
                      // 负面清单考试通过处理
                      Map<String, Object> map = new HashMap<>();
                      map.put("testStatus", 0);
                      bonusPointsService.blackCallback(paper.getJoinUserId(),map, 1);
                }else if(Objects.equals(exam.getScopeType(), ScopeType.SCOPE_3.getType())){
                      // 黑名单考试通过处理
                      // 考试开始，练习开始，学习开始，添加字段标记，要执行的内容未对应类型

                      Map<String, Object> map = new HashMap<>();
                      map.put("testStatus", 0);
                      bonusPointsService.blackCallback(paper.getJoinUserId(),map, 1);
                }
//            }
        }

        // 主观分，因为要阅卷，所以给0
        paper.setSubjScore(0);

        // 同步保存考试成绩
        elUserExamService.joinResult(paper.getJoinUserId(), paper.getExamId(), objScore, passed);

        paper.setState(PaperState.FINISHED);
        paper.setUpdateTime(new Date());

        //计算考试时长
        Calendar cl = Calendar.getInstance();
        cl.setTimeInMillis(System.currentTimeMillis());
        int userTime = (int) ((System.currentTimeMillis() - paper.getCreateTime().getTime()) / 1000 );// / 60 2.1需求转换成秒
        if (userTime == 0) {
            userTime = 1;
        }
        paper.setUserTime(userTime);

        //更新试卷
        elPaperMapper.updateElPaper(paper);

        //把打错的问题加入错题本
        ElPaperQu elPaperQu = new ElPaperQu();
        elPaperQu.setPaperId(paper.getId());
        List<ElPaperQu> list = elPaperQuService.selectElPaperQuList(elPaperQu);
        ElUserBook book;
        Integer maxSort = elUserBookMapper.selectMaxSort(paper.getExamId(), SecurityUtils.getUserId());
        for (ElPaperQu qu : list) {
            // 主观题和对的都不加入错题库
            if (qu.getIsRight() == 1) {
                continue;
            }
            //加入错题本
            book = new ElUserBook();
            book.setExamId(paper.getExamId());
            book.setUserId(SecurityUtils.getUserId());
            book.setTitle(qu.getContent());
            book.setQuId(qu.getQuId());
            book.setWrongCount(1);
            book.setSort(++maxSort);

            elUserBookMapper.insertElUserBook(book);
        }
        // 考试结束返回考试结果。 同练习返回功能，区别点，第一次获得证书则返回证书信息
        Map<String, Object> map = elPaperQuMapper.selectCountByPaperId(paper.getId());
        map.put("userTime", paper.getUserTimeStr());
        map.put("userScore", paper.getUserScore());
        // 如果有证书地址，则显示，否则按钮隐藏
        if(userCertUrl!=null){
            String baseUrl=request.getServerName() ;
            String url="";
            if(baseUrl.contains("192.168")){
                url=fileConfigUtils.getLocalUrl()+userCertUrl;
            }else{
                url=fileConfigUtils.getRemoteUrl()+userCertUrl;
            }
            url= UrlFormatUtils.getHttpsORHttpUrl(url);
            map.put("userCertUrl", url);
        }else{
            map.put("userCertUrl", null);
        }
        // 是否合格
        map.put("passed", passed);

        // 因牵扯事务嵌套，此方法放到最后执行
        extracted(paper, userCertUrl);
        return map;
    }

    public void extracted(ElPaper paper, String userCertUrl) {
        try {
            if(userCertUrl != null){
                // 初始化信用分
                Map<String, Object> data = new HashMap<>();
                data.put("joinUserId", paper.getJoinUserId());
                R<SysUser> user = remoteUserService.getUserInfoByUserId(paper.getJoinUserId(), SecurityConstants.INNER);
                if (user.getCode() == 200 && user.getData() != null) {
                    data.put("nickName", user.getData().getNickName());
                    data.put("userName", user.getData().getUserName());
                }
                data.put("gainSafeCert", 1);
                data.put("gainSubSafeCert", 1);
                data.put("reason", "获取实验室安全准入资格证书！");
                pointsRecordService.initCreditPoints(data);
            }
        }catch (Exception e){
            e.getMessage();
            logger.error("初始化信用分异常：" + e.getMessage());
        }

    }

    /**
     * 交卷查询考试结果
     */
    @Override
    public ElPaper paperResult(ElPaper elPaper) {

        // 试题基本信息
        elPaper = elPaperMapper.selectElPaperById(elPaper.getId());
        if(elPaper == null){
            throw new ServiceException("查询失败，试卷ID无效！");
        }

        List<ElPaperQu> quList = elPaperQuMapper.selectElPaperQuByPaperId(elPaper.getId());

        List<ElPaperQu> radioList = new ArrayList<>();
        List<ElPaperQu> multiList = new ArrayList<>();
        List<ElPaperQu> judgeList = new ArrayList<>();
        for (ElPaperQu item : quList) {
            if (QuType.RADIO.equals(item.getQuType())) {
                radioList.add(item);
            }
            if (QuType.MULTI.equals(item.getQuType())) {
                multiList.add(item);
            }
            if (QuType.JUDGE.equals(item.getQuType())) {
                judgeList.add(item);
            }
        }
        elPaper.setRadioList(radioList);
        elPaper.setMultiList(multiList);
        elPaper.setJudgeList(judgeList);

        elPaper.setElPaperQuList(null);


        return elPaper;
    }

    @Override
    public Map<String, Object> getPaperStatistics(Long paperId) {
        List<Map<String, Object>> datas = elPaperQuMapper.queryPaperStatisticsByPaperId(paperId);

        int right = 0, wrong = 0;
        for (Map<String, Object> data : datas) {
            if (0 == (int) data.get("isRight")) {
                wrong = Integer.parseInt(data.get("count") + "");
            } else if (1 == (int) data.get("isRight")) {
                right = Integer.parseInt(data.get("count") + "");
            }
        }

        Map<String, Object> statis = new HashMap<>();
        statis.put("right", right);
        statis.put("wrong", wrong);
        return statis;
    }

    /**
     * 超时弃考
     */
    @Override
    public void abandonPaper() {
        elPaperMapper.updateGiveOutState(PaperState.BREAK);
    }

    /**
     * 开始考核 -- 章节ID
     * @return
     */
    @Override
    public ElPaper startAssess(Long courseChapterId) {

        ElCourseChapter courseChapter = courseChapterMapper.selectElCourseChapterById(courseChapterId);
        if(courseChapter == null && courseChapter.getIsAssess() == 0){
            throw new ServiceException("该章节不需要考核！");
        }
        // 检验该章节完成，完成则才能考核
        if(courseChapter.getDuration() > courseChapterMapper.selectChapterDurationsByUserId(courseChapter.getId(),  SecurityUtils.getUserIdEx())){
            throw new ServiceException("请先完成该章节学习！");
        }

        ElPaper paper = insertElPaper(null, courseChapter);

        this.savePaperQu(paper.getId(), null, courseChapter);

        return selectElPaperById(paper.getId());

    }

    /**
     * 考核提交返回结果 -- 考核ID(试卷ID)
     * @return
     */
    @Override
    public Map<String, Object> finishAssess(Long paperId) {

        ElPaper paper = elPaperMapper.selectElPaperById(paperId);
        if(paper == null){
            throw new ServiceException("ID 无效");
        }

        // ifnull(round(correctly/(unAnswered+answered) * 100, 0),0) as accuracy --正确率
        Map<String, Object> map = elPaperQuMapper.selectCountByPaperId(paperId);
        int acc = (Integer.parseInt(map.get("unAnswered") + "") + Integer.parseInt(map.get("answered")+ ""));
        map.put("accuracy", acc > 0 ? (int)(Double.parseDouble(map.get("correctly")+"")/acc * 100) : 0);

        // 考核全部正确添加换算记录
        Long convertRecordId = null;
        if(Integer.parseInt(map.get("accuracy") + "") == 100){

            // TODO 未学习完成，不可获得考核奖励分 且考核分值不算数
            Long correctly = Long.parseLong(map.get("correctly")+"");
            ElConvertRecord elConvertRecord = new ElConvertRecord();
            elConvertRecord.setType(ConvertType.ASSESS);
            // 此处业务ID 为试卷ID
            elConvertRecord.setBusinessId(paper.getId());
            elConvertRecord.setBusinessNum(correctly);
            elConvertRecord.setStatus(0);
            elConvertRecord.setUseNum(0L);

            convertRecordService.insertElConvertRecord(elConvertRecord);
            convertRecordId = elConvertRecord.getId();

            // 修改练习 完成状态
            paper.setTotalScore(Math.toIntExact(correctly));
            paper.setObjScore(Math.toIntExact(correctly));
            paper.setSubjScore(0);
            paper.setUserScore(Math.toIntExact(correctly));

            elPaperMapper.updateElPaper(paper);
        }


        // 通过elConvertRecord 换算记录直接执行获取换算结果返回数值
        // 获得奖励积分
        map.put("points", convertRecordId != null ? convertTimingService.doConvertById(convertRecordId) : 0);
        return map;
    }

    /**
     * 考核详情 -- 试卷ID
     */
    @Override
    public ElPaper assessDetail(Long paperId) {
        ElPaper elPaper = new ElPaper();
        elPaper.setId(paperId);
        elPaper = paperResult(elPaper);

        Map<String, Object> otherData = new HashMap<>();

        // 全部题数
        otherData.put("allQu", elPaper.getRadioList().size() + elPaper.getMultiList().size() + elPaper.getJudgeList().size());
        // 单选题数
        otherData.put("radioQu", elPaper.getRadioList().size());
        // 多选题数
        otherData.put("multiQu", elPaper.getMultiList().size());
        // 判断题数
        otherData.put("judgeQu", elPaper.getJudgeList().size());

        Map<String, Object> map = elPaperQuMapper.selectCountByPaperId(paperId);
        int acc = (Integer.parseInt(map.get("unAnswered") + "") + Integer.parseInt(map.get("answered")+ ""));
        map.put("accuracy", acc > 0 ? (int)(Double.parseDouble(map.get("correctly")+"")/acc * 100) : 0);

        // 考核正确率，100 表示通过，其余都不通过
        otherData.put("accuracy", map.get("accuracy"));

        Long courseChapterId = elPaper.getCourseChapterId();
        ElCourseChapter courseChapter = courseChapterMapper.selectElCourseChapterById(courseChapterId);
        if(courseChapter != null){
            // 章节名称
            otherData.put("title", courseChapter.getTitle());
            // 考核名称
            otherData.put("assessName", courseChapter.getAssessName());
        }else {
            // 章节名称
            otherData.put("title", "无效数据");
            // 考核名称
            otherData.put("assessName", "无效数据");
        }

        elPaper.setOtherData(otherData);
        return elPaper;
    }

    /**
     * 用户端考核列表 -- 章节ID
     */
    @Override
    public List<ElPaperAssessVo> assessList(Long courseChapterId) {
        ElPaper elPaper = new ElPaper();
        elPaper.setCourseChapterId(courseChapterId);
        elPaper.setJoinUserId(SecurityUtils.getUserId());

        return elPaperMapper.selectPaperAssessList(elPaper);
    }

    /**
     * 管理端考核列表考核列表 -- 章节ID
     */
    @Override
    public List<ElPaperAssessVo> allAssessList(Long courseChapterId) {
        ElPaper elPaper = new ElPaper();
        elPaper.setCourseChapterId(courseChapterId);
        elPaper.setJoinUserId(SecurityUtils.getUserId());

        return elPaperMapper.selectPaperAssessList(elPaper);
    }

    /**
     * 新增试卷考题信息
     *
     * @param elPaper 试卷管理对象
     */
    public void insertElPaperQu(ElPaper elPaper) {
        List<ElPaperQu> elPaperQuList = elPaper.getElPaperQuList();
        Long id = elPaper.getId();
        if (StringUtils.isNotNull(elPaperQuList)) {
            List<ElPaperQu> list = new ArrayList<>();
            for (ElPaperQu elPaperQu : elPaperQuList) {
                elPaperQu.setPaperId(id);
                list.add(elPaperQu);
            }
            if (list.size() > 0) {
                elPaperMapper.batchElPaperQu(list);
            }
        }
    }

    /**
     * 题库组题方式产生题目列表
     *
     * @param examId
     * @return
     */
    private List<ElPaperQu> generateByRepo(Long examId, Integer level) {

        // 查找规则指定的题库
        List<ElExamRepo> list = elExamRepoService.queryByExamId(examId);

        //最终的题目列表
        List<ElPaperQu> paperQuList = new ArrayList<>();

        //排除ID，避免题目重复
        List<Long> excludes = new ArrayList<>();

        // 去掉 难度匹配
        level = null;
        if (!CollectionUtils.isEmpty(list)) {
            for (ElExamRepo item : list) {
                // 2.1需求， 需要在组题模式下 根据分类组题
                // 题库方式暂 不删除处理
                // 单选题
                if (item.getRadioCount() > 0) {
                    /*List<ElQu> radioList = elQuService.listByRandom(item.getRepoId(), QuType.RADIO, level, excludes,
                            item.getRadioCount());*/
                    List<ElQu> radioList = elQuService.listByRandom(item.getClassifyId(),QuType.RADIO, level, excludes,
                            item.getRadioCount());
                    putList(level, paperQuList, excludes, item, radioList, QuType.RADIO);
                }

                //多选题
                if (item.getMultiCount() > 0) {
                    /*List<ElQu> multiList = elQuService.listByRandom(item.getRepoId(), QuType.MULTI, level, excludes,
                            item.getMultiCount());*/
                    List<ElQu> multiList = elQuService.listByRandom(item.getClassifyId(),QuType.MULTI, level, excludes,
                            item.getMultiCount());
                    putList(level, paperQuList, excludes, item, multiList, QuType.MULTI);
                }

                // 判断题
                if (item.getJudgeCount() > 0) {
                    /*List<ElQu> judgeList = elQuService.listByRandom(item.getRepoId(), QuType.JUDGE, level, excludes,
                            item.getJudgeCount());*/
                    List<ElQu> judgeList = elQuService.listByRandom(item.getClassifyId(),QuType.JUDGE, level, excludes,
                            item.getJudgeCount());
                    putList(level, paperQuList, excludes, item, judgeList, QuType.JUDGE);
                }
            }
        }
        return paperQuList;
    }

    private void putList(Integer level, List<ElPaperQu> paperQuList, List<Long> excludes, ElExamRepo item, List<ElQu> quList, Integer quType) {
        for (ElQu qu : quList) {
            ElPaperQu paperQu = this.processPaperQu(item, qu);
            paperQuList.add(paperQu);
            excludes.add(qu.getId());
        }

        int count = 0;
        String quTypeName = "";
        if (QuType.RADIO.equals(quType)) {
            count = item.getRadioCount() - quList.size();
            quTypeName = "单选题";
        } else if (QuType.MULTI.equals(quType)) {
            count = item.getMultiCount() - quList.size();
            quTypeName = "多选题";
        } else if (QuType.JUDGE.equals(quType)) {
            count = item.getJudgeCount() - quList.size();
            quTypeName = "判断题";
        }

        // 数量不足时 题目数量补足
        if (count > 0) {
            // 因根据题目类型设置得分规则， 故题目数量不足时，不再用其他类型题不足

            throw new ServiceException(quTypeName + "数量不满足，创建试卷失败！");

            /*quList = elQuService.otherListByRandom(item.getRepoId(), QuType.RADIO, level, excludes,
                    count);
            if(count != quList.size()){
                throw new ServiceException(quTypeName + "数量不满足，创建试卷失败！");
            }
            for (ElQu qu : quList) {
                ElPaperQu paperQu = this.processPaperQu(item, qu);
                paperQuList.add(paperQu);
                excludes.add(qu.getId());
            }*/
        }
    }

    /**
     * 填充试题题目信息
     *
     * @param repo
     * @param qu
     * @return
     */
    private ElPaperQu processPaperQu(ElExamRepo repo, ElQu qu) {

        //保存试题信息
        ElPaperQu paperQu = new ElPaperQu();
        paperQu.setQuId(qu.getId());
        paperQu.setAnswered(0);
        paperQu.setIsRight(0);
        paperQu.setQuType(qu.getQuType());

        if (QuType.RADIO.equals(qu.getQuType())) {
            paperQu.setScore(repo.getRadioScore());
            paperQu.setActualScore(repo.getRadioScore());
        }

        if (QuType.MULTI.equals(qu.getQuType())) {
            paperQu.setScore(repo.getMultiScore());
            paperQu.setActualScore(repo.getMultiScore());
        }

        if (QuType.JUDGE.equals(qu.getQuType())) {
            paperQu.setScore(repo.getJudgeScore());
            paperQu.setActualScore(repo.getJudgeScore());
        }

        return paperQu;
    }

    /**
     * 保存试卷
     *
     * @param exam
     */
    private Long savePaper(ElExam exam, List<ElPaperQu> quList) {
        //保存试卷基本信息
        ElPaper paper = insertElPaper(exam, null);

        this.savePaperQu(paper.getId(), quList);

        return paper.getId();
    }

    /**
     * 同步手动组题数据
     * @param exam
     */
    private Long savePaperByJoin(ElExam exam) {
        //保存试卷基本信息
        ElPaper paper = insertElPaper(exam, null);

        this.savePaperQu(paper.getId(), exam, null);

        return paper.getId();
    }

    /**
     * 保存试卷试题列表
     *
     * @param paperId
     * @param quList
     */
    private void savePaperQu(Long paperId, List<ElPaperQu> quList) {

        List<ElPaperQu> batchQuList = new ArrayList<>();
        List<ElPaperQuAnswer> batchAnswerList = new ArrayList<>();

        int sort = 0;
        for (ElPaperQu item : quList) {

            item.setPaperId(paperId);
            item.setSort(sort);

            //回答列表
            List<ElQuAnswer> answerList = elQuAnswerService.queryByQuId(item.getQuId());

            if (!CollectionUtils.isEmpty(answerList)) {

                int ii = 0;
                for (ElQuAnswer answer : answerList) {
                    ElPaperQuAnswer paperQuAnswer = new ElPaperQuAnswer();
                    paperQuAnswer.setPaperId(paperId);
                    paperQuAnswer.setQuId(answer.getQuId());
                    paperQuAnswer.setAnswerId(answer.getId());
                    paperQuAnswer.setChecked(0);
                    paperQuAnswer.setSort(ii);
                    paperQuAnswer.setAbc(QuType.ABC.get(ii));
                    paperQuAnswer.setIsRight(answer.getIsRight());
                    ii++;
                    batchAnswerList.add(paperQuAnswer);
                }
            }

            batchQuList.add(item);
            sort++;
        }

        //添加问题
        elPaperMapper.batchElPaperQu(batchQuList);

        //批量添加问题答案
        elPaperQuMapper.batchElPaperQuAnswer(batchAnswerList);
    }

    private void savePaperQu(Long paperId, ElExam exam, ElCourseChapter courseChapter) {


        List<ElPaperQu> batchQuList = new ArrayList<>();
        List<ElPaperQuAnswer> batchAnswerList = new ArrayList<>();

        int sort = 0;
        ElPaperQu paperQu;
        ElPaperQuAnswer paperQuAnswer;

        if(exam != null){
            // 同步手动题库
            List<ElExamQu> examQuList = examQuService.queryByExamId(exam.getId());
            for (ElExamQu item : examQuList) {

                paperQu = new ElPaperQu();
                BeanUtils.copyProperties(item, paperQu);
                paperQu.setPaperId(paperId);
                paperQu.setId(null);
                paperQu.setSort(sort);

                //回答列表
                List<ElExamQuAnswer> answerList = item.getExamQuAnswers();
                for (ElExamQuAnswer answer : answerList) {
                    paperQuAnswer = new ElPaperQuAnswer();
                    BeanUtils.copyProperties(answer, paperQuAnswer);
                    paperQuAnswer.setPaperId(paperId);
                    paperQuAnswer.setId(null);
                    batchAnswerList.add(paperQuAnswer);
                }

                batchQuList.add(paperQu);
                sort++;
            }
        }else if(courseChapter != null){
            // 同步考核题库

            ElCourseChapterQu elCourseChapterQu = new ElCourseChapterQu();
            elCourseChapterQu.setCourseChapterId(courseChapter.getId());
            List<ElCourseChapterQu> courseChapterQuList = elCourseChapterQuMapper.selectElCourseChapterQuList(elCourseChapterQu);

            if(courseChapterQuList.size()  == 0){
                throw new ServiceException("数据异常，未查询到题目！");
            }

            ElCourseChapterQuAnswer elCourseChapterQuAnswer = new ElCourseChapterQuAnswer();
            for (ElCourseChapterQu item : courseChapterQuList) {

                paperQu = new ElPaperQu();
                BeanUtils.copyProperties(item, paperQu);
                paperQu.setPaperId(paperId);
                paperQu.setId(null);
                paperQu.setSort(sort);

                //回答列表
                elCourseChapterQuAnswer.setCourseChapterQuId(item.getId());
                elCourseChapterQuAnswer.setQuId(item.getQuId());
                List<ElCourseChapterQuAnswer> answerList = elCourseChapterQuAnswerMapper.selectElCourseChapterQuAnswerList(elCourseChapterQuAnswer);
                for (ElCourseChapterQuAnswer answer : answerList) {
                    paperQuAnswer = new ElPaperQuAnswer();
                    BeanUtils.copyProperties(answer, paperQuAnswer);
                    paperQuAnswer.setPaperId(paperId);
                    paperQuAnswer.setId(null);
                    batchAnswerList.add(paperQuAnswer);
                }

                batchQuList.add(paperQu);
                sort++;
            }
        }else {
            throw new ServiceException("参数异常！");
        }


        //添加问题
        elPaperMapper.batchElPaperQu(batchQuList);

        //批量添加问题答案
        elPaperQuMapper.batchElPaperQuAnswer(batchAnswerList);
    }
}
