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

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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.distributed.print.business.bean.dto.BasicExamStudentDto;
import com.qmth.distributed.print.business.bean.params.BasicExamStudentParam;
import com.qmth.distributed.print.business.bean.result.BasicExamStudentResult;
import com.qmth.distributed.print.business.mapper.BasicExamStudentMapper;
import com.qmth.distributed.print.business.service.BasicExamService;
import com.qmth.distributed.print.business.service.BasicExamStudentService;
import com.qmth.distributed.print.business.service.BasicTeachClazzService;
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.*;
import com.qmth.teachcloud.common.enums.ExamModelEnum;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.service.BasicCourseService;
import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
import com.qmth.teachcloud.common.service.CommonCacheService;
import com.qmth.teachcloud.common.service.SysUserService;
import com.qmth.teachcloud.common.util.ConvertUtil;
import com.qmth.teachcloud.common.util.ExcelUtil;
import com.qmth.teachcloud.common.util.RegexUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
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.MarkStudentService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 考生字典表 服务实现类
 * </p>
 *
 * @author CaoZixuan
 * @since 2024-02-22
 */
@Service
public class BasicExamStudentServiceImpl extends ServiceImpl<BasicExamStudentMapper, BasicExamStudent> implements BasicExamStudentService {

    @Resource
    private BasicRoleDataPermissionService basicRoleDataPermissionService;
    @Resource
    private BasicCourseService basicCourseService;
    @Resource
    private BasicTeachClazzService basicTeachClazzService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private CommonCacheService commonCacheService;
    @Resource
    private MarkPaperService markPaperService;
    @Resource
    private MarkStudentService markStudentService;
    @Resource
    private BasicExamService basicExamService;

    @Override
    public IPage<BasicExamStudentResult> page(Long semesterId, Long examId, String courseCode,
                                              String teacher, String college, String major, String teachClazz, String examStudentInfo, int pageNumber,
                                              int pageSize) {
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();

        courseCode = SystemConstant.translateSpecificSign(courseCode);
        teacher = SystemConstant.translateSpecificSign(teacher);
        college = SystemConstant.translateSpecificSign(college);
        major = SystemConstant.translateSpecificSign(major);
        examStudentInfo = SystemConstant.translateSpecificSign(examStudentInfo);
        teachClazz = SystemConstant.translateSpecificSign(teachClazz);

        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(requestUser.getSchoolId(), requestUser.getId(),
                ServletUtil.getRequest().getServletPath());
        IPage<BasicExamStudentResult> page = this.baseMapper.findBasicExamStudentPage(new Page<>(pageNumber, pageSize),
                requestUser.getSchoolId(), semesterId, examId, courseCode, teacher, college, major, teachClazz, examStudentInfo, dpr);
        for (BasicExamStudentResult record : page.getRecords()) {
            Long examStartTime = record.getExamStartTime();
            Long examEndTime = record.getExamEndTime();
            if (SystemConstant.longNotNull(examStartTime) && SystemConstant.longNotNull(examEndTime)) {
                Map<String, Object> dateMap = ConvertUtil.analyzeDateAndTime(examStartTime, examEndTime);
                String date = String.valueOf(dateMap.get("date"));
                String time = String.valueOf(dateMap.get("time"));
                record.setExamDate(date);
                record.setExamTime(time);
            }
        }
        return page;
    }

    @Override
    public List<BasicExamStudentResult> list(SysUser requestUser, Long semesterId, Long examId, String courseCode,
                                             String teacher, String college, String major, String teachClazz, String examStudentInfo) {
        Long schoolId = requestUser.getSchoolId();

        courseCode = SystemConstant.translateSpecificSign(courseCode);
        teacher = SystemConstant.translateSpecificSign(teacher);
        college = SystemConstant.translateSpecificSign(college);
        major = SystemConstant.translateSpecificSign(major);
        examStudentInfo = SystemConstant.translateSpecificSign(examStudentInfo);
        teachClazz = SystemConstant.translateSpecificSign(teachClazz);

        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(schoolId, requestUser.getId(),
                ServletUtil.getRequest().getServletPath());
        List<BasicExamStudentResult> list = this.baseMapper.findBasicExamStudentList(schoolId, semesterId, examId,
                courseCode, teacher, college, major, teachClazz, examStudentInfo, dpr);
        for (BasicExamStudentResult basicExamStudentResult : list) {
            Long examStartTime = basicExamStudentResult.getExamStartTime();
            Long examEndTime = basicExamStudentResult.getExamEndTime();
            if (SystemConstant.longNotNull(examStartTime) && SystemConstant.longNotNull(examEndTime)) {
                Map<String, Object> dateMap = ConvertUtil.analyzeDateAndTime(examStartTime, examEndTime);
                String date = String.valueOf(dateMap.get("date"));
                String time = String.valueOf(dateMap.get("time"));
                basicExamStudentResult.setExamDate(date);
                basicExamStudentResult.setExamTime(time);
            }
        }
        return list;
    }

    @Transactional
    @Override
    public Long save(BasicExamStudentParam basicExamStudentParam, SysUser requestUser) {
        BasicExam basicExam = basicExamService.getById(basicExamStudentParam.getExamId());
        BasicExamStudent basicExamStudentOld = this.getById(basicExamStudentParam.getId());
        List<String> oldPaperNumberList = new ArrayList<>();
        BasicExamStudent basicExamStudent = this.editEntityHelp(basicExamStudentParam, basicExam, oldPaperNumberList, requestUser);
        this.saveOrUpdate(basicExamStudent);
        MarkPaper markPaper = null;
        if (ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
            if (StringUtils.isBlank(basicExamStudent.getPaperNumber())) {
                throw ExceptionResultEnum.ERROR.exception("试卷编号不能为空");
            }
            markPaper = markPaperService.getByExamIdAndPaperNumber(basicExamStudent.getExamId(), basicExamStudent.getPaperNumber());
            if (markPaper == null) {
                // 模式4，不存在试卷，则创建
                BasicCourse basicCourse = basicCourseService.getByCode(basicExamStudent.getCourseCode());
                markPaper = new MarkPaper(basicExamStudent.getExamId(), basicExamStudent.getCourseCode(), basicCourse.getName(), basicExamStudent.getPaperNumber(), String.valueOf(System.currentTimeMillis()), requestUser.getId(), SystemConstant.DEFAULT_PAPER_TYPE_A);
                markPaperService.save(markPaper);
            }
        } else {
            if (StringUtils.isNotBlank(basicExamStudent.getPaperNumber())) {
                markPaper = markPaperService.getByExamIdAndPaperNumber(basicExamStudent.getExamId(), basicExamStudent.getPaperNumber());
            }
        }
        if (markPaper != null) {
            // 同步更新扫描阅卷考生表
            markStudentService.updateByBasicExamStudent(basicExamStudent, markPaper, new HashSet<>());
            markPaperService.updateStudentCountByExamIdAndPaperNumberAndPaperType(basicExamStudent.getExamId(), basicExamStudent.getPaperNumber(), SystemConstant.DEFAULT_PAPER_TYPE_A);
            if (basicExamStudentOld != null) {
                markPaperService.updateStudentCountByExamIdAndPaperNumberAndPaperType(basicExamStudent.getExamId(), basicExamStudentOld.getPaperNumber(), SystemConstant.DEFAULT_PAPER_TYPE_A);
            }
        }

        if (ExamModelEnum.MODEL4.equals(basicExam.getExamModel()) && basicExamStudentOld != null) {
            markPaperService.deleteByExamIdAndPaperNumber(basicExamStudent.getExamId(), basicExamStudentOld.getPaperNumber(), true);
        }
        return basicExamStudent.getId();
    }

    @Transactional
    @Override
    public void buildImportObjects(Map<String, Object> map) {

    }

    @Override
    public void exportLogic(HttpServletResponse response, Long semesterId, Long examId, String courseCode, String teacher, String college, String major, String teachClazz, String examStudentInfo)
            throws Exception {
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        List<BasicExamStudentResult> list = this.list(requestUser, semesterId, examId, courseCode, teacher, college,
                major, teachClazz, examStudentInfo);
        List<BasicExamStudentDto> exportDto = list.stream().flatMap(e -> {
            BasicExamStudentDto basicExamStudentDto = new BasicExamStudentDto();
            BeanUtils.copyProperties(e, basicExamStudentDto);
            return Stream.of(basicExamStudentDto);
        }).collect(Collectors.toList());

        // 生成excel文件
        ExcelUtil.excelExport("考生字典数据", BasicExamStudentDto.class, exportDto, response);
    }

    @Transactional
    @Override
    public void deleteBatch(List<Long> idList) {
        if (CollectionUtils.isNotEmpty(idList)) {
            List<BasicExamStudent> basicExamStudentList = this.listByIds(idList);
            for (BasicExamStudent basicExamStudent : basicExamStudentList) {
                MarkStudent markStudent = markStudentService.findByExamIdAndPaperNumberAndStudentCode(basicExamStudent.getExamId(), basicExamStudent.getPaperNumber(), basicExamStudent.getStudentCode());
                if (markStudent != null && markStudent.getUpload()) {
                    throw ExceptionResultEnum.ERROR.exception("考生已扫描，无法删除");
                }
                markStudentService.deleteByExamIdAndPaperNumberAndStudentCode(basicExamStudent.getExamId(), basicExamStudent.getPaperNumber(), basicExamStudent.getStudentCode());
                BasicExam basicExam = basicExamService.getById(basicExamStudent.getExamId());
                if (ExamModelEnum.MODEL4.equals(basicExam.getExamModel())) {
                    markPaperService.deleteByExamIdAndPaperNumber(basicExamStudent.getExamId(), basicExamStudent.getPaperNumber(), true);
                }
            }
            this.removeByIds(idList);
            basicExamStudentList.stream().map(BasicExamStudent::getClazzId).distinct().forEach(e -> basicTeachClazzService.deleteFreeClazz(e));
        }
    }

    /**
     * 构造考生新增/编辑对象
     *
     * @param basicExamStudentParam 考生参数
     * @param requestUser           请求人
     * @return 考生对象
     */
    @Override
    public BasicExamStudent editEntityHelp(BasicExamStudentParam basicExamStudentParam, BasicExam basicExam, List<String> oldPaperNumberList, SysUser requestUser) {
        List<String> errorMsgList = new ArrayList<>();
        Long schoolId = requestUser.getSchoolId();
        Long requestUserId = requestUser.getId();

        Long id = basicExamStudentParam.getId();
        Long semesterId = basicExamStudentParam.getSemesterId();
        Long examId = basicExamStudentParam.getExamId();
        String courseCode = basicExamStudentParam.getCourseCode();
        String studentName = basicExamStudentParam.getStudentName();
        String studentCode = basicExamStudentParam.getStudentCode();
        String college = basicExamStudentParam.getCollege();
        String major = basicExamStudentParam.getMajor();
        String teachClazz = basicExamStudentParam.getTeachClazz();
        String paperNumber = basicExamStudentParam.getPaperNumber();
        String teacherName = basicExamStudentParam.getTeacherName();
        String teacherCode = basicExamStudentParam.getTeacherCode();
        Long examStartTime = basicExamStudentParam.getExamStartTime();
        Long examEndTime = basicExamStudentParam.getExamEndTime();
        String examPlace = basicExamStudentParam.getExamPlace();
        String examRoom = basicExamStudentParam.getExamRoom();

        // 校验1 学期、考试、课程为下拉框，姓名、学号、教学班为文本框，均必填；
        if (!SystemConstant.longNotNull(semesterId)) {
            errorMsgList.add("请选择学期");
        }
        if (!SystemConstant.longNotNull(examId)) {
            errorMsgList.add("请选择考试");
        }
        if (!SystemConstant.strNotNull(courseCode)) {
            errorMsgList.add("请选择课程");
        }
        BasicCourse basicCourse = basicCourseService.findByCourseCode(courseCode, schoolId);
        if (Objects.isNull(basicCourse)) {
            errorMsgList.add(String.format("课程代码[%s]在课程管理中不存在", courseCode));
        }

        if (!SystemConstant.strNotNull(studentName)) {
            errorMsgList.add("姓名必填");
        }
        if (!SystemConstant.strNotNull(studentCode)) {
            errorMsgList.add("学号必填");
        }
        if (!RegexUtil.validStudentCode(studentCode)) {
            errorMsgList.add("学号只能由数字、字母组成");
        }
        if (!SystemConstant.strNotNull(teachClazz)) {
            errorMsgList.add("教学班必填");
        }

        Long teacherId = null;
        if (SystemConstant.strNotNull(teacherCode) && !SystemConstant.strNotNull(teacherName)) {
            errorMsgList.add("任课老师必填");
        }
        if (SystemConstant.strNotNull(teacherName) && !SystemConstant.strNotNull(teacherCode)) {
            errorMsgList.add("任课老师工号必填");
        }
        if (SystemConstant.strNotNull(teacherName) && SystemConstant.strNotNull(teacherCode)) {
            // 存在教师信息，根据工号查询，不存在报错（缺少机构信息没法直接创建教师）
            SysUser teacher = sysUserService.getOne(
                    new QueryWrapper<SysUser>().lambda().eq(SysUser::getSchoolId, schoolId)
                            .eq(SysUser::getCode, teacherCode).eq(SysUser::getRealName, teacherName)
                            .last(SystemConstant.LIMIT1));
            if (Objects.isNull(teacher)) {
                errorMsgList.add(String.format("任课老师工号[%s],任课老师[%s]在用户管理中不存在", teacherCode, teacherName));
            } else {
                teacherId = teacher.getId();
            }
        }

        // 校验2 试卷编号存在时，任课教师，考试时间，考点考场均必填；
        BasicSchool basicSchool = commonCacheService.schoolCache(schoolId);
        boolean needPaperNumber = (basicSchool.getHasPaperNumber() != null && basicSchool.getHasPaperNumber()) || ExamModelEnum.MODEL4.equals(basicExam.getExamModel());
        if (SystemConstant.strNotNull(paperNumber)) {
            String hasPaperNumberError = "试卷编号不为空时: ";
            if (!SystemConstant.strNotNull(teacherCode) || !SystemConstant.strNotNull(teacherName)) {
                errorMsgList.add(hasPaperNumberError + "任课老师、任课老师工号必填");
            }
            if (!SystemConstant.longNotNull(examStartTime) || !SystemConstant.longNotNull(examEndTime)) {
                errorMsgList.add(hasPaperNumberError + "考试时间必填");
            }
            if (!SystemConstant.strNotNull(examPlace)) {
                errorMsgList.add(hasPaperNumberError + "考点（校区）必填");
            }
            if (!SystemConstant.strNotNull(examRoom)) {
                errorMsgList.add(hasPaperNumberError + "考场(考试教室)必填");
            }
        } else if (needPaperNumber) {
            errorMsgList.add("试卷编号必填");
        }

        if (CollectionUtils.isNotEmpty(errorMsgList)) {
            throw ExceptionResultEnum.ERROR.exception(String.join(";", errorMsgList));
        }

        // 若教学班不存在则新建一个
        BasicTeachClazz basicTeachClazz = basicTeachClazzService.findOrCreateBasicTeachClazz(requestUser, examId,
                courseCode, teachClazz);

        BasicExamStudent basicExamStudent = new BasicExamStudent();
        basicExamStudent.setSchoolId(schoolId);
        basicExamStudent.setSemesterId(semesterId);
        basicExamStudent.setExamId(examId);
        basicExamStudent.setCourseCode(courseCode);
        basicExamStudent.setClazzId(basicTeachClazz.getId());
        basicExamStudent.setStudentName(studentName);
        basicExamStudent.setStudentCode(studentCode);
        basicExamStudent.setCollege(college);
        basicExamStudent.setMajor(major);
        basicExamStudent.setPaperNumber(paperNumber);
        basicExamStudent.setTeacherId(teacherId);
        basicExamStudent.setExamStartTime(examStartTime);
        basicExamStudent.setExamEndTime(examEndTime);
        basicExamStudent.setExamPlace(examPlace);
        basicExamStudent.setExamRoom(examRoom);

        if (SystemConstant.longNotNull(id)) {
            // 编辑 （学号不可更改）
            BasicExamStudent dbBasicExamStudent = this.getById(id);
            if (Objects.isNull(dbBasicExamStudent)) {
                throw ExceptionResultEnum.ERROR.exception("考生不存在");
            }
            if (!studentCode.equals(dbBasicExamStudent.getStudentCode())) {
                throw ExceptionResultEnum.ERROR.exception("编辑考生时，学号不可更改");
            }
            MarkStudent markStudent = markStudentService.findByExamIdAndPaperNumberAndStudentCode(dbBasicExamStudent.getExamId(), dbBasicExamStudent.getPaperNumber(), dbBasicExamStudent.getStudentCode());
            if (markStudent != null && markStudent.getUpload() && StringUtils.isNotBlank(paperNumber) && !paperNumber.equals(dbBasicExamStudent.getPaperNumber())) {
                throw ExceptionResultEnum.ERROR.exception("考生已扫描，不能修改试卷编号");
            }
            if (ExamModelEnum.MODEL4.equals(basicExam.getExamModel()) && dbBasicExamStudent != null) {
                oldPaperNumberList.add(dbBasicExamStudent.getPaperNumber());
            }

            basicExamStudent.setId(id);
            basicExamStudent.updateInfo(requestUserId);
        } else {
            // 新增 （学号在考试课程下唯一）
            if (this.count(new QueryWrapper<BasicExamStudent>().lambda().eq(BasicExamStudent::getSchoolId, schoolId)
                    .eq(BasicExamStudent::getExamId, examId).eq(BasicExamStudent::getCourseCode, courseCode)
                    .eq(BasicExamStudent::getStudentCode, studentCode)) > 0) {
                throw ExceptionResultEnum.ERROR.exception(String.format("学号[%s]重复", studentCode));
            }
            basicExamStudent.insertInfo(requestUserId);
        }

        return basicExamStudent;
    }

    @Override
    public List<BasicExamStudent> listByExamIdAndPaperNumber(Long examId, String paperNumber) {
        QueryWrapper<BasicExamStudent> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(BasicExamStudent::getExamId, examId)
                .eq(BasicExamStudent::getPaperNumber, paperNumber)
                .orderByAsc(BasicExamStudent::getStudentCode);
        return this.list(queryWrapper);
    }

}
