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

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

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.core.concurrent.service.ConcurrentService;
import com.qmth.boot.core.exception.ParameterException;
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
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.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.QuestionType;
import com.qmth.teachcloud.common.enums.ScanStatus;
import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
import com.qmth.teachcloud.common.enums.scan.ConditionType;
import com.qmth.teachcloud.common.enums.scan.OmrField;
import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
import com.qmth.teachcloud.common.util.ServletUtil;
import com.qmth.teachcloud.mark.bean.OmrTaskItem;
import com.qmth.teachcloud.mark.bean.OmrTaskPage;
import com.qmth.teachcloud.mark.dto.*;
import com.qmth.teachcloud.mark.entity.*;
import com.qmth.teachcloud.mark.enums.LockType;
import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
import com.qmth.teachcloud.mark.mapper.ScanOmrTaskMapper;
import com.qmth.teachcloud.mark.service.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xf
 * @since 2023-09-22
 */
@Service
public class ScanOmrTaskServiceImpl extends ServiceImpl<ScanOmrTaskMapper, ScanOmrTask> implements ScanOmrTaskService {

    @Autowired
    private ScanStudentPaperService studentPaperService;

    @Autowired
    private MarkStudentService studentService;

    @Autowired
    private ScanPaperService paperService;

    @Autowired
    private ScanPaperPageService pageService;

    @Autowired
    private ConcurrentService concurrentService;

    @Autowired
    private MarkQuestionService questionService;

    @Resource
    private MarkPaperService markPaperService;

    @Resource
    private TeachcloudCommonService teachcloudCommonService;

    @Resource
    private BasicRoleDataPermissionService basicRoleDataPermissionService;

    private static final String OMR_SUSPECT = "?";

    private static final String OMR_BLANK = "#";

    @Override
    @Transactional
    public List<ScanOmrTask> buildTask(ConditionType c, Long studentId) {
        List<ScanStudentPaper> paperIds = clearAndToDispose(c, studentId);
        if (CollectionUtils.isEmpty(paperIds)) {
            return null;
        }
        MarkStudent student = studentService.getById(studentId);
        // 所有客观题空白
        boolean allObjectiveBlank = isAllBlank(paperIds);
        if(allObjectiveBlank){
            return null;
        }
        List<OmrTaskDto> retList = new ArrayList<>();
        boolean multi_blank = false;
        boolean single_blank = false;
        int multi_blank_count = 0;
        int single_blank_count = 0;
        for (ScanStudentPaper spe : paperIds) {
            ScanPaper paper = paperService.getById(spe.getPaperId());
            if (paper == null) {
                throw new ParameterException("paper不存在");
            }
            if(paper.getInvalid()){
                continue;
            }
            Long paperId = spe.getPaperId();
            ScanOmrTask task = new ScanOmrTask();
            task.setId(SystemConstant.getDbUuid());
            task.setCardNumber(paper.getCardNumber());
            task.setExamId(paper.getExamId());
            task.setConditions(c);
            task.setPaperId(paperId);
            task.setPaperIndex(spe.getPaperIndex());
            task.setStatus(OmrTaskStatus.WAITING);
            task.setStudentId(spe.getStudentId());
            task.setPages(new ArrayList<>());
            List<ScanPaperPage> pageList = pageService.listByPaperId(paperId);
            OmrTaskDto taskDto = new OmrTaskDto(task);
            retList.add(taskDto);
            // 循环试卷
            for (ScanPaperPage pageEntity : pageList) {
                OmrTaskPageDto pageDto = new OmrTaskPageDto(pageEntity.getPageIndex());
                taskDto.getPage().add(pageDto);
                List<OmrTaskItem> items = pageDto.getItems();
                // 分组类型
                // 识别嫌疑
                if (ConditionType.FILL_SUSPECT.equals(c)) {
                    for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
                            && i < pageEntity.getQuestion().getResult().size(); i++) {
                        String result = pageEntity.getQuestion().getResult().get(i);
                        if (result != null && result.startsWith(OMR_SUSPECT)) {
                            OmrTaskItem item = new OmrTaskItem();
                            item.setIndex(i + 1);
                            item.setField(OmrField.QUESTION);
                            item.setOmrResult(result);
                            items.add(item);
                        }
                    }
                    pageDto.setItems(items);
                }
                if (ConditionType.QUESTION_BLANK.equals(c)) {
                    for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
                            && i < pageEntity.getQuestion().getResult().size(); i++) {
                        String result = pageEntity.getQuestion().getResult().get(i);
                        if (result != null && result.contains(OMR_BLANK)) {
                            OmrTaskItem item = new OmrTaskItem();
                            item.setIndex(i + 1);
                            item.setField(OmrField.QUESTION);
                            item.setOmrResult(result);
                            items.add(item);
                        }
                    }
                    pageDto.setItems(items);
                }
                // 卷型空选
                // if (ConditionType.PAPER_TYPE_BLANK.equals(c)) {
                // if (pageEntity.getPaperType() != null
                // && pageEntity.getPaperType().getResult().contains(OMR_BLANK)) {
                // OmrTaskItem item = new OmrTaskItem();
                // item.setIndex(1);
                // item.setField(OmrField.PAPER_TYPE);
                // item.setOmrResult(pageEntity.getPaperType().getResult());
                // items.add(item);
                // }
                // }
                // 卷型多选
                // if (ConditionType.PAPER_TYPE_EXCEED.equals(c)) {
                // if ((!pageEntity.getPaperType().getResult().contains(OMR_SUSPECT)
                // && pageEntity.getPaperType().getResult().length() > 2)
                // || (pageEntity.getPaperType().getResult().contains(OMR_SUSPECT)
                // && pageEntity.getPaperType().getResult().length() > 1)) {
                // OmrTaskItem item = new OmrTaskItem();
                // item.setField(OmrField.PAPER_TYPE);
                // item.setOmrResult(pageEntity.getPaperType().getResult());
                // items.add(item);
                // }
                // }
//                if (ConditionType.QUESTION_MULTI_BLANK.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
//                    List<MarkQuestion> questiongList = questionService
//                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
//                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(),true);
//                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
//                            || questiongList.isEmpty()) {
//                        continue;
//                    }
//                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
//                            : pageEntity.getQuestion().getResult().size();
//                    for (int i = 0; i < size; i++) {
//                        String result = pageEntity.getQuestion().getResult().get(i);
//                        MarkQuestion question = questiongList.get(i);
//                        if (question.getQuestionType().equals(QuestionType.MULTIPLE.getValue()) && result != null
//                                && result.contains(OMR_BLANK)) {
//                            OmrTaskItem item = new OmrTaskItem();
//                            item.setIndex(i + 1);
//                            item.setField(OmrField.QUESTION);
//                            item.setOmrResult(result);
//                            pageDto.getPageMultiBlankItems().add(item);
//                            multi_blank_count++;
//                            if (multi_blank_count > 0) {
//                                multi_blank = true;
//                            }
//                        }
//                    }
//                }
//                if (ConditionType.QUESTION_SINGLE_BLANK.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
//                    List<MarkQuestion> questiongList = questionService
//                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
//                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(),true);
//                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
//                            || questiongList.isEmpty()) {
//                        continue;
//                    }
//                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
//                            : pageEntity.getQuestion().getResult().size();
//                    for (int i = 0; i < size; i++) {
//                        String result = pageEntity.getQuestion().getResult().get(i);
//                        MarkQuestion question = questiongList.get(i);
//                        if ((question.getQuestionType().equals(QuestionType.SINGLE.getValue())||question.getQuestionType().equals(QuestionType.TRUE_OR_FALSE.getValue()))
//                                && result != null
//                                && result.contains(OMR_BLANK)) {
//                            OmrTaskItem item = new OmrTaskItem();
//                            item.setIndex(i + 1);
//                            item.setField(OmrField.QUESTION);
//                            item.setOmrResult(result);
//                            pageDto.getPageSingleBlankItems().add(item);
//                            single_blank_count++;
//                            if (single_blank_count > 0) {
//                                single_blank = true;
//                            }
//                        }
//                    }
//                }
                if (ConditionType.QUESTION_SINGLE_EXCEED.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
                    List<MarkQuestion> questiongList = questionService
                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(),true);
                    if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
                            || questiongList.isEmpty()) {
                        continue;
                    }
                    int size = pageEntity.getQuestion().getResult().size() > questiongList.size() ? questiongList.size()
                            : pageEntity.getQuestion().getResult().size();
                    for (int i = 0; i < size; i++) {
                        String result = pageEntity.getQuestion().getResult().get(i);
                        MarkQuestion question = questiongList.get(i);
                        String newStr = result.replace(OMR_SUSPECT, "");
                        if ((question.getQuestionType().equals(QuestionType.SINGLE.getValue())||question.getQuestionType().equals(QuestionType.TRUE_OR_FALSE.getValue()))
                                && result != null
                                && newStr.length() > 1) {
                            OmrTaskItem item = new OmrTaskItem();
                            item.setIndex(i + 1);
                            item.setField(OmrField.QUESTION);
                            item.setOmrResult(result);
                            items.add(item);
                        }
                    }
                    pageDto.setItems(items);
                }
            }
        }
        List<ScanOmrTask> result = new ArrayList<>();
        if (retList.size() == 0) {
            return result;
        }
        for (OmrTaskDto dto : retList) {
            for (OmrTaskPageDto pageDto : dto.getPage()) {
                if (multi_blank) {
                    pageDto.getItems().addAll(pageDto.getPageMultiBlankItems());
                }
                if (single_blank) {
                    pageDto.getItems().addAll(pageDto.getPageSingleBlankItems());
                }
                if (pageDto.getItems().size() > 0) {
                    OmrTaskPage page = new OmrTaskPage();
                    page.setItems(pageDto.getItems());
                    page.setIndex(pageDto.getPageIndex());
                    dto.getTask().getPages().add(page);
                }
            }
            if (dto.getTask().getPages().size() > 0) {
                result.add(dto.getTask());
            }
        }
        return result;
    }

    private List<ScanStudentPaper> clearAndToDispose(ConditionType c, Long studentId) {
        List<ScanStudentPaper> spes = studentPaperService.findByStudentId(studentId);
        if (CollectionUtils.isEmpty(spes)) {
            return spes;
        }
        List<ScanOmrTask> tasks = getByStudent(c, studentId);
        if (CollectionUtils.isEmpty(tasks)) {
            return spes;
        }
        Map<Integer, Long> speMap = new HashMap<>();
        for (ScanStudentPaper spe : spes) {
            speMap.put(spe.getPaperIndex(), spe.getPaperId());
        }
        Map<Integer, Long> taskMap = new HashMap<>();
        for (ScanOmrTask t : tasks) {
            taskMap.put(t.getPaperIndex(), t.getPaperId());
        }
        if (ConditionType.FILL_SUSPECT.equals(c)) {
            List<ScanStudentPaper> ret = new ArrayList<>();
            for (ScanStudentPaper spe : spes) {
                Long paperId = taskMap.get(spe.getPaperIndex());
                if (paperId == null) {// 没有task的直接创建
                    ret.add(spe);
                } else if (paperId.longValue() != spe.getPaperId().longValue()) {// 和task不一致的删除并创建
                    delete(c, studentId, paperId);
                    ret.add(spe);
                }
            }
            for (ScanOmrTask t : tasks) {
                if (speMap.get(t.getPaperIndex()) == null) {// 不在绑定关系的task删除
                    delete(c, studentId, t.getPaperId());
                }
            }
            return ret;
        } else {
            if (spes.size() != tasks.size()) {// 数量不一致的删除重建
                delete(c, studentId);
                return spes;
            }
            for (ScanOmrTask t : tasks) {
                if (!t.getPaperId().equals(speMap.get(t.getPaperIndex()))) {// 有一个不一致的删除重建
                    delete(c, studentId);
                    return spes;
                }
            }
            return null;// 完全一致的不处理
        }
    }

    private List<ScanOmrTask> getByStudent(ConditionType c, Long studentId) {
        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
        lw.eq(ScanOmrTask::getConditions, c);
        lw.eq(ScanOmrTask::getStudentId, studentId);
        return baseMapper.selectList(wrapper);
    }

    private void delete(ConditionType c, Long studentId, Long paperId) {
        UpdateWrapper<ScanOmrTask> wrapper = new UpdateWrapper<>();
        LambdaUpdateWrapper<ScanOmrTask> lw = wrapper.lambda();
        lw.eq(ScanOmrTask::getConditions, c);
        lw.eq(ScanOmrTask::getStudentId, studentId);
        lw.eq(ScanOmrTask::getPaperId, paperId);
        this.baseMapper.delete(wrapper);
    }

    private void delete(ConditionType c, Long studentId) {
        UpdateWrapper<ScanOmrTask> wrapper = new UpdateWrapper<>();
        LambdaUpdateWrapper<ScanOmrTask> lw = wrapper.lambda();
        lw.eq(ScanOmrTask::getConditions, c);
        lw.eq(ScanOmrTask::getStudentId, studentId);
        this.baseMapper.delete(wrapper);
    }

    private boolean isAllBlank(List<ScanStudentPaper> paperIds) {
        for (ScanStudentPaper spe : paperIds) {
            ScanPaper paper = paperService.getById(spe.getPaperId());
            if (paper == null) {
                throw new ParameterException("paper不存在");
            }
            List<ScanPaperPage> pageList = pageService.listByPaperId(spe.getPaperId());
            for (ScanPaperPage pageEntity : pageList) {
                for (int i = 0; pageEntity.getQuestion() != null && pageEntity.getQuestion().getResult() != null
                        && i < pageEntity.getQuestion().getResult().size(); i++) {
                    String result = pageEntity.getQuestion().getResult().get(i);
                    if (!"#".equals(result)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    @Override
    public ScanOmrStudent getTask(Long studentId) {
        MarkStudent student = studentService.getById(studentId);
        if (student == null) {
            throw ExceptionResultEnum.ERROR.exception("没有识别对照任务");
        }
        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
        lw.eq(ScanOmrTask::getStudentId, studentId);
        List<ScanOmrTask> list = baseMapper.selectList(wrapper);
        if (list.isEmpty()) {
            throw ExceptionResultEnum.ERROR.exception("没有识别对照任务");
        }
        ScanOmrStudent scanOmrStudent = new ScanOmrStudent();
        scanOmrStudent.setCardNumber(student.getCardNumber());
        scanOmrStudent.setStudentCode(student.getStudentCode());
        scanOmrStudent.setStudentName(student.getStudentName());
        scanOmrStudent.setCourseCode(student.getCourseCode());
        scanOmrStudent.setCourseName(student.getCourseName());
        scanOmrStudent.setCoursePaperId(student.getCoursePaperId());
        scanOmrStudent.setCoursePaperNumber(student.getPaperNumber());
        scanOmrStudent.setTasks(toTaskVo(list));
        return scanOmrStudent;
    }

    private List<ScanOmrTaskDto> toTaskVo(List<ScanOmrTask> tasks) {
        List<ScanOmrTaskDto> list = new ArrayList<ScanOmrTaskDto>();
        for (ScanOmrTask task : tasks) {
            ScanOmrTaskDto vo = new ScanOmrTaskDto();
            vo.setId(task.getId());
            vo.setPaperId(task.getPaperId());
            vo.setPaperNum(task.getPaperIndex());
            vo.setConditions(task.getConditions());
            List<ScanOmrTaskPageDto> pages = new ArrayList<>();
            for (OmrTaskPage taskPage : task.getPages()) {
                ScanOmrTaskPageDto page = new ScanOmrTaskPageDto();
                Map<Integer, List<String>> question = new HashMap<>();
                // Map<Integer, List<String>> selective = new HashMap<>();
                for (OmrTaskItem item : taskPage.getItems()) {
                    // if (OmrField.ABSENT.equals(item.getField())) {
                    // page.setAbsent(getBooleanItem(item));
                    // }
                    // if (OmrField.BREACH.equals(item.getField())) {
                    // page.setBreach(getBooleanItem(item));
                    // }
                    // if (OmrField.PAPER_TYPE.equals(item.getField())) {
                    // page.setPaperType(getStringItem(item));
                    // }
                    if (OmrField.QUESTION.equals(item.getField())) {
                        List<String> content = getStringItem(item);
                        if (content != null) {
                            question.put(item.getIndex(), content);
                        }
                    }
                    // if (OmrField.SELECTIVE.equals(item.getField())) {
                    // List<String> content = getStringItem(item);
                    // if (content != null) {
                    // selective.put(item.getIndex(), content);
                    // }
                    // }
                }
                if (question.size() > 0) {
                    page.setQuestion(question);
                }
                // if (selective.size() > 0) {
                // page.setSelective(selective);
                // }
                // 有需要仲裁的数据才返回结构
                if (page.getAbsent() != null || page.getBreach() != null || page.getPaperType() != null
                        || page.getQuestion() != null || page.getSelective() != null) {
                    page.setIndex(taskPage.getIndex());
                    ScanPaperPage p = pageService.findPaperIdAndIndex(task.getPaperId(), taskPage.getIndex());
                    page.setRecogData(p.getRecogData());
                    page.setUri(teachcloudCommonService.filePreview(p.getSheetPath()));
                    pages.add(page);
                }
            }
            vo.setPages(pages);
            list.add(vo);
        }
        return list;
    }

    private List<String> getStringItem(OmrTaskItem item) {
        // 只取最新的值
        List<String> value = new ArrayList<>();
        if (item.getSecondResult() != null) {
            value.add(item.getSecondResult());
        } else if (item.getFirstResult() != null && item.getSecondResult() == null) {
            value.add(item.getFirstResult());
        } else {
            value.add(item.getOmrResult());
        }
        return value;
    }

    private List<Boolean> getBooleanItem(OmrTaskItem item) {
        List<Boolean> value = new ArrayList<>();
        value.add(Boolean.valueOf(item.getOmrResult()));
        if (item.getFirstResult() != null && item.getSecondResult() == null) {
            value.add(Boolean.valueOf(item.getFirstResult()));
        } else if (item.getSecondResult() != null) {
            value.add(Boolean.valueOf(item.getSecondResult()));
        }
        return value;
    }

    @Override
    @Transactional
    public ScanOmrTaskSaveDto submitTask(@NotNull List<ScanOmrTaskResultDto> results, @NotNull Long userId) {
        Long studentId = null;
        for (ScanOmrTaskResultDto result : results) {
            ScanOmrTask task = this.getById(result.getId());
            if (task == null) {
                throw new ParameterException("任务不存在");
            }
            if (studentId == null) {
                studentId = task.getStudentId();
            }
            if (!Objects.equals(studentId, task.getStudentId())) {
                throw new ParameterException("任务非同一个学生");
            }
            MarkStudent markStudent = studentService.getById(studentId);
            if (markStudent == null) {
                throw new ParameterException("考生不存在");
            }
            MarkPaper markPaper = markPaperService.getByExamIdAndCoursePaperId(markStudent.getExamId(),
                    markStudent.getCoursePaperId());
            if (markPaper == null) {
                throw new ParameterException("课程不存在");
            }
            if (MarkPaperStatus.FINISH.equals(markPaper.getStatus())) {
                throw ExceptionResultEnum.MARK_PAPER_FINISH.exception();
            }
            concurrentService.getReadWriteLock(LockType.STUDENT + "-" + task.getStudentId()).writeLock().lock();

            try {
                for (OmrTaskPage page : task.getPages()) {
                    ScanOmrTaskResultPageDto pageVo = result.findPage(page.getIndex());
                    if (pageVo == null) {
                        throw new ParameterException("page[" + page.getIndex() + "]不存在");
                    }
                    for (OmrTaskItem item : page.getItems()) {
                        // if (OmrField.ABSENT.equals(item.getField())) {
                        // if (pageVo.getAbsent() == null) {
                        // throw new ParameterException("page[" + page.getIndex() + "].absent不存在");
                        // }
                        // item.setFirstResult(pageVo.getAbsent().toString());
                        // }
                        // if (OmrField.BREACH.equals(item.getField())) {
                        // if (pageVo.getBreach() == null) {
                        // throw new ParameterException("page[" + page.getIndex() + "].breach不存在");
                        // }
                        // item.setFirstResult(pageVo.getBreach().toString());
                        // }
                        if (OmrField.QUESTION.equals(item.getField())) {
                            String content = pageVo.getQuestion() != null ? pageVo.getQuestion().get(item.getIndex())
                                    : null;
                            if (content == null) {
                                throw new ParameterException(
                                        "page[" + page.getIndex() + "].question[" + item.getIndex() + "]不存在");
                            }
                            item.setFirstResult(content);
                        }
                        // if (OmrField.SELECTIVE.equals(item.getField())) {
                        // String content = pageVo.getSelective() != null ?
                        // pageVo.getSelective().get(item.getIndex())
                        // : null;
                        // if (content == null) {
                        // throw new ParameterException(
                        // "page[" + page.getIndex() + "].selective[" + item.getIndex() + "]不存在");
                        // }
                        // item.setFirstResult(content);
                        // }
                    }
                }
                task.setStatus(OmrTaskStatus.PROCESSED);
                updatePaperResult(result, task.getPaperId(), userId);
                task.setUserId(userId);
                task.setUpdateTime(System.currentTimeMillis());
                this.saveOrUpdate(task);
            } finally {
                concurrentService.getReadWriteLock(LockType.STUDENT + "-" + task.getStudentId()).writeLock().unlock();
            }
        }
        ScanOmrTaskSaveDto vo = new ScanOmrTaskSaveDto();
        vo.setStudentId(studentId);
        vo.setUpdateTime(System.currentTimeMillis());
        return vo;
    }

    private void updatePaperResult(ScanOmrTaskResultDto result, Long paperId, Long userId) {
        ScanPaper paper = paperService.getById(paperId);
        ScanStudentPaper sp = studentPaperService.findByPaperId(paperId);
        if (paper == null) {
            throw new ParameterException("未找到paper信息");
        }
        if (sp == null) {
            throw new ParameterException("paper未绑定考生");
        }
        List<ScanPaperPage> pages = pageService.listByPaperId(paperId);
        if (CollectionUtils.isEmpty(pages)) {
            throw new ParameterException("未找到page信息");
        }
        for (ScanPaperPage page : pages) {
            ScanOmrTaskResultPageDto vo = result.findPage(page.getPageIndex());
            if (vo != null) {
                vo.update(page);
            }
        }
        paperService.savePaperAndPages(paper, pages);
        studentService.updateStudentAnswer(sp.getStudentId());
    }

    @Override
    public ScanOmrTaskStatusDto getStatus(Long examId, String courseCode, String coursePaperId) {
        SysUser user = (SysUser) ServletUtil.getRequestUser();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(user.getSchoolId(), user.getId(),
                ServletUtil.getRequest().getServletPath());
        ScanOmrTaskStatusDto status = new ScanOmrTaskStatusDto();
        status.setFinishCount(this.getFinishStudentCountByExamAndUserId(examId, courseCode, coursePaperId,
                OmrTaskStatus.PROCESSED.name(), dpr));
        status.setTodoCount(this.getFinishStudentCountByExamAndUserId(examId, courseCode, coursePaperId,
                OmrTaskStatus.WAITING.name(), dpr));
        return status;
    }

    @Override
    public int getFinishStudentCountByExamAndUserId(Long examId, String courseCode, String coursePaperId, String status,
            DataPermissionRule dpr) {
        return this.baseMapper.getStudentCountByExamAndStatusAndUserId(examId, courseCode, coursePaperId, status,
                MarkPaperStatus.FORMAL.name(), dpr);
    }

    @Transactional
    @Override
    public void deleteByStudentId(Long examId, Long studentId) {
        QueryWrapper<ScanOmrTask> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanOmrTask> lw = wrapper.lambda();
        lw.eq(ScanOmrTask::getExamId, examId);
        lw.eq(ScanOmrTask::getStudentId, studentId);
        List<ScanOmrTask> tasks = baseMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(tasks)) {
            return;
        }
        concurrentService.getReadWriteLock(LockType.STUDENT + "-" + studentId).writeLock().lock();
        try {
            List<Long> ids = tasks.stream().map(e -> e.getId()).collect(Collectors.toList());
            this.removeByIds(ids);
        } finally {
            concurrentService.getReadWriteLock(LockType.STUDENT + "-" + studentId).writeLock().unlock();
        }
    }

    @Override
    public int getCount(Long examId, OmrTaskStatus status, String courseCode, String coursePaperId,
            MarkPaperStatus markPaperStatus, DataPermissionRule dpr) {
        ScanOmrTask scanOmrTask = new ScanOmrTask();
        scanOmrTask.setExamId(examId);
        scanOmrTask.setCourseCode(courseCode);
        scanOmrTask.setCoursePaperId(coursePaperId);
        scanOmrTask.setStatus(status);
        scanOmrTask.setMarkPaperStatus(markPaperStatus.name());
        return baseMapper.countOmrTask(scanOmrTask, dpr);
    }

    @Override
    public List<ScanStudentDto> list(Long examId, String courseCode, String coursePaperId, OmrTaskStatus status) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(),
                sysUser.getId(), ServletUtil.getRequest().getServletPath());
        return this.baseMapper.listByExamIdAndStatusAndUserId(examId, courseCode, coursePaperId, status,
                MarkPaperStatus.FORMAL.name(), dpr);
    }

    @Override
    public void saveTask(Long studentId) {
        List<ScanOmrTask> omrTaskList = new ArrayList<ScanOmrTask>();
        for (ConditionType c : ConditionType.values()) {
            List<ScanOmrTask> omrTask = this.buildTask(c, studentId);
            if (omrTask!=null && !omrTask.isEmpty()) {
                omrTaskList.addAll(omrTask);
            }
        }
        if (!omrTaskList.isEmpty()) {
            this.saveBatch(omrTaskList);
        }
    }
}
