package com.qmth.distributed.print.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.distributed.print.business.bean.params.analyze.AbleAnalyzePaperParam;
import com.qmth.distributed.print.business.bean.params.analyze.GradeBatchPaperParam;
import com.qmth.distributed.print.business.bean.result.DictionaryResult;
import com.qmth.distributed.print.business.bean.result.analyze.GradeBatchPaperResult;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.mapper.GradeBatchPaperMapper;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.SysOrg;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.GradeAnalyzePaperStatusEnum;
import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
import com.qmth.teachcloud.common.service.SysOrgService;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 分析-批次试卷关联关系表 服务实现类
 * </p>
 *
 * @author wangliang
 * @since 2022-05-20
 */
@Service
public class GradeBatchPaperServiceImpl extends ServiceImpl<GradeBatchPaperMapper, GradeBatchPaper> implements GradeBatchPaperService {
    @Resource
    SysOrgService sysOrgService;
    @Resource
    GradeBatchService gradeBatchService;
    @Resource
    GradePaperDimensionService gradePaperDimensionService;
    @Resource
    GradePaperStructService gradePaperStructService;
    @Resource
    GradePaperService gradePaperService;
    @Resource
    GradeModuleDefineService gradeModuleDefineService;
    @Resource
    GradeModuleEvaluationService gradeModuleEvaluationService;
    @Resource
    ExamTaskService examTaskService;
    @Resource
    BasicRoleDataPermissionService basicRoleDataPermissionService;

    @Override
    public IPage<GradeBatchPaperResult> findGradeBatchPaperPage(Long batchId, Long examId, String courseName, int pageNumber, int pageSize, SysUser requestUser) {
        Long schoolId = requestUser.getSchoolId();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(schoolId, requestUser.getId(), ServletUtil.getRequest().getServletPath());
        courseName = SystemConstant.translateSpecificSign(courseName);
        IPage<GradeBatchPaperResult> datasource = this.baseMapper.findGradeBatchPaperPage(new Page<>(pageNumber, pageSize), batchId, examId, courseName, schoolId, dpr);
        for (GradeBatchPaperResult record : datasource.getRecords()) {
            Long teachingRoomId = record.getTeachingRoomId();
            SysOrg teachCollege = sysOrgService.findCollegeLevelOrgByOrgId(teachingRoomId);
            if (Objects.nonNull(teachCollege)){
                record.setTeachCollegeId(teachCollege.getId());
                record.setTeachCollegeName(teachCollege.getName());
            }
        }
        return datasource;
    }

    @Override
    public List<GradeBatchPaperResult> findAbleAnalyzePaperList(Long batchId, Long examId, Long collegeId, String courseCode, String teacherName, SysUser requestUser) {
        Long schoolId = requestUser.getSchoolId();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(schoolId, requestUser.getId(), ServletUtil.getRequest().getServletPath());
        GradeBatch gradeBatch = gradeBatchService.getById(batchId);
        if (Objects.isNull(gradeBatch)) {
            throw ExceptionResultEnum.ERROR.exception("教研分析批次不存在");
        }

        List<GradeBatchPaperResult> datasource = this.baseMapper.findAbleAnalyzePaper(gradeBatch.getSemesterId(), examId, collegeId, courseCode, SystemConstant.translateSpecificSign(teacherName), dpr, schoolId);
        List<GradeBatchPaperResult> copy = new ArrayList<>();

        for (GradeBatchPaperResult gradeBatchPaperResult : datasource) {
            // 额外处理开课学院
            Long teachingRoomId = gradeBatchPaperResult.getTeachingRoomId();
            SysOrg teachCollege = sysOrgService.findCollegeLevelOrgByOrgId(teachingRoomId);
            if (SystemConstant.longNotNull(collegeId) && !collegeId.equals(teachCollege.getId())) {
                continue;
            }
            gradeBatchPaperResult.setPaperName(gradeBatchPaperResult.getCourseName());
            gradeBatchPaperResult.setTeachCollegeId(teachCollege.getId());
            gradeBatchPaperResult.setTeachCollegeName(teachCollege.getName());
            copy.add(gradeBatchPaperResult);
        }
        return copy.stream().sorted(Comparator.comparing(GradeBatchPaperResult::getSemesterName)
                .thenComparing(GradeBatchPaperResult::getExamName)
                .thenComparing(GradeBatchPaperResult::getTeachCollegeId)
                .thenComparing(GradeBatchPaperResult::getCourseCode)
                .thenComparing(GradeBatchPaperResult::getPaperNumber)
                .thenComparing(GradeBatchPaperResult::getPaperType)).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveGradeBatchPaper(GradeBatchPaperParam gradeBatchPaperParam, SysUser requestUser) {
        Long batchId = gradeBatchPaperParam.getBatchId();
        Long schoolId = requestUser.getSchoolId();
        GradeBatch gradeBatch = gradeBatchService.getById(batchId);
        if (Objects.isNull(gradeBatch)){
            throw ExceptionResultEnum.ERROR.exception("分析批次不存在");
        }
        Long examId = gradeBatch.getExamId();
        List<AbleAnalyzePaperParam> ableAnalyzePaperParamList = gradeBatchPaperParam.getAbleAnalyzePaperList();

        // 是否需要更新批次状态
        AtomicBoolean updateBatchStatus = new AtomicBoolean(false);
        List<GradeBatchPaper> gradeBatchPaperList = ableAnalyzePaperParamList.stream().flatMap(e -> {
            String paperNumber = e.getPaperNumber();
            String paperType = e.getPaperType();
            Long teachCollegeId = e.getTeachCollegeId();
            String teachCollegeName = e.getTeachCollegeName();
            String paperName = e.getPaperName();

            GradeBatchPaper gradeBatchPaper = new GradeBatchPaper();
            gradeBatchPaper.setSchoolId(schoolId);
            gradeBatchPaper.setBatchId(batchId);
            gradeBatchPaper.setExamId(examId);
            gradeBatchPaper.setPaperNumber(paperNumber);
            gradeBatchPaper.setPaperType(paperType);
            gradeBatchPaper.setPaperName(e.getPaperName());
            gradeBatchPaper.setTeachCollegeId(teachCollegeId);
            gradeBatchPaper.setTeachCollegeName(teachCollegeName);


            GradeBatchPaper dbBatchPaper = this.getOne(new QueryWrapper<GradeBatchPaper>().lambda()
                    .eq(GradeBatchPaper::getSchoolId, schoolId)
                    .eq(GradeBatchPaper::getBatchId, batchId)
                    .eq(GradeBatchPaper::getPaperNumber, paperNumber)
                    .eq(GradeBatchPaper::getPaperType, paperType));
            if (Objects.isNull(dbBatchPaper)) {
                // 新增
                gradeBatchPaper.insertInfo(requestUser.getId());
                gradeBatchPaper.setStatus(GradeAnalyzePaperStatusEnum.PUSH_GRADE_BATCH);
                gradeBatchPaper.setEnable(true);
                gradeBatchPaper.setPublishStatus(false);
                gradeBatchPaper.setOrgId(requestUser.getOrgId());
                updateBatchStatus.set(true);

                // 更新批次状态为PUSH_GRADE_BATCH
                UpdateWrapper<GradeBatch> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().set(GradeBatch::getStatus, GradeAnalyzePaperStatusEnum.PUSH_GRADE_BATCH).eq(GradeBatch::getId, batchId);
                gradeBatchService.update(updateWrapper);
            } else {
                // 编辑（计算中的不允许被编辑，其他状态下的只要开课学院和试卷名称有变化，状态就更新为需要重新推送）
                GradeAnalyzePaperStatusEnum dbStatus = dbBatchPaper.getStatus();
                if (GradeAnalyzePaperStatusEnum.CALCULATING.equals(dbStatus)) {
                    throw ExceptionResultEnum.ERROR.exception("试卷编号为【" + paperNumber + "】，试卷类型为【" + paperType + "】的分析试卷正在计算中请稍后再试");
                }
                if (!teachCollegeId.equals(dbBatchPaper.getTeachCollegeId()) || !teachCollegeName.equals(dbBatchPaper.getTeachCollegeName()) || !paperName.equals(dbBatchPaper.getPaperName())) {
                    gradeBatchPaper.setStatus(GradeAnalyzePaperStatusEnum.PUSH_GRADE_BATCH);
                    updateBatchStatus.set(true);
                }
                gradeBatchPaper.setId(dbBatchPaper.getId());
                gradeBatchPaper.setEnable(true);
                gradeBatchPaper.setStatus(dbBatchPaper.getStatus());
                gradeBatchPaper.setPublishStatus(dbBatchPaper.getPublishStatus());
                gradeBatchPaper.updateInfo(requestUser.getId());
            }
            return Stream.of(gradeBatchPaper);
        }).collect(Collectors.toList());

        this.saveOrUpdateBatch(gradeBatchPaperList);

        // 更新批次状态
        if (updateBatchStatus.get()) {
            UpdateWrapper<GradeBatch> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(GradeBatch::getStatus, GradeAnalyzePaperStatusEnum.PUSH_GRADE_BATCH).eq(GradeBatch::getId, batchId);
            gradeBatchService.update(updateWrapper);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteGradeBatchPaper(Long batchId, List<Long> idList) {
        for (Long id : idList) {
            GradeBatchPaper gradeBatchPaper = this.getById(id);
            if (GradeAnalyzePaperStatusEnum.CALCULATING.equals(gradeBatchPaper.getStatus())) {
                throw ExceptionResultEnum.ERROR.exception("试卷编号为【" + gradeBatchPaper.getPaperNumber() +
                        "】，试卷类型为【" + gradeBatchPaper.getPaperType() + "】的分析试卷正在计算中请稍后再试");
            }
            if (gradeBatchPaper.getPublishStatus()) {
                throw ExceptionResultEnum.ERROR.exception("试卷编号为【" + gradeBatchPaper.getPaperNumber() +
                        "】，试卷类型为【" + gradeBatchPaper.getPaperType() + "】的分析试卷已发布，不能删除");
            }
        }
        // 更新批次状态为status=PUSH_GRADE_BATCH
        UpdateWrapper<GradeBatch> gradeBatchUpdateWrapper = new UpdateWrapper<>();
        gradeBatchUpdateWrapper.lambda().set(GradeBatch::getStatus, GradeAnalyzePaperStatusEnum.PUSH_GRADE_BATCH).eq(GradeBatch::getId, batchId);
        gradeBatchService.update(gradeBatchUpdateWrapper);

        // 更新enale=false
        UpdateWrapper<GradeBatchPaper> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(GradeBatchPaper::getEnable, false).in(GradeBatchPaper::getId, idList);
        this.update(updateWrapper);
    }

    @Override
    public GradeBatchPaper findByThirdExamIdAndGradeCourseCode(Long schoolId, String thirdExamId, String gradeCourseCode) {
        return this.baseMapper.findByThirdExamIdAndGradeCourseCode(schoolId, thirdExamId, gradeCourseCode);
    }

    @Transactional
    @Override
    public void checkOperateAuth(Long schoolId, Long examId, String paperNumber, String paperType) {
        List<GradeBatchPaper> gradeBatchPaperList = this.list(new QueryWrapper<GradeBatchPaper>().lambda()
                .eq(GradeBatchPaper::getSchoolId, schoolId)
                .eq(GradeBatchPaper::getExamId, examId)
                .eq(GradeBatchPaper::getPaperNumber, paperNumber)
                .eq(GradeBatchPaper::getPaperType, paperType));
        if (gradeBatchPaperList.stream().anyMatch(e -> GradeAnalyzePaperStatusEnum.CALCULATING.equals(e.getStatus()))) {
            throw ExceptionResultEnum.ERROR.exception("选择的试卷有正在计算的分析课程");
        }
        if (gradeBatchPaperList.stream().anyMatch(GradeBatchPaper::getPublishStatus)) {
            throw ExceptionResultEnum.ERROR.exception("选择的试卷有已发布的分析课程，不能更新分析配置参数");
        }
        List<Long> batchIdList = gradeBatchPaperList.stream().map(GradeBatchPaper::getBatchId).distinct().collect(Collectors.toList());
        if (batchIdList.size() > 0) {
            if (gradeBatchService.list(new QueryWrapper<GradeBatch>().lambda().in(GradeBatch::getId, batchIdList)).stream().anyMatch(e -> GradeAnalyzePaperStatusEnum.CALCULATING.equals(e.getStatus()))) {
                throw ExceptionResultEnum.ERROR.exception("所选择的试卷所属的批次正在计算中不能更改");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePaperAndBatchStatus(Long schoolId, Long examId, String paperNumber, String paperType) {
        if (this.analyzeDataReady(schoolId, examId, paperNumber, paperType)) {
            List<GradeBatchPaper> gradeBatchPaperList = this.list(new QueryWrapper<GradeBatchPaper>().lambda()
                    .eq(GradeBatchPaper::getSchoolId, schoolId)
                    .eq(GradeBatchPaper::getExamId,examId)
                    .eq(GradeBatchPaper::getPaperNumber, paperNumber)
                    .eq(GradeBatchPaper::getPaperType, paperType));
            // 如果所有数据都有，则更新状态
            // 更新批次科目状态
            for (GradeBatchPaper gradeBatchPaper : gradeBatchPaperList) {
                gradeBatchPaper.setStatus(GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE);
                this.updateById(gradeBatchPaper);

                // 更新批次状态
                GradeBatch gradeBatch = gradeBatchService.getById(gradeBatchPaper.getBatchId());
                // 批次未推送成功，不更新状态
                if (GradeAnalyzePaperStatusEnum.PUSH_GRADE_BATCH.equals(gradeBatch.getStatus())) {
                    continue;
                }
                if (GradeAnalyzePaperStatusEnum.FINISH_CALCULATE.equals(gradeBatch.getStatus())) {
                    gradeBatch.setStatus(GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE);
                    gradeBatchService.updateById(gradeBatch);
                } else {
                    QueryWrapper<GradeBatchPaper> queryWrapperList = new QueryWrapper<>();
                    queryWrapperList.lambda().eq(GradeBatchPaper::getBatchId, gradeBatchPaper.getBatchId());
                    List<GradeBatchPaper> gradeBatchPaperAll = this.list(queryWrapperList);
                    if (!gradeBatchPaperAll.isEmpty()) {
                        long count = gradeBatchPaperAll.stream().filter(m -> !GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE.equals(m.getStatus())).count();
                        if (count == 0) {
                            // 更新批次状态
                            UpdateWrapper<GradeBatch> updateWrapper = new UpdateWrapper<>();
                            updateWrapper.lambda().set(GradeBatch::getStatus, GradeAnalyzePaperStatusEnum.READY_TO_CALCULATE).eq(GradeBatch::getId, gradeBatchPaper.getBatchId());
                            gradeBatchService.update(updateWrapper);
                        }
                    }
                }
            }
        }
    }

    @Override
    public boolean analyzeDataReady(Long schoolId, Long examId, String paperNumber, String paperType) {
        // 检验维度数据存在
        boolean dimensionExist = gradePaperDimensionService.list(new QueryWrapper<GradePaperDimension>().lambda()
                        .eq(GradePaperDimension::getSchoolId, schoolId)
                        .eq(GradePaperDimension::getExamId, examId)
                        .eq(GradePaperDimension::getPaperNumber, paperNumber)
                        .eq(GradePaperDimension::getPaperType, paperType))
                .size() > 0;
        if (!dimensionExist) {
            return false;
        }
        // 检验结构数据存在
        boolean structExist = gradePaperStructService.list(new QueryWrapper<GradePaperStruct>().lambda()
                        .eq(GradePaperStruct::getSchoolId, schoolId)
                        .eq(GradePaperStruct::getExamId, examId)
                        .eq(GradePaperStruct::getPaperNumber, paperNumber)
                        .eq(GradePaperStruct::getPaperType, paperType))
                .size() > 0;
        if (!structExist) {
            return false;
        }
        // 检验试卷基础分析数据存在
        boolean paperExist = gradePaperService.list(new QueryWrapper<GradePaper>()
                        .lambda()
                        .eq(GradePaper::getSchoolId, schoolId)
                        .eq(GradePaper::getExamId, examId)
                        .eq(GradePaper::getPaperNumber, paperNumber)
                        .eq(GradePaper::getPaperType, paperType))
                .size() > 0;
        if (!paperExist) {
            return false;
        }
        // 精熟度定义数据存在
        boolean moduleDefineExist = gradeModuleDefineService.list(new QueryWrapper<GradeModuleDefine>()
                        .lambda()
                        .eq(GradeModuleDefine::getSchoolId, schoolId)
                        .eq(GradeModuleDefine::getExamId, examId)
                        .eq(GradeModuleDefine::getPaperNumber, paperNumber)
                        .eq(GradeModuleDefine::getPaperType, paperType))
                .size() > 0;
        if (!moduleDefineExist) {
            return false;
        }

        // 模块评价数据存在
        return gradeModuleEvaluationService.list(new QueryWrapper<GradeModuleEvaluation>()
                        .lambda()
                        .eq(GradeModuleEvaluation::getSchoolId, schoolId)
                        .eq(GradeModuleEvaluation::getExamId, examId)
                        .eq(GradeModuleEvaluation::getPaperNumber, paperNumber)
                        .eq(GradeModuleEvaluation::getPaperType, paperType))
                .size() > 0;
    }

    @Override
    public List<DictionaryResult> findTeachCollegeList(Long schoolId, Long examId) {
        QueryWrapper<ExamTask> examTaskQueryWrapper = new QueryWrapper<>();
        examTaskQueryWrapper.lambda().eq(ExamTask::getSchoolId, schoolId);
        if (SystemConstant.longNotNull(examId)) {
            examTaskQueryWrapper.lambda().eq(ExamTask::getExamId, examId);
        }
        // 命题任务教研室id集合
        List<Long> teachingRoomIdList = examTaskService.list(examTaskQueryWrapper)
                .stream()
                .map(ExamTask::getTeachingRoomId)
                .distinct()
                .collect(Collectors.toList());

        List<SysOrg> teachOrgList = new ArrayList<>();
        Map<Long, Long> keyMap = new HashMap<>();
        for (Long orgId : teachingRoomIdList) {
            SysOrg sysOrg = sysOrgService.findCollegeLevelOrgByOrgId(orgId);
            if (Objects.isNull(sysOrg)){
                continue;
            }
            Long id = sysOrg.getId();
            if (!keyMap.containsKey(id)) {
                teachOrgList.add(sysOrg);
                keyMap.put(id, id);
            }
        }

        return teachOrgList.stream().flatMap(e -> {
            DictionaryResult dictionaryResult = new DictionaryResult();
            dictionaryResult.setName(e.getName());
            dictionaryResult.setId(e.getId());
            return Stream.of(dictionaryResult);
        }).collect(Collectors.toList());
    }
}