package com.rongwei.training.controller;

import cn.hutool.core.util.RandomUtil;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.utils.StringUtils;
import com.rongwei.training.domain.*;
import com.rongwei.training.vo.PlanPaperVo;
import com.rongwei.training.vo.SubjectVo;
import com.rongwei.trainingcommon.sys.dao.SubjectDao;
import com.rongwei.trainingcommon.sys.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("paper")
@Slf4j
public class PlanPaperController {
    @Autowired
    private PlanPaperService planPaperService;
    @Autowired
    private ExamPaperService examPaperService;
    @Autowired
    private PaperSubjectAssignService paperSubjectAssignService;
    @Autowired
    private PaperSubjectAutoService paperSubjectAutoService;
    @Autowired
    private SubjectService subjectService;
    @Autowired
    private SubjectOptionsService subjectOptionsService;
    @Autowired
    private SubjectDao subjectDao;

    @GetMapping("/getPaperDetail/{id}")
    public R info(@PathVariable("id") String id) throws InvocationTargetException, IllegalAccessException {
        PlanPaperVo paper = new PlanPaperVo();
        // 查出试卷信息以及对应的题目信息
        PlanPaperDo planPaperDo = planPaperService.getById(id);
        Map<String, Object> paperDetailQueryMap = new HashMap<>();
        paperDetailQueryMap.put("paperid", planPaperDo.getPaperid());
        paperDetailQueryMap.put("deleted", "0");
        List<PaperSubjectAutoDo> paperSubjectAutoList = (List<PaperSubjectAutoDo>) paperSubjectAutoService.listByMap(paperDetailQueryMap);
        List<PaperSubjectAssignDo> paperSubjectAssignList = (List<PaperSubjectAssignDo>) paperSubjectAssignService.listByMap(paperDetailQueryMap);
        // 获取到对应题目id列表
        List<String> subjectIds = new ArrayList<>();
        // 分数映射
        Map<String, Integer> scoreMap = new HashMap<>();
        // 遍历固定题目
        List<SubjectDo> subjects = new ArrayList<>();
        paperSubjectAssignList.forEach(row -> {
            subjectIds.add(row.getSubjectid());
            scoreMap.put(row.getSubjectid(), row.getTotalscore());
        });
        if (subjectIds.size() > 0) {
            List<SubjectDo> tempSubjects = (List<SubjectDo>) subjectService.listByIds(subjectIds);
            subjects.addAll(tempSubjects);
        }
        // 遍历动态题目
        for (PaperSubjectAutoDo row : paperSubjectAutoList) {
            log.info("获取随机题目信息: {}", row);
            String courseId = row.getCoursethemeid();
            // 根据课程主题和题目类型获取 所有的题目
            List<SubjectDo> tempSubjectList = subjectDao.getSubjectByCourseId(courseId, row.getSubjecttype());
            // 需要随机取该课程的多少题
            int tempNum = row.getThemesubjectnum();
            if (getRandomSubject(scoreMap, subjects, row, tempSubjectList, tempNum)) {
                return R.errorWithMsg("课程" + row.getCoursethemename() + "没有足够的题目");
            }
        }

        log.info("题目获取结束");
        // 获取题目的选项
        List<SubjectVo> paperSubjects = new ArrayList<>();
        log.info("本次生成的题目信息：{}", subjects);
        subjects.forEach(row -> {
            List<SubjectOptionsDo> options = subjectOptionsService.getOptionsBySubjectId(row.getId());
            // 筛选出选项编号不为空的答案信息
            options = options.stream().filter(subjectOptionsDo -> StringUtils.isNotBlank(subjectOptionsDo.getOptionscode())).collect(Collectors.toList());
            log.info("获取到的答案信息:{}", options);
            // 按A、B、C、D排序
            Collections.sort(options, new Comparator<SubjectOptionsDo>() {
                @Override
                public int compare(SubjectOptionsDo o1, SubjectOptionsDo o2) {
                    return o1.getOptionscode().compareTo(o2.getOptionscode());
                }
            });
            SubjectVo subjectVo = new SubjectVo();
            try {
                BeanUtils.copyProperties(subjectVo, row);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            log.info("题目:{}所对应的分数:{}", row.getSubjectname(), scoreMap.get(subjectVo.getId()));
            // 设置每题分数
            subjectVo.setSubjectScore(scoreMap.get(subjectVo.getId()));
            subjectVo.setOptions(options);
            paperSubjects.add(subjectVo);
        });
        PlanPaperVo planPaperVo = new PlanPaperVo();
        BeanUtils.copyProperties(planPaperVo, planPaperDo);
        // 单选
        List<SubjectVo> sSubjectList = new ArrayList<>();
        // 多选
        List<SubjectVo> mSubjectList = new ArrayList<>();
        // 判断
        List<SubjectVo> jSubjectList = new ArrayList<>();
        paperSubjects.stream().collect(Collectors.groupingBy(SubjectVo::getSubjecttype, Collectors.toList())).forEach((typeName, vo) -> {
            if ("10".equals(typeName)) {
                sSubjectList.addAll(vo);
            } else if ("20".equals(typeName)) {
                mSubjectList.addAll(vo);
            } else if ("30".equals(typeName)) {
                jSubjectList.addAll(vo);
            }
        });
        List<SubjectVo> paperSubjectList = new ArrayList<>();
        paperSubjectList.addAll(sSubjectList);
        paperSubjectList.addAll(mSubjectList);
        paperSubjectList.addAll(jSubjectList);
        planPaperVo.setSubjects(paperSubjectList);
        ExamPaperDo examPaperDo = examPaperService.getById(planPaperVo.getPaperid());
        planPaperVo.setPassinggrade(examPaperDo.getPassinggrade());
        planPaperVo.setExaminationtime(examPaperDo.getExaminationtime());
        return R.ok(planPaperVo);
    }

    /**
     * 获取随机题目
     *
     * @param scoreMap        分数考题ID映射
     * @param subjects        已取出的题目
     * @param row             试卷考题表
     * @param tempSubjectList 当前课程主题下某一题目类型的所有题目
     * @param tempNum         需要取出的考题数
     * @return
     */
    private boolean getRandomSubject(Map<String, Integer> scoreMap, List<SubjectDo> subjects, PaperSubjectAutoDo row,
                                     List<SubjectDo> tempSubjectList, int tempNum) {
        log.info("本次需要从课程:{}中获取随机题目:{},题库中共有：{}", row.getCoursethemename(), tempNum, tempSubjectList.size());
        if (tempNum > tempSubjectList.size() || tempSubjectList.isEmpty()) {
            log.error("题目数不够");
            return true;
        } else {
            // 本次取出的题目
            List<SubjectDo> takeOutSubjectList = RandomUtil.randomEleList(tempSubjectList, tempNum);
            log.info("本次取出的随机题目:{}题,题目信息: {}", takeOutSubjectList.size(), takeOutSubjectList);
            // 从本次取出的题目中筛选出 之前已选中的题目
            List<SubjectDo> repeatTakeOutSubjectList = takeOutSubjectList.stream()
                    .filter(takeOutSubject -> subjects.stream()
                            .filter(subject -> subject.getSubjecttype().equals(row.getSubjecttype()))
                            .anyMatch(subjectDo -> takeOutSubject.getSubjectname().equals(subjectDo.getSubjectname())))
                    .collect(Collectors.toList());
            log.info("已重复的题目数: {},题目信息：{}", repeatTakeOutSubjectList.size(), repeatTakeOutSubjectList);
            // 将重复的题目从本次取出的题目中删除
            takeOutSubjectList.removeIf(takeOutSubject -> repeatTakeOutSubjectList.stream()
                    .anyMatch(repetitionSubject -> repetitionSubject.getId().equals(takeOutSubject.getId())));
            // 保存题目
            takeOutSubjectList.forEach(row2 -> {
                log.info("保存题目信息: {}", row2);
                scoreMap.put(row2.getId(), row.getSubjectscore());
                subjects.add(row2);
            });
            // 当重复的题目不为空时
            if (!repeatTakeOutSubjectList.isEmpty()) {
                log.info("题目重复重新获取随机题目");
                // 从当前题库对象中删除 已存在的题目
                tempSubjectList.removeIf(takeOutSubject -> repeatTakeOutSubjectList.stream()
                        .anyMatch(repetitionSubject -> repetitionSubject.getId().equals(takeOutSubject.getId())));
                return this.getRandomSubject(scoreMap, subjects, row, tempSubjectList, repeatTakeOutSubjectList.size());
            }
            return false;
        }
    }
}
