package com.qmth.teachcloud.mark.service.impl;

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

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.teachcloud.common.bean.dto.mark.ObjectiveAnswerDto;
import com.qmth.teachcloud.common.bean.result.ExcelResult;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.MarkQuestion;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.*;
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
import com.qmth.teachcloud.common.util.ConvertUtil;
import com.qmth.teachcloud.common.util.ExcelUtil;
import com.qmth.teachcloud.common.util.FileStoreUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import com.qmth.teachcloud.mark.dto.mark.setting.MarkQuestionDto;
import com.qmth.teachcloud.mark.entity.MarkPaper;
import com.qmth.teachcloud.mark.mapper.MarkQuestionMapper;
import com.qmth.teachcloud.mark.params.MarkObjectiveQuestionParams;
import com.qmth.teachcloud.mark.params.MarkQuestionParams;
import com.qmth.teachcloud.mark.service.MarkGroupService;
import com.qmth.teachcloud.mark.service.MarkPaperService;
import com.qmth.teachcloud.mark.service.MarkQuestionService;

/**
 * <p>
 * 小题信息表 服务实现类
 * </p>
 *
 * @author xf
 * @since 2023-09-22
 */
@Service
public class MarkQuestionServiceImpl extends ServiceImpl<MarkQuestionMapper, MarkQuestion> implements MarkQuestionService {

    @Resource
    private TeachcloudCommonService teachcloudCommonService;
    @Resource
    private MarkPaperService markPaperService;
    @Resource
    private MarkGroupService markGroupService;
    @Resource
    private FileStoreUtil fileStoreUtil;

    @Override
    public String assembleGroupQuestionsByExamIdAndPaperNumberAndNumber(Long examId, String paperNumber, Integer groupNumber) {
        return this.baseMapper.assembleQuestionsByExamIdAndPaperNumberAndNumber(examId, paperNumber, groupNumber);
    }

    @Override
    public List<MarkQuestion> listQuestionByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType) {
        QueryWrapper<MarkQuestion> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<MarkQuestion> lambdaQueryWrapper = queryWrapper.lambda();
        lambdaQueryWrapper.eq(MarkQuestion::getExamId, examId)
                .eq(MarkQuestion::getPaperNumber, paperNumber);
        if (StringUtils.isNotBlank(paperType)) {
            lambdaQueryWrapper.eq(MarkQuestion::getPaperType, paperType);
        }
        lambdaQueryWrapper.orderByAsc(MarkQuestion::getMainNumber)
                .orderByAsc(MarkQuestion::getSubNumber);
        return this.list(queryWrapper);
    }

    @Transactional
    @Override
    public void saveQuestions(MarkQuestionParams markQuestionParams) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        Long examId = markQuestionParams.getExamId();
        String paperNumber = markQuestionParams.getPaperNumber();
        MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, paperNumber);

        List<MarkQuestion> questions = markQuestionParams.getQuestions();
        if (CollectionUtils.isEmpty(questions)) {
            throw ExceptionResultEnum.ERROR.exception("没有可保存的结构数据");
        }

        // 校验题号不能重复
        Map<String, Long> longMap = questions.stream().collect(Collectors.groupingBy(m -> String.valueOf(m.getMainNumber()) + m.getSubNumber(), Collectors.counting()));
        long count = longMap.entrySet().stream().filter(m -> m.getValue().intValue() > 1).count();
        if (count > 0) {
            throw ExceptionResultEnum.ERROR.exception("大题号-小题号有重复数据");
        }

        // 查询已有结构信息
        List<MarkQuestion> markQuestionList = this.listQuestionByExamIdAndPaperNumberAndPaperType(examId, paperNumber, null);
        if (CollectionUtils.isEmpty(markQuestionList)) {
            for (MarkQuestion question : questions) {
                if (question.getTotalScore() <= 0) {
                    throw ExceptionResultEnum.ERROR.exception("小题满分必须大于0");
                }
                if (!question.getObjective() && (question.getIntervalScore() == null || question.getIntervalScore() <= 0)) {
                    throw ExceptionResultEnum.ERROR.exception("间隔分必须大于0");
                }
                question.setExamId(examId);
                question.setPaperNumber(paperNumber);
                question.setCreateId(sysUser.getId());
                question.setCreateTime(System.currentTimeMillis());
                // 用来判断是否保存过
                question.setUpdateId(sysUser.getId());
                question.setUpdateTime(System.currentTimeMillis());
            }
            this.saveBatch(questions);
        } else {
            List<MarkQuestion> saveOrUpdateList = new ArrayList<>();
            for (MarkQuestion question : questions) {
                if (Objects.isNull(question.getId())) {
                    question.setId(SystemConstant.getDbUuid());
                    question.setExamId(examId);
                    question.setPaperNumber(paperNumber);
                    question.setPaperType(markPaper.getPaperType());
                    saveOrUpdateList.add(question);
                } else {
                    Optional<MarkQuestion> questionOptional = markQuestionList.stream().filter(m -> m.getId().equals(question.getId())).findFirst();
                    if (questionOptional.isPresent()) {
                        MarkQuestion markQuestion = questionOptional.get();
                        if (markQuestion.getGroupNumber() != null && markQuestion.getGroupNumber().intValue() > 0) {
                            if (markQuestion.getTotalScore().doubleValue() - question.getTotalScore().doubleValue() != 0) {
                                throw ExceptionResultEnum.ERROR.exception("大题号" + markQuestion.getMainNumber() + "小题号" + markQuestion.getSubNumber() + "已分组，不能修改小题满分");
                            }
                            // 主观题改客观题
                            if(!markQuestion.getObjective() && question.getObjective()){
                                throw ExceptionResultEnum.ERROR.exception("大题号" + markQuestion.getMainNumber() + "小题号" + markQuestion.getSubNumber() + "已分组，不能修改为客观题题型");
                            }
                        }
                        if (question.getTotalScore() <= 0) {
                            throw ExceptionResultEnum.ERROR.exception("小题满分必须大于0");
                        }
                        if (!QuestionType.findByValue(question.getQuestionType()).getObjective() && question.getIntervalScore() <= 0) {
                            throw ExceptionResultEnum.ERROR.exception("间隔分必须大于0");
                        }
                        // 客观题变主观题
                        if(markQuestion.getObjective() && !question.getObjective()){
                            // 清除判分策略
                            markQuestion.setObjectivePolicy(null);
                            markQuestion.setObjectivePolicyScore(null);
                            markQuestion.setAnswer(null);
                            markQuestion.setOptionCount(0);
                        }
                        // 客观题
                        if(question.getObjective()){
                            markQuestion.setOptionCount(question.getOptionCount());
                            if(!markQuestion.getQuestionType().equals(question.getQuestionType())){
                                // 清除判分策略
                                markQuestion.setObjectivePolicy(null);
                                markQuestion.setObjectivePolicyScore(null);
                                markQuestion.setAnswer(null);
                            }
                        }
                        // 大题号
                        markQuestion.setMainNumber(question.getMainNumber());
                        // 小题号
                        markQuestion.setSubNumber(question.getSubNumber());
                        // 大题名称
                        markQuestion.setMainTitle(question.getMainTitle());
                        // 题型
                        markQuestion.setQuestionType(question.getQuestionType());
                        markQuestion.setObjective(question.getObjective());
                        markQuestion.setTotalScore(question.getTotalScore());
                        markQuestion.setIntervalScore(question.getIntervalScore());
                        // 用来判断是否保存过
                        markQuestion.setUpdateId(sysUser.getId());
                        markQuestion.setUpdateTime(System.currentTimeMillis());
                        saveOrUpdateList.add(markQuestion);
                        markQuestionList.remove(markQuestion);
                    } else {
                        question.setId(SystemConstant.getDbUuid());
                        question.setExamId(examId);
                        question.setPaperNumber(paperNumber);
                        question.setPaperType(markPaper.getPaperType());
                        question.setCreateId(sysUser.getId());
                        question.setCreateTime(System.currentTimeMillis());
                        // 用来判断是否保存过
                        question.setUpdateId(sysUser.getId());
                        question.setUpdateTime(System.currentTimeMillis());
                        saveOrUpdateList.add(question);
                    }
                }
            }
            // 删除的结构
            if (CollectionUtils.isNotEmpty(markQuestionList)) {
                List<Long> deleteIds = markQuestionList.stream().map(MarkQuestion::getId).collect(Collectors.toList());
                this.removeByIds(deleteIds);
            }
            this.saveOrUpdateBatch(saveOrUpdateList);
        }
        // 更新客观题满分、主观题满分、总分
        List<MarkQuestion> markQuestions = this.listQuestionByExamIdAndPaperNumberAndPaperType(examId, paperNumber, null);
        Double objectiveScore = markQuestions.stream().filter(m -> m.getObjective()).collect(Collectors.summingDouble(m -> m.getTotalScore()));
        Double subjectiveScore = markQuestions.stream().filter(m -> !m.getObjective()).collect(Collectors.summingDouble(m -> m.getTotalScore()));
        Double totalScore = markQuestions.stream().collect(Collectors.summingDouble(m -> m.getTotalScore()));
        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(MarkPaper::getObjectiveScore, objectiveScore)
                .set(MarkPaper::getSubjectiveScore, subjectiveScore)
                .set(MarkPaper::getTotalScore, totalScore)
                .eq(MarkPaper::getExamId, examId)
                .eq(MarkPaper::getPaperNumber, paperNumber);
        markPaperService.update(updateWrapper);

        // 修改分组题目总分
        Map<Integer, Double> collectGroupScoreMap = markQuestions.stream().filter(m -> m.getGroupNumber() != null).collect(Collectors.groupingBy(m -> m.getGroupNumber(), Collectors.summingDouble(m -> m.getTotalScore())));
        if (MapUtils.isNotEmpty(collectGroupScoreMap)) {
            for (Map.Entry<Integer, Double> entry : collectGroupScoreMap.entrySet()) {
                markGroupService.updateTotalScore(examId, paperNumber, entry.getKey(), entry.getValue());
            }
        }
    }

    @Override
    public List<MarkQuestion> listQuestionByExamIdAndPaperNumberAndGroupNumber(Long examId, String paperNumber, Integer number, Boolean isObjective) {
        LambdaQueryWrapper<MarkQuestion> lambdaQueryWrapper = new QueryWrapper<MarkQuestion>().lambda();
        lambdaQueryWrapper.eq(MarkQuestion::getExamId, examId)
                .eq(MarkQuestion::getPaperNumber, paperNumber);
        if (number != null) {
            lambdaQueryWrapper.eq(MarkQuestion::getGroupNumber, number);
        }
        if (isObjective != null) {
            lambdaQueryWrapper.eq(MarkQuestion::getObjective, isObjective);
        }
        lambdaQueryWrapper.orderByAsc(MarkQuestion::getMainNumber)
                .orderByAsc(MarkQuestion::getSubNumber);
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public void objectiveAnswerSettingModelExport(Long examId, String paperNumber, HttpServletResponse response)
            throws Exception {
        List<ObjectiveAnswerDto> datasource = this.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber,
                null, true).stream().flatMap(e -> {
            ObjectiveAnswerDto dto = new ObjectiveAnswerDto();
            dto.setMainNumber(String.valueOf(e.getMainNumber()));
            dto.setSubNumber(String.valueOf(e.getSubNumber()));
            dto.setMainTitle(e.getMainTitle());
            dto.setAnswer(e.getAnswer());
            return Stream.of(dto);
        }).collect(Collectors.toList());

        // 生成excel文件
        ExcelUtil.excelExport("客观题标答模板", ObjectiveAnswerDto.class, datasource, response);
    }

    @Transactional
    @Override
    public void objectiveAnswerSettingImport(Long examId, String paperNumber, MultipartFile file) throws Exception {
        List<MarkQuestion> willEditList = new ArrayList<>();
        // 试卷结构
        List<MarkQuestion> datasource = this.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, null,
                true);
        ExcelResult<ObjectiveAnswerDto> excelResult = ConvertUtil.analyzeExcel(file.getInputStream(), ObjectiveAnswerDto.class,
                false, 0);
        if (!excelResult.isSuccess()) {
            throw ExceptionResultEnum.ERROR.exception(excelResult.getErrorMsg());
        }
        // 逻辑异常
        List<String> logicErrorList = new ArrayList<>();
        List<ObjectiveAnswerDto> objectiveAnswerDtoList = excelResult.getDatasource();
        if (!Objects.equals(datasource.size(), objectiveAnswerDtoList.size())) {
            logicErrorList.add("试卷结构试题数量和导入文件中的试题数量不一致");
        }
        Set<String> questionNumberSet = new HashSet<>();
        // 构建题号-试题结构map
        Map<String, MarkQuestion> markQuestionMap = datasource.stream()
                .collect(Collectors.toMap(k -> k.getMainNumber() + SystemConstant.HYPHEN + k.getSubNumber(), v -> v));

        for (int i = 0; i < objectiveAnswerDtoList.size(); i++) {
            int rowIndex = i + 2;
            ObjectiveAnswerDto cell = objectiveAnswerDtoList.get(i);
            int exMainNumber = Integer.parseInt(cell.getMainNumber());
            int exSubNumber = Integer.parseInt(cell.getSubNumber());
            String exMainTitle = cell.getMainTitle();
            String exAnswer = cell.getAnswer();

            String key = exMainNumber + SystemConstant.HYPHEN + exSubNumber;
            String unifyNotice = String.format("第[%s]行,大题号[%s],小题号[%s]的试题", rowIndex, exMainNumber, exSubNumber);
            List<String> rowException = new ArrayList<>();
            if (questionNumberSet.contains(key)) {
                // 题号重复检验
                rowException.add("题号和前面重复");
            } else {
                questionNumberSet.add(key);
                if (markQuestionMap.containsKey(key)) {
                    MarkQuestion markQuestion = markQuestionMap.get(key);
                    markQuestion.setAnswer(exAnswer);
                    willEditList.add(markQuestion);
                    String mainTitle = markQuestion.getMainTitle();
                    if (!Objects.equals(exMainTitle, mainTitle)) {
                        rowException.add(String.format("大题名称[%s]错误", exMainTitle));
                    } else {
                        Integer questionType = markQuestion.getQuestionType();
                        Integer optionCount = markQuestion.getOptionCount();
                        List<String> optionScope = new ArrayList<>();
                        try {
                            for (int j = 1; j <= optionCount; j++) {
                                String code = OptionsEnum.getCodeByIndex(j);
                                optionScope.add(code);
                            }
                        } catch (Exception e) {
                            throw ExceptionResultEnum.ERROR.exception(
                                    String.format("第[%s]行,大题号[%s],小题号[%s]的试题答案可选选项解析失败", rowIndex, exMainNumber,
                                            exSubNumber));
                        }

                        // 答案选项越界校验
                        List<String> answerList = Arrays.asList(exAnswer.split(""));
                        if (CollectionUtils.isNotEmpty(answerList)) {
                            for (String answer : answerList) {
                                String outOfBoundsException = String.format("答案[%s]错误。答案只能从[%s]中选择", answer, String.join("", optionScope));
                                try {
                                    OptionsEnum optionsEnum = OptionsEnum.getByCode(answer);
                                    int optionIndex = optionsEnum.getIndex();
                                    if (optionIndex > optionCount) {
                                        // 答案选项超出范围
                                        rowException.add(outOfBoundsException);
                                    }
                                } catch (Exception e) {
                                    rowException.add(outOfBoundsException);
                                }
                            }
                        } else {
                            rowException.add("答案必填");
                        }

                        // 答案和题型匹配校验
                        if (Objects.equals(questionType, 1)) {
                            // 单选题
                            if (answerList.size() > 1) {
                                rowException.add(String.format("为[单选题],答案[%s]错误", exAnswer));
                            }
                        } else if (Objects.equals(questionType, 2)) {
                            // 多选题

                        } else if (Objects.equals(questionType, 3)) {
                            // 判断题
                            if (answerList.size() > 1) {
                                rowException.add(String.format("为[判断题],答案[%s]错误", exAnswer));
                            }
                        } else {
                            rowException.add("试题题型错误");
                        }
                    }

                } else {
                    rowException.add("题号错误,试卷中不存在该题号");
                }
            }
            if (CollectionUtils.isNotEmpty(rowException)) {
                unifyNotice = unifyNotice + String.join(",", rowException);
                logicErrorList.add(unifyNotice);
            }
        }
        if (CollectionUtils.isNotEmpty(logicErrorList)) {
            throw ExceptionResultEnum.ERROR.exception(String.join(";\n", logicErrorList));
        }
        this.saveOrUpdateBatch(willEditList);
    }

    @Transactional
    @Override
    public void saveObjectiveQuestions(MarkObjectiveQuestionParams markObjectiveQuestionParams) {
        for (MarkQuestion question : markObjectiveQuestionParams.getObjectiveInfo()) {
            if (StringUtils.isBlank(question.getAnswer())) {
                throw ExceptionResultEnum.ERROR.exception("答案不能为空");
            }
            if (question.getObjectivePolicy() != null && question.getObjectivePolicy().equals(ObjectivePolicy.LEAK)) {
                if (question.getObjectivePolicyScore() == null) {
                    throw ExceptionResultEnum.ERROR.exception("漏选给分不能没有计分规则");
                }
                if (question.getObjectivePolicyScore() > (question.getTotalScore() / question.getAnswer().length())) {
                    throw ExceptionResultEnum.ERROR.exception("漏选给分计分规则有误");
                }
            }
            UpdateWrapper<MarkQuestion> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(MarkQuestion::getAnswer, question.getAnswer());
            if (question.getObjectivePolicy() != null) {
                updateWrapper.lambda().set(MarkQuestion::getObjectivePolicy, question.getObjectivePolicy());
            }
            if (question.getObjectivePolicyScore() != null) {
                updateWrapper.lambda().set(MarkQuestion::getObjectivePolicyScore, question.getObjectivePolicyScore());
            }
            updateWrapper.lambda().eq(MarkQuestion::getId, question.getId());
            this.update(updateWrapper);
        }
    }

    @Override
    public String uploadSubjectiveFile(Long examId, String paperNumber, MultipartFile file, String md5) {
        String answerFilePath = fileStoreUtil.uploadFile(file, md5, UploadFileEnum.PDF);
        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(MarkPaper::getAnswerFilePath, answerFilePath)
                .eq(MarkPaper::getExamId, examId)
                .eq(MarkPaper::getPaperNumber, paperNumber);
        markPaperService.update(updateWrapper);
        return teachcloudCommonService.filePreview(answerFilePath);
    }

    @Override
    public String previewAnswerFileByExamIdAndPaperNumber(Long examId, String paperNumber) {
        MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, paperNumber);
        if (markPaper != null) {
            return teachcloudCommonService.filePreview(markPaper.getAnswerFilePath());
        }
        return null;
    }

    @Override
    public double sumTotalScoreByGroupNumber(Long examId, String paperNumber, Integer groupNumber) {
        Double score = this.baseMapper.sumTotalScoreByGroupNumber(examId, paperNumber, groupNumber);
        return score != null ? score.doubleValue() : 0d;
    }

    @Override
    public MarkQuestion getByExamIdAndPaperNumberAndMainNumberAndSubNumberAndObjective(Long examId, String paperNumber, Integer mainNumber, Integer subNumber, boolean isObjective) {
        QueryWrapper<MarkQuestion> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkQuestion::getExamId, examId)
                .eq(MarkQuestion::getPaperNumber, paperNumber)
                .eq(MarkQuestion::getMainNumber, mainNumber)
                .eq(MarkQuestion::getSubNumber, subNumber)
                .eq(MarkQuestion::getObjective, isObjective);
        return this.getOne(queryWrapper);
    }

    @Override
    public List<MarkQuestion> listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(Long examId, String paperNumber,
                                                                                  Integer paperIndex, Integer pageIndex,boolean isObjective) {
        QueryWrapper<MarkQuestion> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkQuestion::getExamId, examId)
                .eq(MarkQuestion::getPaperNumber, paperNumber)
                .eq(MarkQuestion::getPaperIndex, paperIndex)
                .eq(MarkQuestion::getPageIndex, pageIndex)
                .eq(MarkQuestion::getObjective, isObjective)
                .orderByAsc(MarkQuestion::getMainNumber)
                .orderByAsc(MarkQuestion::getSubNumber);
        return this.list(queryWrapper);
    }

    @Override
    public MarkQuestionDto pageQuestionsByExamIdAndPaperNumber(Long examId, String paperNumber, String paperType, boolean canCreate) {
        MarkQuestionDto markQuestionDto = new MarkQuestionDto();
        markQuestionDto.setCanCreate(canCreate);
        List<MarkQuestion> markQuestionList = this.listQuestionByExamIdAndPaperNumberAndPaperType(examId, paperNumber, null);
        long subjectiveCount = markQuestionList.stream().filter(m -> !m.getObjective() && m.getTotalScore() != null && m.getUpdateTime() != null).count();
        markQuestionDto.setQuestionSubmit(subjectiveCount > 0);
        long objectiveCount = markQuestionList.stream().filter(m -> m.getObjective() && StringUtils.isNotBlank(m.getAnswer()) && m.getUpdateTime() != null).count();
        markQuestionDto.setObjectiveSubmit(objectiveCount > 0);
        markQuestionDto.setQuestions(markQuestionList);
        return markQuestionDto;
    }

    @Override
    public void updateGroupNumberByExamIdAndPaperNumberAndGroupNumber(Integer newGroupNumber, Long examId, String paperNumber, Integer groupNumber) {
        UpdateWrapper<MarkQuestion> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(MarkQuestion::getGroupNumber, newGroupNumber)
                .eq(MarkQuestion::getExamId, examId)
                .eq(MarkQuestion::getPaperNumber, paperNumber)
                .eq(MarkQuestion::getGroupNumber, groupNumber);
        this.update(updateWrapper);
    }

    @Override
    public long countByExamIdAndPaperNumberAndObjectiveAndGroupNumberIsNull(Long examId, String paperNumber, boolean objective) {
        QueryWrapper<MarkQuestion> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkQuestion::getExamId, examId)
                .eq(MarkQuestion::getPaperNumber, paperNumber)
                .eq(MarkQuestion::getObjective, objective)
                .isNull(MarkQuestion::getGroupNumber);
        return this.count(queryWrapper);
    }

    @Override
    public List<MarkQuestion> listByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType, Boolean objective) {
        QueryWrapper<MarkQuestion> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<MarkQuestion> lambdaQueryWrapper = queryWrapper.lambda();
        lambdaQueryWrapper.eq(MarkQuestion::getExamId, examId)
                .eq(MarkQuestion::getPaperNumber, paperNumber);
        if (StringUtils.isNotBlank(paperType)) {
            lambdaQueryWrapper.eq(MarkQuestion::getPaperType, paperType);
        }
        if (objective != null) {
            lambdaQueryWrapper.eq(MarkQuestion::getObjective, objective);
        }
        return this.list(queryWrapper);
    }

    @Override
    public void deleteByExamIdAndPaperNumber(Long examId, String paperNumber) {
        UpdateWrapper<MarkQuestion> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(MarkQuestion::getExamId, examId)
                .eq(MarkQuestion::getPaperNumber, paperNumber);
        this.remove(updateWrapper);
    }

    @Transactional
    @Override
    public void updateMarkPaperScore(Long examId, String paperNumber, String paperType) {
        List<MarkQuestion> markQuestions = this.listQuestionByExamIdAndPaperNumberAndPaperType(examId, paperNumber, paperType);
        Double objectiveScore = markQuestions.stream().filter(MarkQuestion::getObjective)
                .mapToDouble(MarkQuestion::getTotalScore).sum();
        Double subjectiveScore = markQuestions.stream().filter(m -> !m.getObjective())
                .mapToDouble(MarkQuestion::getTotalScore).sum();
        Double totalScore = markQuestions.stream().mapToDouble(MarkQuestion::getTotalScore).sum();
        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(MarkPaper::getObjectiveScore, objectiveScore)
                .set(MarkPaper::getSubjectiveScore, subjectiveScore)
                .set(MarkPaper::getTotalScore, totalScore)
                .eq(MarkPaper::getExamId, examId)
                .eq(MarkPaper::getPaperNumber, paperNumber);
        markPaperService.update(updateWrapper);
    }
}
