package com.xhkjedu.sexam.service.exam;

import com.xhkjedu.sexam.mapper.exam.*;
import com.xhkjedu.sexam.mapper.paper.EPaperMapper;
import com.xhkjedu.sexam.mapper.paper.EPaperQtypeQuestionMapper;
import com.xhkjedu.sexam.mapper.paperstudent.EPaperStudentMapper;
import com.xhkjedu.sexam.mapper.paperstudent.EPaperStudentQuestionMapper;
import com.xhkjedu.sexam.mapper.system.UserMapper;
import com.xhkjedu.sexam.model.exam.*;
import com.xhkjedu.sexam.model.paper.EPaper;
import com.xhkjedu.sexam.model.paper.EPaperQtypeQuestion;
import com.xhkjedu.sexam.model.paperstudent.EPaperStudent;
import com.xhkjedu.sexam.model.paperstudent.EPaperStudentQuestion;
import com.xhkjedu.sexam.service.report.EReportGenerateService;
import com.xhkjedu.sexam.utils.ExamUtil;
import com.xhkjedu.sexam.vo.exam.EBaseVo;
import com.xhkjedu.utils.N_Utils;
import com.xhkjedu.vo.ResultVo;
import com.xhkjedu.vo.system.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

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

@Service
@Slf4j
public class EBaseService {
    @Resource
    private EBaseMapper eBaseMapper;
    @Resource
    private EClassMapper eClassMapper;
    @Resource
    private EClassStudentMapper eClassStudentMapper;
    @Resource
    private ESubjectMapper eSubjectMapper;
    @Resource
    private EPaperMapper ePaperMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private EPaperStudentMapper ePaperStudentMapper;
    @Resource
    private EBaseMacMapper eBaseMacMapper;
    @Resource
    private EPaperQtypeQuestionMapper ePaperQtypeQuestionMapper;
    @Resource
    private EPaperStudentQuestionMapper ePaperStudentQuestionMapper;
    @Resource
    private EReportGenerateService eReportGenerateService;

    /**
     * 发起考试
     *
     * @return com.xhkjedu.vo.ResultVo
     * @Param [model]
     * @Author ywx
     * @Date 2022/7/18 10:37
     **/
    @Transactional(rollbackFor = Exception.class)
    public ResultVo save(EBase model) {
        ResultVo vo = null;
        try {
            //考试
            model.setExamstate(0);
            model.setTeashowrank(0);
            model.setStushowrank(0);
            model.setDeleted(1);
            model.setReportstate(0);
            model.setStuzero(1);//0分学生是否参与统计0不统计1统计
            model.setCreatetime(N_Utils.getSecondTimestamp());

            //考试关联班级，获取班级关联学校
            List<Integer> classids = model.getClassids();
            String strclassid = classids.stream().map(c->String.valueOf(c)).collect(Collectors.joining(","));
            List<Integer> schoolids = eClassMapper.listSchoolidByClassids(strclassid);
            if(schoolids.size() == 1 && schoolids.get(0).equals(model.getSchoolid())){
                model.setHashb(0);
            }else{
                model.setHashb(1);
            }

            int year=eBaseMapper.getYearByUserid(model.getCreateid());
            model.setYear(year);
            eBaseMapper.insertUseGeneratedKeys(model);
            Integer examid = model.getId();

            vo = saveExam(model, examid);//保存考试基本信息
            if (vo != null) throw new Exception(vo.getMsg());

            return new ResultVo(0, "保存成功", examid);
        } catch (Exception e) {
            log.error("发起考试失败："+e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            if(vo !=null ){
                return vo;
            }else{
                return new ResultVo(1, "保存失败");
            }
        }
    }

    //保存考试基本信息
    private ResultVo saveExam(EBase model, Integer examid) {
        List<Integer> classids = model.getClassids();
        if(model.getExammode() == 2) {//线下考试必须有考号
            Integer num = eClassStudentMapper.getNoExamNoNumByClassIds(classids);//根据班级ids获取没有考号学生数量
            if (num != 0) return new ResultVo(1, "有学生未设置考号，请先设置");
            //验证选择学校的准考证号长度是否一致；获取参加考试的学校所有学生考号长度
            List<Integer> schoolExamNo = eClassStudentMapper.listSchoolExamNoLength(classids);
            if(N_Utils.isListNotEmpty(schoolExamNo) && schoolExamNo.size() > 1){
                return new ResultVo(1, "选择考试班级学生考号长度不一致");
            }

        }
        List<EClassStudent> students = eClassStudentMapper.listByClassIds(classids);
        int stuNum = students.stream().distinct().collect(Collectors.toList()).size();
        if (stuNum < students.size()) return new ResultVo(1, "有重复学生，请重新选择");

        //考试班级
        List<EClass> classes = eClassMapper.listByClassIds(classids);
        classes.forEach(c -> c.setExamid(examid));
        eClassMapper.insertList(classes);

        //考试学生
        students.forEach(s -> s.setExamid(examid));
        students = students.stream().filter(s -> !N_Utils.isEmptyInteger(s.getStudentid())).collect(Collectors.toList());
        if(N_Utils.isListNotEmpty(students)) eClassStudentMapper.insertList(students);

        //考试科目
        List<ESubject> subjects = model.getSubjects();//考试科目
        List<EPaper> papers = new ArrayList<>();//考试试卷
        for (ESubject s : subjects) {
            s.setExamid(examid);
            s.setEsstate(0);
            EPaper p = new EPaper();
            p.setExamid(examid);
            p.setSubjectid(s.getSubjectid());
            p.setPtype(0);
            p.setPnum(0);
            p.setPscore(0.0);
            p.setAnswered(0);
            p.setCorrecttype(0);
            p.setScantronnum(0);
            p.setScantronspace(0);
            p.setScantroncol(0);
            p.setCodenum(0);
            p.setHearnum(0);
            papers.add(p);
        }
        eSubjectMapper.insertList(subjects);//考试科目

        Integer createid = model.getCreateid();
        Integer createtime = model.getCreatetime();
        for (int i = 0; i < papers.size(); i++) {
            EPaper ePaper = papers.get(i);
            ePaper.setEsid(subjects.get(i).getId());
            ePaper.setCreateid(createid);
            ePaper.setCreatetime(createtime);
        }
        ePaperMapper.insertList(papers);//考试试卷

        return null;
    }

    //删除
    public Integer deleteById(Integer id) {
        return eBaseMapper.deleteById(id);
    }

    //修改
    @Transactional(rollbackFor = Exception.class)
    public ResultVo update(EBase model) {
        try {
            EBaseVo exam = eBaseMapper.getExamStateById(model.getExamid());
            if (0 != exam.getExamstate()) return new ResultVo(1, "考试已发布禁止操作");
            Long timestamp = Long.valueOf(N_Utils.getSecondTimestamp() + 30 * 60);
            Long begintime = ExamUtil.strToTimestamp(exam.getStrtime());
            if (begintime != 0 && begintime.compareTo(timestamp) != 1) return new ResultVo(1, "开考前30分钟禁止编辑");
            //2022/11/15 禁止修改年级、科目、考试模式
            model.setGradeid(null);
            model.setExammode(null);
            eBaseMapper.updateByPrimaryKeySelective(model);

            Integer examid = model.getExamid();
            List<Integer> classids = model.getClassids();
            //班级集合为空不处理班级
            if (N_Utils.isListEmpty(classids)) return new ResultVo(0, "修改成功");
            eBaseMapper.deleteClassById(examid);//删除关联的班级
            if(exam.getExammode() == 2) {//线下考试必须有考号
                Integer num = eClassStudentMapper.getNoExamNoNumByClassIds(classids);//根据班级ids获取没有考号学生数量
                if (num != 0) return new ResultVo(1, "有学生没有考号");
            }
            List<EClassStudent> students = eClassStudentMapper.listByClassIds(classids);
            int stuNum = students.stream().distinct().collect(Collectors.toList()).size();
            if (stuNum < students.size()) return new ResultVo(1, "有重复学生");

            //考试班级
            List<EClass> classes = eClassMapper.listByClassIds(classids);
            classes.forEach(c -> c.setExamid(examid));
            eClassMapper.insertList(classes);

            //考试学生
            students.forEach(s -> s.setExamid(examid));
            students = students.stream().filter(s -> !N_Utils.isEmptyInteger(s.getStudentid())).collect(Collectors.toList());
            if(N_Utils.isListNotEmpty(students)) eClassStudentMapper.insertList(students);

            return new ResultVo(0, "修改成功");
        } catch (Exception e) {
            log.error("修改考试失败", e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new ResultVo(1, "修改失败");
        }
    }

    //获取详情
    public Map findById(Integer id) {
        Map map = eBaseMapper.findById(id);//考试基本信息(带考试人数)
        List<Map> subjects = eSubjectMapper.listSubjectSet(id);//考试科目设置列表
        map.put("subjects", subjects);
        List<Map> classes = eClassMapper.listByExamId(id);
        map.put("classes", classes);
        map.put("examnum", classes.stream().mapToInt(m-> (int) m.get("classnum")).sum());
        return map;
    }

    //获取列表
    public List<Map> listAll(EBase base) {
        return eBaseMapper.listAll(base);
    }

    //考试设置
    public void setExam(List<ESubject> subjects, Integer handleid) {
        int timestamp = N_Utils.getSecondTimestamp();
        eSubjectMapper.setExam(subjects, handleid, timestamp);
    }

    //发布考试
    public Integer updateExamStateStart(Integer examid, String examcomm, List<UserVo> students,Integer exammode,Integer schoolid) {
        try {
            //发布考试，获取考试试卷题量和分值
            List<EPaper> papers = ePaperMapper.listNumAndScoreByExamId(examid);
            for (EPaper paper : papers) {
                //如果考试已经发布，更改学生提交指定试题为需要批改状态
                new Thread(()->{
                    try {
                        savePaperStudent(paper,students);
                    }catch (Exception e){
                        log.error("保存学生试题重试：" + e.getMessage());
                        try {
                            savePaperStudent(paper,students);
                        }catch (Exception se){
                            log.error("保存学生试题重试出错：" + se.getMessage());
                        }
                    }
                }).start();
            }
            //更改考试状态
            eBaseMapper.postExam(examid, examcomm);
        } catch (Exception e) {
            log.error("发布考试失败："+e.getMessage());
            return 1;
        }
        return 0;
    }

    //保存学生试题
    @Transactional(rollbackFor = Exception.class)
    public void savePaperStudent(EPaper paper,List<UserVo> students){
        int timestamp = N_Utils.getSecondTimestamp();
        try {
            List<EPaperStudent> studentList = new ArrayList<>();
            Integer examid = paper.getExamid();
            Integer esid = paper.getEsid();
            Integer epid = paper.getEpid();
            Integer pnum = paper.getPnum();
            Double pscore = paper.getPscore();
            String subjectid = paper.getSubjectid();
            for (UserVo student : students) {
                EPaperStudent es = new EPaperStudent();
                es.setExamid(examid);
                es.setEsid(esid);
                es.setEpid(epid);
                es.setSubjectid(subjectid);
                es.setClassid(student.getClassid());
                es.setStudentid(student.getUserid());
                es.setSstate(0);
                es.setChecked(0);
                es.setNum(pnum);
                es.setScore(pscore);
                es.setStuscore(0.0);
                es.setCosttime(0);
                es.setCreatetime(timestamp);
                es.setHasbad(0);
                studentList.add(es);
            }
            ePaperStudentMapper.insertList(studentList);//保存考试学生信息

            //获取试卷中所有试题
            List<EPaperQtypeQuestion> queslist = ePaperQtypeQuestionMapper.listQuestionsByEpid(epid);
            //获取该还是卷下试题学生信息
            for (EPaperQtypeQuestion q : queslist) {
                Integer eptqid = q.getEptqid();
                Integer ctype = q.getCtype();
                String questionid = q.getQuestionid();
                String qn = q.getQn();
                Integer qorder = q.getQorder();
                Double score = q.getScore();
                List<EPaperStudentQuestion> stuqlist = new ArrayList<>();
                for (EPaperStudent ps : studentList) {
                    EPaperStudentQuestion epsq = new EPaperStudentQuestion();
                    epsq.setClassid(ps.getClassid());
                    epsq.setStudentid(ps.getStudentid());
                    epsq.setExamid(ps.getExamid());
                    epsq.setSubjectid(ps.getSubjectid());
                    epsq.setEpid(epid);
                    epsq.setEpsid(ps.getId());
                    epsq.setEptqid(eptqid);
                    epsq.setCtype(ctype);
                    epsq.setQuestionid(questionid);
                    epsq.setQn(qn);
                    epsq.setQorder(qorder);
                    epsq.setAnswered(0);
                    epsq.setAnswertype(0);
                    epsq.setConverted(0);
                    epsq.setCosttime(0);
                    epsq.setQscore(score);
                    epsq.setStuscore(0.0);
                    epsq.setChecked(0);
                    epsq.setGood(0);
                    epsq.setBad(0);
                    epsq.setNeeddeal(0);
                    stuqlist.add(epsq);
                }
                ePaperStudentQuestionMapper.insertList(stuqlist);
            }
        } catch (Exception e) {
            log.error("保存学生试题失败：" + e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException("保存学生试题失败");
        }
    }

    //结束考试
    @Transactional(rollbackFor = Exception.class)
    public void updateExamStateEnd(EBase eBase) throws Exception {
        try {
            ePaperStudentMapper.updateStuscoreByExamId(eBase.getExamid());//更新未已提交未批阅完成学生得分
            eBaseMapper.updateExamState(eBase.getExamid(),2);
            if (2 == eBase.getExammode()) {//线下考试修改科目试卷状态
                eSubjectMapper.updatePstate(eBase.getExamid());
            }
//            eBaseMapper.updateExamStateAndReportState(eBase.getExamid(),2);
            //结束考试时自动生成报告pdf，调用mq
        } catch (Exception e) {
            log.error("结束考试失败", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException(e.getMessage());
        }
    }

    //获取考试班级
    public List<Map> listClass(Integer examid) {
        List<Map> classes = eClassMapper.listByExamId(examid);
        return classes;
    }

    //获取考试和班级信息
    public Map getExamAndClass(Integer examid) {
        Map map = eBaseMapper.findById2(examid);
        Integer schoolid = Integer.parseInt(map.get("schoolid").toString());
        List<Map> schools = eClassMapper.listSchoolClassByExamid(schoolid,examid);
        map.put("schools", schools);
        return map;
    }

    //考试学生
    public List<Map> listStu(EClassStudent cs) {
        List<Map> students = eClassStudentMapper.listByExamId(cs);
        Integer examid = cs.getExamid();
        List<Map> classes = eClassMapper.listByExamId(examid);
        Map<Object, Object> classMap = classes.stream().collect(Collectors.toMap(m -> m.get("classid"), m -> m.get("classname")));
        students.forEach(s -> s.put("classname", classMap.get(s.get("classid"))));
        return students;
    }

    //移除考试学生
    @Transactional(rollbackFor = Exception.class)
    public ResultVo delStu(Integer ecsid) {
        EClassStudent student = eClassStudentMapper.selectByPrimaryKey(ecsid);
        EBaseVo exam = eBaseMapper.getExamStateById(student.getExamid());
        if (0 != exam.getExamstate()) return new ResultVo(1, "考试已发布禁止操作");
        Long timestamp = Long.valueOf(N_Utils.getSecondTimestamp() + 30 * 60);
        Long begintime = ExamUtil.strToTimestamp(exam.getStrtime());
        if (begintime != 0 && begintime.compareTo(timestamp) != 1) return new ResultVo(1, "开考前30分钟禁止移除学生");
        eClassStudentMapper.deleteByPrimaryKey(ecsid);
        eClassMapper.updateClassNumByCsId(student.getExamid(), student.getClassid());
        return new ResultVo(0, "移除考试学生成功");
    }

    //考试科目列表
    public Map listSubject(Integer examid) {
        Map map = eBaseMapper.findById(examid);
        List<Map> subjects = eSubjectMapper.listSubject(examid);
        map.put("subjects", subjects);
        return map;
    }

    //根据考试id获取名称
    public String getNameByExamId(Integer examid) {
        return eBaseMapper.getNameByExamId(examid);
    }

    //获取考生
    public List<UserVo> listStuByExamId(Integer examid) {
        return userMapper.listStuByExamId(examid);
    }

    //根据考试id获取考试状态
    public EBaseVo getExamStateById(Integer examid) {
        return eBaseMapper.getExamStateById(examid);
    }

    //获取未完成的考试试卷数量
    public Integer countNoCompletePaper(Integer examid) {
        return eSubjectMapper.countNoCompletePaper(examid);
    }

    public List<UserVo> listTeacherByClassIds(String classids) {
        return userMapper.listTeacherByClassIds(classids);
    }

    //设置出卷人
    public void setSubjectTeacher(ESubject subject) {
        eSubjectMapper.updateByPrimaryKeySelective(subject);
    }

    //考试设置状态
    public Map getSetState(Integer examid) {
        return eBaseMapper.getSetState(examid);
    }

    //保存发布信息
    public void savePostExam(Integer examid, String examcomm) {
        EBase b = new EBase();
        b.setExamid(examid);
        b.setExamcomm(examcomm);
        eBaseMapper.updateByPrimaryKeySelective(b);
    }

    //获取mac编号
    public String getMacNumber(String mac) {
        String macCode = "PC-";
        Integer ebmid = eBaseMacMapper.getIdByMac(mac);//根据mac获取主键
        if (ebmid == null) {
            EBaseMac bm = new EBaseMac();
            bm.setMac(mac);
            eBaseMacMapper.insertUseGeneratedKeys(bm);
            ebmid = bm.getId();
        }
        return macCode + ebmid;
    }

    //考试科目选择列表
    public List<Map> listSubjectForSel(Integer examid) {
        return eSubjectMapper.listSubjectForSel(examid);
    }

    //根据考试id获取考试状态
    public Integer getExamState(Integer examid) {
        return eBaseMapper.getExamState(examid);
    }

    //根据考试科目id获取考试状态
    public Integer getExamStateByEsId(Integer esid) {
        return eBaseMapper.getExamStateByEsId(esid);
    }

    //班级选择列表
    public List<Map> listBj(Integer schoolid, Integer teacherid) {
        return eClassMapper.listBj(schoolid, teacherid);
    }

    //获取考试状态和是否设置答案
    public EBaseVo getExamStateAnseredById(Integer examid) {
        return eBaseMapper.getExamStateAnseredById(examid);
    }

    //生成报告
    public void generateExamReport(Integer examid,Integer createid) throws Exception{
        ePaperStudentMapper.updateStuscoreByExamId(examid);//更新未已提交未批阅完成学生得分
        eReportGenerateService.generateExamReport(examid, createid);
        //生成网页报告后生成pdf报告,发送mq
//        eBaseMapper.updateExamReportState(examid,1);
    }

    //修改生成的报告pdf地址
    @Transactional(rollbackFor = Exception.class)
    public void updateExamReportstate(Map map){
        Integer converted = Integer.parseInt(map.get("converted").toString());
        Integer examid = Integer.parseInt(map.get("examid").toString());
        String reportschool = "";
        if(converted == 2){
            reportschool = map.get("reportschool").toString();
            //更改班级报告、学生报告
        }
        eBaseMapper.updateExamReportSchoolState(examid,converted,reportschool);
    }

    //更加用户id获取用户类型
    public Integer getUsertypeByUserid(Integer userid){
        return userMapper.getUsertypeByUserid(userid);
    }

    //考试未批阅试题数量
    public Integer getNoCheckNum(Integer examid) {
        return eBaseMapper.getNoCheckNum(examid);
    }

    //根据考试id获取状态和模式
    public EBaseVo getExamStateAndMode(Integer examid) {
        return eBaseMapper.getExamStateAndMode(examid);
    }

    //缺考详情
    public List<Map> listQkDetail(Integer epid,Integer schoolid) {
        List<Map> list = ePaperStudentMapper.listQkDetail(epid,schoolid);
        for (Map c : list) {
            List<Map> students=new ArrayList<>();
            String userids = c.get("userids").toString();
            if(N_Utils.isNotEmpty(userids)) students = userMapper.listByUserIds(userids);
            c.put("students", students);
            c.remove("userids");
        }
        return list;
    }

    //设置学生报告排名显示
    public void setShowRank(EBase eBase) {
        if (eBase.getTeashowrank() == null) eBase.setTeashowrank(0);
        if (eBase.getStushowrank() == null) eBase.setStushowrank(0);
        if (eBase.getStuzero() == null) eBase.setStuzero(1);
        eBaseMapper.updateByPrimaryKeySelective(eBase);

        new Thread(() -> {
            Integer examid = eBase.getExamid();
            EBase eb = eBaseMapper.getShowRankById(examid);
            //如果考试显示排名得分有变动重新生成pdf报告
            if (!eBase.getStushowrank().equals(eb.getStushowrank()) || !eBase.getTeashowrank().equals(eb.getTeashowrank())) {
                eReportGenerateService.htmlToPdf(examid);//考试报告html转pdf
            }
        }).start();
    }

    //根据考试id获取pdf报告状态
    public Integer getReportState(Integer examid) {
        return eBaseMapper.getReportState(examid);
    }


    /*
     * @Description 获取考试关联学校
     * @Date 2023/8/29 14:17:29
     * @Author WN
     * @Param [examid]
     * @Return java.util.List<java.util.Map>
     **/
    public List<Map> listSchoolsByExamid(Integer examid) {
        //获取考试信息
        Integer schoolid = eBaseMapper.getSchoolidByExamid(examid);
        return eClassMapper.listSchoolsByExamid(schoolid,examid);
    }
}
