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

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.qmth.distributed.print.business.bean.dto.initMarkData.ExamDetailCourseInitMarkDto;
import com.qmth.distributed.print.business.bean.dto.initMarkData.InitExamDetailDto;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.CardTypeEnum;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicAttachment;
import com.qmth.teachcloud.common.entity.MarkQuestion;
import com.qmth.teachcloud.common.enums.CardCreateMethodEnum;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.UploadFileEnum;
import com.qmth.teachcloud.common.service.BasicAttachmentService;
import com.qmth.teachcloud.common.util.ExamTaskUtil;
import com.qmth.teachcloud.mark.bean.answercard.CardFile;
import com.qmth.teachcloud.mark.bean.vo.parseCard.Struct;
import com.qmth.teachcloud.mark.entity.MarkPaper;
import com.qmth.teachcloud.mark.entity.MarkPaperPackage;
import com.qmth.teachcloud.mark.entity.MarkStudent;
import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
import com.qmth.teachcloud.mark.enums.CardSource;
import com.qmth.teachcloud.mark.service.*;
import com.qmth.teachcloud.mark.utils.CardParseUtils;
import com.qmth.teachcloud.mark.utils.FileStoreUtils;
import com.qmth.teachcloud.task.service.PrintFinishService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
public class PrintFinishServiceImpl implements PrintFinishService {

    private static final Logger log = LoggerFactory.getLogger(PrintFinishServiceImpl.class);

    @Resource
    private BasicAttachmentService basicAttachmentService;
    @Resource
    private MarkPaperService markPaperService;
    @Resource
    private MarkQuestionService markQuestionService;
    @Resource
    private MarkStudentService markStudentService;
    @Resource
    private ScanAnswerCardService scanAnswerCardService;
    @Resource
    private MarkPaperPackageService markPaperPackageService;
    @Resource
    private ExamDetailService examDetailService;
    @Resource
    private ExamStudentService examStudentService;
    @Resource
    private ExamTaskDetailService examTaskDetailService;
    @Resource
    private ExamTaskPaperDataService examTaskPaperDataService;
    @Resource
    private ExamCardService examCardService;
    @Resource
    private FileStoreUtils fileStoreUtils;
    @Resource
    private MarkFileService markFileService;

    /**
     * 打印结束后，生成阅卷科目数据
     *
     * @param examId
     * @param courseCode
     * @param courseName
     * @param paperNumber
     * @param paperInfoVos
     */
    @Transactional
    @Override
    public void insertMarkPaper(Long examId, String courseCode, String courseName, String paperNumber, String coursePaperId, Long userId, String paperType, List<PaperInfoVo> paperInfoVos) {
        try {
            MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumberAndPaperType(examId, paperNumber, paperType);
            if (markPaper == null) {
                MarkPaper insertMarkPaper = new MarkPaper(examId, courseCode, courseName, paperNumber, coursePaperId, userId, paperType);
                if (CollectionUtils.isNotEmpty(paperInfoVos)) {
                    BasicAttachment basicAttachment = basicAttachmentService.getById(paperInfoVos.get(0).getAttachmentId());
                    if (basicAttachment != null) {
                        insertMarkPaper.setPaperFilePath(basicAttachment.getPath());
                    }
                }
                markPaperService.save(insertMarkPaper);
            }
        } catch (Exception e) {
            log.info("同步考试课程失败");
        }
    }

    @Transactional
    @Override
    public void insertMarkStudent(ExamDetailCourseInitMarkDto dto, String paperType) {
        try {
            List<InitExamDetailDto> initExamDetailDtoList = examDetailService.listPrintFinishExamDetailCourseIds(dto.getExamId(), dto.getPaperNumber(), paperType);

            List<MarkStudent> markStudentList = new ArrayList<>();
            Set<String> secretNumberSet = new HashSet<>();
            for (InitExamDetailDto initExamDetailDto : initExamDetailDtoList) {
                List<ExamStudent> examStudentList = examStudentService.listByExamDetailCourseIdNotIntMarkStudent(initExamDetailDto.getExamDetailCourseId(), paperType);
                for (ExamStudent examStudent : examStudentList) {
                    MarkStudent markStudent = markStudentService.getById(examStudent.getId());
                    if (markStudent != null) {
                        continue;
                    }
                    MarkStudent student = new MarkStudent(examStudent.getId(), dto.getExamId(), dto.getCourseCode(), dto.getCourseName(), dto.getPaperNumber(), dto.getCoursePaperId(), paperType, examStudent.getStudentCode(), examStudent.getStudentName(), initExamDetailDto.getPackageCode(), initExamDetailDto.getExamPlace(), initExamDetailDto.getExamRoom(), examStudent.getCollegeName(), examStudent.getMajorName(), examStudent.getTeachClazzName(), examStudent.getTeacherId(), examStudent.getTeacherName(), dto.getExamStartTime(), dto.getExamEndTime(), dto.getCreateId());
                    if (student.getSecretNumber() == null) {
                        student.randomSecretNumber();
                        while (secretNumberSet.contains(student.getSecretNumber())
                                || markStudentService.countByExamIdAndSecretNumber(student.getExamId(), student.getSecretNumber()) > 0) {
                            student.randomSecretNumber();
                        }
                    }
                    markStudentList.add(student);
                }
            }

            if (CollectionUtils.isNotEmpty(markStudentList)) {
                markStudentService.saveBatch(markStudentList);
                // 更新mark_paper表student_count字段
                markPaperService.updateStudentCountByExamIdAndPaperNumberAndPaperType(dto.getExamId(), dto.getPaperNumber(), paperType);
            }
        } catch (Exception e) {
            log.info("考生同步阅卷失败", e.getMessage());
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
    }

    @Override
    public void insertScanAnswerCardAndMarkQuestion(ExamDetailCourseInitMarkDto dto, String paperType) {
        if (StringUtils.isNotBlank(paperType)) {
            ExamTaskDetail examTaskDetail = examTaskDetailService.findByExamIdAndCourseCodeAndPaperNumber(dto.getExamId(), dto.getCourseCode(), dto.getPaperNumber());
            List<PaperInfoVo> paperInfoVoList = ExamTaskUtil.parsePaperAttachmentPath(examTaskDetail.getPaperAttachmentIds(), paperType);
            for (PaperInfoVo paperInfoVo : paperInfoVoList) {
                ExamCard examCard = examCardService.getById(paperInfoVo.getCardId());
                if (examCard != null) {
                    // 上传通卡，不同步卡格式
                    if (CardTypeEnum.GENERIC.equals(examCard.getType()) && CardCreateMethodEnum.UPLOAD.equals(examCard.getCreateMethod())) {
                        continue;
                    }
                    // 解析卡格式中试卷结构并保存
                    this.insertMarkQuestion(dto.getExamId(), dto.getPaperNumber(), paperType, examCard.getContent());
                    // 生成并保存卡格式文件（后缀为.json）
                    this.insertScanAnswerCard(dto, paperInfoVo, examCard.getContent());
                    // 题库获取的试卷，同步标答文件
                    if (examCard.getPaperId() != null) {
                        this.insertPaperAnswerFile(dto.getExamId(), dto.getPaperNumber(), paperType, examCard.getPaperId());
                    }
                }
            }
        }
    }

    @Override
    public void insertScanAnswerCard(ExamDetailCourseInitMarkDto dto, PaperInfoVo paperInfoVo, String content) {
        ExamCard examCard = examCardService.getById(paperInfoVo.getCardId());
        if (examCard != null) {
            ScanAnswerCard scanAnswerCard = scanAnswerCardService.getByExamIdAndCoursePaperIdAndCardId(dto.getExamId(), dto.getCoursePaperId(), Long.valueOf(paperInfoVo.getCardId()));
            if (scanAnswerCard != null) {
                return;
            }

            File tempFile = SystemConstant.getFileTempDirVar(System.currentTimeMillis() + File.separator + SystemConstant.getNanoId(), SystemConstant.TEMP_PREFIX);
            String rootPath = tempFile.getParent();
            String jsonPath = rootPath + File.separator + paperInfoVo.getCardId() + SystemConstant.JSON_PREFIX;

            InputStream inputStream = null;
            File jsonFile = null;
            try {
                // 将知学知考卡格式内容，转换为扫描端格式
                CardFile cardFile = CardFile.parse(examCard.getContent());
                jsonFile = SystemConstant.createJsonFile(jsonPath, cardFile.output());
                if (jsonFile.exists()) {
                    inputStream = new FileInputStream(jsonFile);
                    String md5 = DigestUtils.md5Hex(new FileInputStream(jsonFile));
                    Integer number = scanAnswerCardService.findMaxCardNumberByExamId(dto.getExamId()) + 1;
                    String path = markFileService.getAnswerCardUri(dto.getExamId(), dto.getCoursePaperId(), number);
                    String uploadPath = fileStoreUtils.uploadFile(inputStream, md5, UploadFileEnum.CARD, path);

                    scanAnswerCard = new ScanAnswerCard();
                    scanAnswerCard.setId(SystemConstant.getDbUuid());
                    scanAnswerCard.setExamId(dto.getExamId());
                    scanAnswerCard.setPaperNumber(dto.getPaperNumber());
                    scanAnswerCard.setCoursePaperId(dto.getCoursePaperId());
                    scanAnswerCard.setPaperType(dto.getPaperType());
                    scanAnswerCard.setCardId(Long.valueOf(paperInfoVo.getCardId()));
                    scanAnswerCard.setNumber(number);
                    scanAnswerCard.setSource(CardSource.WEB);
                    scanAnswerCard.setUri(uploadPath);
                    scanAnswerCard.setMd5(md5);
                    scanAnswerCard.setNeedAdapte(true);
                    scanAnswerCard.setSinglePage(false);// 默认false
                    // 题卡张数
                    int paperCount = CardParseUtils.calcPaperCount(content, true);
                    scanAnswerCard.setPaperCount(paperCount);
                    scanAnswerCardService.save(scanAnswerCard);
                }
            } catch (IOException e) {
                log.info("考试[{}]，试卷编号[{}]，题卡ID[{}]同步阅卷失败", dto.getExamId(), dto.getPaperNumber(), paperInfoVo.getCardId());
            } finally {
                try {
                    FileUtils.forceDeleteOnExit(jsonFile);
                } catch (IOException e) {
                    log.info("删除jsonFile失败");
                }
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        log.info("关闭inputStream流失败");
                    }
                }
            }


        }
    }

    @Override
    public void insertMarkQuestion(Long examId, String paperNumber, String paperType, String content) {
        try {
            List<Struct> structList = CardParseUtils.parseCardContent(content);
            if (CollectionUtils.isEmpty(structList)) {
                return;
            }
            List<MarkQuestion> markQuestionList = markQuestionService.listQuestionByExamIdAndPaperNumberAndPaperType(examId, paperNumber, paperType);
            // 第一次新增
            if (CollectionUtils.isEmpty(markQuestionList)) {
                List<MarkQuestion> markQuestions = new ArrayList<>();
                for (Struct struct : structList) {
                    MarkQuestion markQuestion = new MarkQuestion();
                    markQuestion.setId(SystemConstant.getDbUuid());
                    markQuestion.setExamId(examId);
                    markQuestion.setPaperNumber(paperNumber);
                    markQuestion.setPaperType(paperType);
                    markQuestion.setObjective(struct.getObjective());
                    markQuestion.setMainNumber(struct.getMainNumber());
                    markQuestion.setSubNumber(struct.getSubNumber());
                    markQuestion.setMainTitle(struct.getMainTitle());
                    markQuestion.setOptionCount(struct.getOptionCount());
                    markQuestion.setQuestionType(struct.getType());
                    markQuestion.setPaperIndex(struct.getPaperIndex());
                    markQuestion.setPageIndex(struct.getPageIndex());
                    if (StringUtils.isNotBlank(struct.getAnswer())) {
                        markQuestion.setAnswer(struct.getAnswer());
                    }
                    if (struct.getScore() != null) {
                        markQuestion.setTotalScore(struct.getScore());
                        // 间隔分（整数默认1，小数默认0.5）
                        if (!markQuestion.getObjective()) {
                            markQuestion.setIntervalScore(markQuestion.getTotalScore() % 1 > 0 ? 0.5 : 1);
                        }
                    }
                    markQuestions.add(markQuestion);
                }
                markQuestionService.saveBatch(markQuestions);
            } else {
//                List<ScanAnswerCard> scanAnswerCardList = scanAnswerCardService.listByExamIdAndPaperNumber(examId, paperNumber);
//                if (CollectionUtils.isNotEmpty(scanAnswerCardList)) {
//                    for (ScanAnswerCard scanAnswerCard : scanAnswerCardList) {
//                        int count = scanPaperService.getCountByExamAndCardNumber(examId, scanAnswerCard.getNumber());
//                        if (count > 0) {
//                            return;
//                        }
//                    }
//                }
            }
        } catch (Exception e) {
            log.info("同步结构失败");
        }
    }

    @Override
    public void insertPaperAnswerFile(Long examId, String paperNumber, String paperType, Long paperId) {
        MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumberAndPaperType(examId, paperNumber, paperType);
        if (markPaper != null) {
            ExamTaskPaperData examTaskPaperData = examTaskPaperDataService.selectByMultiId(new ExamTaskPaperData(examId, paperNumber, paperId));
            if (examTaskPaperData != null && examTaskPaperData.getAnswerPdfAttachmentId() != null) {
                BasicAttachment basicAttachment = basicAttachmentService.getById(examTaskPaperData.getAnswerPdfAttachmentId());
                if (basicAttachment != null && StringUtils.isNotBlank(basicAttachment.getPath())) {
                    UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.lambda().set(MarkPaper::getAnswerFilePath, basicAttachment.getPath())
                            .eq(MarkPaper::getId, markPaper.getId());
                    markPaperService.update(updateWrapper);
                }
            }
        }
    }

    @Override
    public void insertMarkPaperPackageCode(ExamDetailCourseInitMarkDto dto, String paperType) {
        List<ExamDetailCourseInitMarkDto> packageCodeList = examDetailService.listPrintFinishPackageCode(dto.getExamId(), dto.getPaperNumber(), paperType);
        if (CollectionUtils.isNotEmpty(packageCodeList)) {
            List<MarkPaperPackage> markPaperPackages = new ArrayList<>();
            for (ExamDetailCourseInitMarkDto packageCodeDto : packageCodeList) {
                markPaperPackages.add(new MarkPaperPackage(packageCodeDto.getExamId(), packageCodeDto.getCourseCode(), packageCodeDto.getCourseName(), packageCodeDto.getPaperNumber(), packageCodeDto.getCoursePaperId(), paperType, packageCodeDto.getPackageCode()));
            }
            markPaperPackageService.saveOrUpdateBatchByMultiId(markPaperPackages);
        }
    }
}
