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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qmth.distributed.print.business.bean.dto.open.*;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicSchool;
import com.qmth.teachcloud.common.entity.MarkQuestion;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
import com.qmth.teachcloud.mark.dto.mark.ScoreItem;
import com.qmth.teachcloud.mark.entity.MarkPaper;
import com.qmth.teachcloud.mark.entity.MarkStudent;
import com.qmth.teachcloud.mark.service.MarkPaperService;
import com.qmth.teachcloud.mark.service.MarkQuestionService;
import com.qmth.teachcloud.mark.service.MarkStudentService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class OpenApiServiceImpl implements OpenApiService {

    @Resource
    private GradeBatchPaperService gradeBatchPaperService;

    @Resource
    private GradePaperService gradePaperService;

    @Resource
    private GradePaperDimensionService gradePaperDimensionService;

    @Resource
    private GradePaperStructService gradePaperStructService;

    @Resource
    private GradeModuleDefineService gradeModuleDefineService;

    @Resource
    private GradeModuleEvaluationService gradeModuleEvaluationService;

    @Resource
    ExamTaskService examTaskService;

    @Resource
    private TSyncExamStudentScoreService tSyncExamStudentScoreService;

    @Resource
    private GradeBatchStudentClazzService gradeBatchStudentClazzService;

    @Resource
    private GradeBatchService gradeBatchService;

    @Resource
    private MarkPaperService markPaperService;

    @Resource
    private MarkStudentService markStudentService;

    @Resource
    private MarkQuestionService markQuestionService;

    @Override
    public PaperConfig getPaperConfig(BasicSchool basicSchool, String thirdExamId, String gradeCourseCode) {
        GradeBatchPaper gradeBatchPaper = gradeBatchPaperService.findByThirdExamIdAndGradeCourseCode(basicSchool.getId(), thirdExamId, gradeCourseCode);
        if (gradeBatchPaper == null) {
            return null;
        }
        Long examId = null;
        GradeBatch gradeBatch = gradeBatchService.getOne(
                new QueryWrapper<GradeBatch>().lambda().eq(GradeBatch::getThirdExamId, thirdExamId));
        if (Objects.nonNull(gradeBatch)) {
            examId = gradeBatch.getExamId();
        }
        return gradePaperService.findBySchoolIdAndPaperNumberAndPaperType(gradeBatchPaper.getSchoolId(), examId,
                gradeBatchPaper.getPaperNumber(), gradeBatchPaper.getPaperType());
    }

    @Override
    public List<PaperDimension> getPaperDimension(BasicSchool basicSchool, String thirdExamId, String gradeCourseCode) {
        GradeBatchPaper gradeBatchPaper = gradeBatchPaperService.findByThirdExamIdAndGradeCourseCode(basicSchool.getId(), thirdExamId, gradeCourseCode);
        if (gradeBatchPaper == null) {
            return new ArrayList<>();
        }
        return gradePaperDimensionService.findBySchoolIdAndPaperNumberAndPaperType(gradeBatchPaper.getSchoolId(),
                gradeBatchPaper.getExamId(), gradeBatchPaper.getPaperNumber(), gradeBatchPaper.getPaperType());
    }

    @Override
    public List<PaperStructure> getPaperStructure(BasicSchool basicSchool, String thirdExamId, String gradeCourseCode) {
        GradeBatchPaper gradeBatchPaper = gradeBatchPaperService.findByThirdExamIdAndGradeCourseCode(basicSchool.getId(), thirdExamId, gradeCourseCode);
        if (gradeBatchPaper == null) {
            return new ArrayList<>();
        }
        return gradePaperStructService.findBySchoolIdAndPaperNumberAndPaperType(gradeBatchPaper.getSchoolId(),
                gradeBatchPaper.getExamId(), gradeBatchPaper.getPaperNumber(), gradeBatchPaper.getPaperType());
    }

    @Override
    public List<PaperEvaluation> getPaperEvaluation(BasicSchool basicSchool, String thirdExamId, String gradeCourseCode) {
        List<PaperEvaluation> paperEvaluations = new ArrayList<>();
        GradeBatchPaper gradeBatchPaper = gradeBatchPaperService.findByThirdExamIdAndGradeCourseCode(basicSchool.getId(), thirdExamId, gradeCourseCode);
        if (gradeBatchPaper == null) {
            return paperEvaluations;
        }
        Long examId = null;
        GradeBatch gradeBatch = gradeBatchService.getOne(
                new QueryWrapper<GradeBatch>().lambda().eq(GradeBatch::getThirdExamId, thirdExamId));
        if (Objects.nonNull(gradeBatch)) {
            examId = gradeBatch.getExamId();
        }
        List<GradeModuleDefine> gradeModuleDefineList = gradeModuleDefineService.findBySchoolIdAndPaperNumberAndPaperType(
                gradeBatchPaper.getSchoolId(), examId, gradeBatchPaper.getPaperNumber(), gradeBatchPaper.getPaperType());
        List<GradeModuleEvaluation> gradeModuleEvaluationList = gradeModuleEvaluationService.findBySchoolIdAndPaperNumberAndPaperType(
                gradeBatchPaper.getSchoolId(), examId, gradeBatchPaper.getPaperNumber(), gradeBatchPaper.getPaperType());
        // 分组（分隔符_）
        if (!gradeModuleDefineList.isEmpty()) {

            Map<String, List<GradeModuleDefine>> stringListMap = gradeModuleDefineList.stream().collect(Collectors.groupingBy(m -> m.getModuleType() + "_" + m.getInterpret() + "_" + m.getRemark()));
            for (Map.Entry<String, List<GradeModuleDefine>> stringListEntry : stringListMap.entrySet()) {
                String[] key = stringListEntry.getKey().split("_");
                String moduleType = key[0];
                String interpret = key[1];
                String remark = key[2];

                PaperEvaluation paperEvaluation = new PaperEvaluation();
                paperEvaluation.setModuleType(moduleType);
                paperEvaluation.setInterpret(interpret);
                paperEvaluation.setRemark(remark);

                List<PaperEvaluation.SecondaryDimensionLevelDefine> secondaryDimensionLevelDefineArrayList = new ArrayList<>();
                for (GradeModuleDefine gradeModuleDefine : stringListEntry.getValue()) {
                    PaperEvaluation.SecondaryDimensionLevelDefine secondaryDimensionLevelDefine = new PaperEvaluation.SecondaryDimensionLevelDefine();
                    secondaryDimensionLevelDefine.setDefine(gradeModuleDefine.getDefine());
                    secondaryDimensionLevelDefine.setLevel(gradeModuleDefine.getLevel());
                    secondaryDimensionLevelDefine.setMax(gradeModuleDefine.getMax());
                    secondaryDimensionLevelDefine.setMin(gradeModuleDefine.getMin());
                    secondaryDimensionLevelDefine.setScope(gradeModuleDefine.getScope());
                    secondaryDimensionLevelDefineArrayList.add(secondaryDimensionLevelDefine);
                }
                paperEvaluation.setSecondaryDimensionLevelDefineList(secondaryDimensionLevelDefineArrayList);

                if (!gradeModuleEvaluationList.isEmpty()) {
                    GradeModuleEvaluation gradeModuleEvaluation = gradeModuleEvaluationList.stream().filter(m -> moduleType.equals(m.getModuleType().name())).findFirst().orElseGet(null);
                    paperEvaluation.setFormula(
                            gradeModuleEvaluation == null ? null : gradeModuleEvaluation.getFormula().name());

                    List<PaperEvaluation.ModuleEvaluation> moduleEvaluationList = gradeModuleEvaluationList.stream().filter(m -> moduleType.equals(m.getModuleType().name())).map(m -> {
                        PaperEvaluation.ModuleEvaluation moduleEvaluation = new PaperEvaluation.ModuleEvaluation();
                        moduleEvaluation.setAdvice(m.getAdvice());
                        moduleEvaluation.setLevelCode(m.getLevelCode());
                        moduleEvaluation.setLevelName(m.getLevelName());
                        moduleEvaluation.setResult(m.getResult());
                        moduleEvaluation.setScope(m.getScope());
                        return moduleEvaluation;
                    }).collect(Collectors.toList());
                    paperEvaluation.setModuleEvaluationList(moduleEvaluationList);
                }

                paperEvaluations.add(paperEvaluation);
            }
            return paperEvaluations;
        }
        return paperEvaluations;
    }

    @Override
    public List<ExamStudentScore> listExamStudentScore(BasicSchool basicSchool, String thirdExamId, String gradeCourseCode, Integer pageNumber, Integer pageSize) {
        GradeBatchPaper gradeBatchPaper = gradeBatchPaperService.findByThirdExamIdAndGradeCourseCode(basicSchool.getId(), thirdExamId, gradeCourseCode);
        Long examId = gradeBatchPaper.getExamId();
        String paperNumber = gradeBatchPaper.getPaperNumber();
        String paperType = gradeBatchPaper.getPaperType();

        MarkPaper markPaper = markPaperService.getOne(
                new QueryWrapper<MarkPaper>().lambda().eq(MarkPaper::getExamId, examId)
                        .eq(MarkPaper::getPaperNumber, paperNumber).eq(MarkPaper::getPaperType, paperType).last("limit 1"));

        if (Objects.isNull(markPaper)) {
            throw ExceptionResultEnum.ERROR.exception(
                    String.format("考试id为[%s],试卷编号为[%s],试卷类型为[%s]的考试科目不存在", examId, paperNumber, paperType));
        }
        if (!MarkPaperStatus.FINISH.equals(markPaper.getStatus())) {
            throw ExceptionResultEnum.ERROR.exception(
                    String.format("考试id为[%s],试卷编号为[%s],试卷类型为[%s]的考试科目未评卷结束,不能开始分析计算", examId, paperNumber, paperType));
        }
        QueryWrapper<MarkStudent> markStudentQueryWrapper = new QueryWrapper<>();
        markStudentQueryWrapper.lambda().eq(MarkStudent::getExamId, examId).eq(MarkStudent::getPaperNumber, paperNumber)
                .eq(MarkStudent::getPaperType, paperType);

        Page<MarkStudent> page = new Page<>(pageNumber, pageSize);
        IPage<MarkStudent> markStudentIPage = markStudentService.page(page, markStudentQueryWrapper);

        // 任课老师
        QueryWrapper<GradeBatchStudentClazz> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(GradeBatchStudentClazz::getBatchId, gradeBatchPaper.getBatchId());
        List<GradeBatchStudentClazz> gradeBatchStudentClazzList = gradeBatchStudentClazzService.list(queryWrapper);

        // 试卷结构
        // 客观题架构
        List<MarkQuestion> os = markQuestionService.listByExamIdAndPaperNumberAndPaperType(examId, paperNumber,
                paperType, true);
        // 主观题结构
        List<MarkQuestion> ss = markQuestionService.listByExamIdAndPaperNumberAndPaperType(examId, paperNumber,
                paperType, false);

        return markStudentIPage.getRecords().stream().flatMap(e -> {
            ExamStudentScore examStudentScore = new ExamStudentScore();
            examStudentScore.setName(e.getStudentName());
            examStudentScore.setExamNumber(e.getStudentCode());
            examStudentScore.setStudentCode(e.getStudentCode());
            examStudentScore.setPaperNumber(gradeBatchPaper.getPaperNumber());
            examStudentScore.setPaperName(e.getCourseName());
            examStudentScore.setPaperType(paperType);
            examStudentScore.setCollege(e.getCollege());
            examStudentScore.setMajor(SystemConstant.strNotNull(e.getMajorName()) ? e.getMajorName() : "未知专业");
            examStudentScore.setClassName(SystemConstant.strNotNull(e.getClassName()) ? e.getClassName() : "未知班级");

            List<GradeBatchStudentClazz> gradeBatchStudentClasses = gradeBatchStudentClazzList.isEmpty() ?
                    null :
                    gradeBatchStudentClazzList.stream()
                            .filter(s -> s.getClazzName().equals(e.getClassName()) && s.getPaperNumber().equals(examStudentScore.getPaperNumber()) && s.getPaperType()
                                    .equals(examStudentScore.getPaperType())).collect(Collectors.toList());

            GradeBatchStudentClazz gradeBatchStudentClazz = gradeBatchStudentClasses == null || gradeBatchStudentClasses.isEmpty() ?
                    null :
                    gradeBatchStudentClasses.get(0);
            if (gradeBatchStudentClazz == null) {
                throw ExceptionResultEnum.ERROR.exception(
                        String.format("科目[%s]，试卷编号[%s]，班级[%s]未导入任课老师", e.getCourseName(), e.getPaperNumber(), e.getClassName()));
            }

            examStudentScore.setTeacherName(gradeBatchStudentClazz.getTeacherName());
            examStudentScore.setTeacherCode(gradeBatchStudentClazz.getTeacherNumber());
            int status = 1;
            if (e.getAbsent() || e.getManualAbsent() || e.getOmrAbsent()) {
                status = 2;
            } else if (e.getBreach()) {
                status = 3;
            }
            examStudentScore.setStatus(status);
            examStudentScore.setTotalScore(e.getTotalScore());
            examStudentScore.setObjectiveScore(e.getObjectiveScore());
            examStudentScore.setSubjectiveScore(e.getSubjectiveScore());
            // 客观题详情
            List<ScoreItem> objectiveScoreList = e.getScoreList(true, os);
            // 主观题详情
            List<ScoreItem> subjectiveScoreList = e.getScoreList(false, ss);
            List<ExamStudentScore.TopicInfo> objectiveScoreDetail;
            List<ExamStudentScore.TopicInfo> subjectiveScoreDetail;
            if (CollectionUtils.isNotEmpty(objectiveScoreList)) {
                objectiveScoreDetail = objectiveScoreList.stream().flatMap(ol -> {
                    ExamStudentScore.TopicInfo topicInfo = new ExamStudentScore.TopicInfo();
                    topicInfo.setMainNumber(ol.getMainNumber());
                    topicInfo.setSubNumber(String.valueOf(ol.getSubNumber()));
                    topicInfo.setAnswer(ol.getAnswer());
                    topicInfo.setScore(ol.getScoreString());
                    return Stream.of(topicInfo);
                }).collect(Collectors.toList());
                examStudentScore.setObjectiveScoreDetail(objectiveScoreDetail);
            }

            if (CollectionUtils.isNotEmpty(subjectiveScoreList)) {
                subjectiveScoreDetail = subjectiveScoreList.stream().flatMap(sl -> {
                    ExamStudentScore.TopicInfo topicInfo = new ExamStudentScore.TopicInfo();
                    topicInfo.setMainNumber(sl.getMainNumber());
                    topicInfo.setSubNumber(String.valueOf(sl.getSubNumber()));
                    topicInfo.setAnswer(sl.getAnswer());
                    topicInfo.setScore(sl.getScoreString());
                    return Stream.of(topicInfo);
                }).collect(Collectors.toList());
                examStudentScore.setSubjectiveScoreDetail(subjectiveScoreDetail);
            }
            return Stream.of(examStudentScore);
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }
}
