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

import com.alibaba.fastjson.JSONObject;
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.dto.ExamTaskPrintDetailDto;
import com.qmth.distributed.print.business.bean.dto.ExamTaskPrintDto;
import com.qmth.distributed.print.business.bean.dto.TaskPrintExtendFieldsDto;
import com.qmth.distributed.print.business.bean.dto.TaskPrintHouseDto;
import com.qmth.distributed.print.business.bean.params.ExamTaskPrintParams;
import com.qmth.distributed.print.business.bean.params.SerialNumberParams;
import com.qmth.distributed.print.business.entity.*;
import com.qmth.distributed.print.business.enums.ExamDataSourceEnum;
import com.qmth.distributed.print.business.enums.ExamDetailStatusEnum;
import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
import com.qmth.distributed.print.business.mapper.ExamTaskPrintMapper;
import com.qmth.distributed.print.business.service.*;
import com.qmth.teachcloud.common.bean.dto.MqDto;
import com.qmth.teachcloud.common.bean.dto.TaskPrintClassDto;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.*;
import com.qmth.teachcloud.common.enums.*;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.util.RedisUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Date: 2021/8/2.
 */
@Service
public class ExamTaskPrintServiceImpl extends ServiceImpl<ExamTaskPrintMapper, ExamTaskPrint> implements ExamTaskPrintService {

    @Resource
    private BasicStudentService basicStudentService;

    @Resource
    private ExamDetailService examDetailService;

    @Resource
    private ExamDetailCourseService examDetailCourseService;

    @Resource
    private ExamStudentService examStudentService;

    @Resource
    private ExamPrintPlanService examPrintPlanService;

    @Resource
    private BasicExamRuleService basicExamRuleService;

    @Resource
    private BasicUserCourseService basicUserCourseService;

    @Resource
    TBTaskService tbTaskService;

    @Resource
    @Lazy
    PrintCommonService printCommonService;

    @Resource
    BasicClazzService basicClazzService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    private TeachCourseService teachCourseService;

    @Resource
    private TeachClazzService teachClazzService;

    @Resource
    private TeachStudentService teachStudentService;

    @Resource
    private BasicCourseService basicCourseService;

    @Override
    public IPage<BasicStudent> listStudentByClass(String classId, Integer pageNumber, Integer pageSize) {
        Page<BasicStudent> page = new Page<>(pageNumber, pageSize);
        IPage<BasicStudent> studentIPage = basicStudentService.listPage(page, classId);
        return studentIPage;
    }

    @Transactional
    @Override
    public void remove(Long examTaskPrintId) {
        ExamTaskPrint examTaskPrint = this.getById(examTaskPrintId);
        ExamDetail examDetail = examDetailService.getById(examTaskPrint.getExamDetailId());
        if (!examDetail.getStatus().name().equals(ExamDetailStatusEnum.NEW.name()) &&
                !examDetail.getStatus().name().equals(ExamDetailStatusEnum.READY.name())) {
            throw ExceptionResultEnum.ERROR.exception("当前状态不可删除");
        }

        List<Long> entityId = Arrays.asList(examTaskPrint.getExamDetailId());
        boolean isFinish = tbTaskService.countByPrintPlanIdAndEntityId(examTaskPrint.getSchoolId(), examTaskPrint.getPrintPlanId(), entityId);
        if (!isFinish) {
            throw ExceptionResultEnum.ERROR.exception("任务正在生成pdf，不能删除");
        }

        QueryWrapper<ExamDetailCourse> examDetailCourseQueryWrapper = new QueryWrapper<>();
        examDetailCourseQueryWrapper.lambda().eq(ExamDetailCourse::getExamDetailId, examTaskPrint.getExamDetailId());
        List<ExamDetailCourse> examDetailCourses = examDetailCourseService.list(examDetailCourseQueryWrapper);
        for (ExamDetailCourse examDetailCours : examDetailCourses) {
            // 删除考务数据-考生
            UpdateWrapper<ExamStudent> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(ExamStudent::getExamDetailCourseId, examDetailCours.getId());
            examStudentService.remove(updateWrapper);

            // 删除考务数据-课程
            examDetailCourseService.removeById(examDetailCours.getId());
        }

        // 删除考务数据-考点
        examDetailService.removeById(examTaskPrint.getExamDetailId());
        // 删除exam_task_print
        this.removeById(examTaskPrintId);
    }

    @Override
    public ExamTaskPrintDto listTaskPrint(Long printPlanId, String courseCode, String paperNumber) {
        List<ExamTaskPrintDetailDto> examTaskPrintList = this.baseMapper.listByPrintPlanIdAndCourseCodeAndPaperNumber(printPlanId, courseCode, paperNumber);
        ExamTaskPrintDto examTaskPrintDto = new ExamTaskPrintDto();
        if (!CollectionUtils.isEmpty(examTaskPrintList)) {
            ExamPrintPlan examPrintPlan = examPrintPlanService.getById(printPlanId);
            if (PrintPlanStatusEnum.NEW.equals(examPrintPlan.getStatus()) || PrintPlanStatusEnum.READY.equals(examPrintPlan.getStatus())) {
                // 是否在任务中
                List<Long> entityIds = examTaskPrintList.stream().map(m -> m.getExamDetailId()).collect(Collectors.toList());
                QueryWrapper<TBTask> tbTaskQueryWrapper = new QueryWrapper<>();
                tbTaskQueryWrapper.lambda().isNotNull(TBTask::getStatus)
                        .eq(TBTask::getType, TaskTypeEnum.CREATE_PDF)
                        .eq(TBTask::getPrintPlanId, printPlanId)
                        .in(TBTask::getEntityId, entityIds);
                examTaskPrintDto.setSubmit(tbTaskService.count(tbTaskQueryWrapper) > 0);
            } else {
                examTaskPrintDto.setSubmit(true);
            }
            examTaskPrintDto.setList(examTaskPrintList);
            List<Long> startTimes = examTaskPrintList.stream().map(m -> m.getExamStartTime()).distinct().collect(Collectors.toList());
            List<Long> endTimes = examTaskPrintList.stream().map(m -> m.getExamEndTime()).distinct().collect(Collectors.toList());
            if (startTimes.size() != 1 || endTimes.size() != 1) {
                throw ExceptionResultEnum.ERROR.exception("考试时间有误");
            }
            examTaskPrintDto.setExamStartTime(startTimes.get(0));
            examTaskPrintDto.setExamEndTime(endTimes.get(0));
        }
        return examTaskPrintDto;
    }

    @Transactional
    @Override
    public ExamDetail createTaskPrint(ExamTaskPrint examTaskPrint) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();

        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(examTaskPrint.getPrintPlanId());
        if (examPrintPlan == null) {
            throw ExceptionResultEnum.ERROR.exception("印刷计划不存在");
        }
        PrintPlanStatusEnum printPlanStatus = examPrintPlan.getStatus();
        if (PrintPlanStatusEnum.NEW != printPlanStatus && PrintPlanStatusEnum.READY != printPlanStatus) {
            throw ExceptionResultEnum.ERROR.exception(printPlanStatus.getDesc() + "状态下的印刷计划不允许生成考务数据");
        }

        BasicExamRule basicExamRule = basicExamRuleService.getBySchoolId(schoolId);
        if (Objects.isNull(basicExamRule)) {
            throw ExceptionResultEnum.EXAM_RULE_IS_NULL.exception();
        }

        List<String> classIds = Arrays.asList(examTaskPrint.getClassId().split(","));
        if (examTaskPrint.getId() == null) {
            // 校验班级
            QueryWrapper<ExamTaskPrint> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(ExamTaskPrint::getPrintPlanId, examTaskPrint.getPrintPlanId());
            List<ExamTaskPrint> examTaskPrints = this.list(queryWrapper);
            validateClass(examTaskPrints, classIds);

            examTaskPrint.setSchoolId(schoolId);
            examTaskPrint.setOrgId(sysUser.getOrgId());
            examTaskPrint.setCreateId(sysUser.getId());
            examTaskPrint.setCreateTime(System.currentTimeMillis());

            // 卷袋号生成规则
            SerialNumberParams serialNumberParams = new SerialNumberParams("packageCode-" + schoolId, "1", 6);
            ExamDetail examDetail = new ExamDetail();
            examDetail.setId(SystemConstant.getDbUuid());
            examDetail.setPackageCode(printCommonService.createTempNumber(serialNumberParams));
            examDetail.setSchoolId(schoolId);
            examDetail.setOrgId(sysUser.getOrgId());
            examDetail.setPrintPlanId(examTaskPrint.getPrintPlanId());
            examDetail.setPrintPlanName(examPrintPlan.getName());
            examDetail.setExamPlace(examTaskPrint.getExamPlace());
            examDetail.setExamRoom(examTaskPrint.getExamRoom());
            examDetail.setStatus(ExamDetailStatusEnum.NEW);
            examDetail.setTotalSubjects(examTaskPrint.getStudentCount());
            examDetail.setExamStartTime(examTaskPrint.getExamStartTime());
            examDetail.setExamEndTime(examTaskPrint.getExamEndTime());
            examDetail.setExamDataSource(ExamDataSourceEnum.EXAM_TASK);
            examDetail.setNormal(true);
            examDetail.setPrintHouseId(Long.valueOf(examTaskPrint.getPrintHouseId()));
            examDetail.setCreateId(examTaskPrint.getCreateId());
            examDetail.setCreateTime(System.currentTimeMillis());
            examDetailService.save(examDetail);

            examTaskPrint.setExamDetailId(examDetail.getId());
            this.save(examTaskPrint);

            ExamDetailCourse examDetailCourse = new ExamDetailCourse();
            examDetailCourse.setId(SystemConstant.getDbUuid());
            examDetailCourse.setSchoolId(schoolId);
            examDetailCourse.setOrgId(sysUser.getOrgId());
            examDetailCourse.setExamDetailId(examDetail.getId());
            examDetailCourse.setCourseCode(examTaskPrint.getCourseCode());
            examDetailCourse.setCourseName(examTaskPrint.getCourseName());
            examDetailCourse.setPaperNumber(examTaskPrint.getPaperNumber());
            examDetailCourse.setClazzId(examTaskPrint.getClassId());
            examDetailCourse.setTotalSubjects(examTaskPrint.getStudentCount());
            examDetailCourse.setCreateId(examTaskPrint.getCreateId());
            examDetailCourseService.save(examDetailCourse);

            List<ExamStudent> examStudents = printCommonService.createBatchStudent(examTaskPrint.getSchoolId(), examTaskPrint.getExtendFields(), classIds, examDetailCourse.getId(), sysUser);
            if (!CollectionUtils.isEmpty(examStudents)) {
                examStudentService.insertBatch(examStudents);
            }

            // 更改印刷计划状态
            examPrintPlan.setStatus(PrintPlanStatusEnum.READY);
            examPrintPlanService.updateById(examPrintPlan);

            return examDetail;
        } else {
            // 校验班级
            QueryWrapper<ExamTaskPrint> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(ExamTaskPrint::getPrintPlanId, examTaskPrint.getPrintPlanId())
                    .ne(ExamTaskPrint::getId, examTaskPrint.getId());
            List<ExamTaskPrint> examTaskPrints = this.list(queryWrapper);
            // 校验班级
            validateClass(examTaskPrints, classIds);

            ExamTaskPrint taskPrint = this.getById(examTaskPrint.getId());
            taskPrint.setExamPlace(examTaskPrint.getExamPlace());
            taskPrint.setExamRoom(examTaskPrint.getExamRoom());
            taskPrint.setInvigilatorTeacher(examTaskPrint.getInvigilatorTeacher());
            taskPrint.setClassId(examTaskPrint.getClassId());
            taskPrint.setClassName(examTaskPrint.getClassName());
            taskPrint.setStudentCount(examTaskPrint.getStudentCount());
            taskPrint.setCampusId(examTaskPrint.getCampusId());
            taskPrint.setPrintHouseId(examTaskPrint.getPrintHouseId());
            taskPrint.setExtendFields(examTaskPrint.getExtendFields());
            taskPrint.setUpdateId(sysUser.getId());
            taskPrint.setUpdateTime(System.currentTimeMillis());
            this.updateById(taskPrint);

            ExamDetail examDetail = examDetailService.getById(taskPrint.getExamDetailId());
            examDetail.setExamPlace(examTaskPrint.getExamPlace());
            examDetail.setExamRoom(examTaskPrint.getExamRoom());
            examDetail.setTotalSubjects(examTaskPrint.getStudentCount());
            examDetail.setUpdateId(sysUser.getId());
            examDetail.setUpdateTime(System.currentTimeMillis());
            examDetailService.updateById(examDetail);

            QueryWrapper<ExamDetailCourse> examDetailCourseQueryWrapper = new QueryWrapper<>();
            examDetailCourseQueryWrapper.lambda().eq(ExamDetailCourse::getExamDetailId, taskPrint.getExamDetailId());
            ExamDetailCourse examDetailCourse = examDetailCourseService.getOne(examDetailCourseQueryWrapper);
            examDetailCourse.setClazzId(taskPrint.getClassId());
            examDetailCourseService.updateById(examDetailCourse);

            UpdateWrapper<ExamStudent> examStudentUpdateWrapper = new UpdateWrapper<>();
            examStudentUpdateWrapper.lambda().eq(ExamStudent::getExamDetailCourseId, examDetailCourse.getId());
            examStudentService.remove(examStudentUpdateWrapper);

            List<ExamStudent> examStudents = printCommonService.createBatchStudent(taskPrint.getSchoolId(), taskPrint.getExtendFields(), classIds, examDetailCourse.getId(), sysUser);
            if (!CollectionUtils.isEmpty(examStudents)) {
                examStudentService.insertBatch(examStudents);
            }

            return examDetail;
        }
    }

    @Override
    public List<TaskPrintClassDto> listClass(String printPlanId, String courseCode, String paperNumber, Long examTaskPrintId) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        List<BasicUserCourse> courseList = basicUserCourseService.listBySchoolIdAndCourseCode(schoolId, courseCode);
        Set<String> stringList = courseList.stream().map(m -> String.valueOf(m.getClazzId())).collect(Collectors.toSet());

        if (!CollectionUtils.isEmpty(stringList)) {
            QueryWrapper<ExamTaskPrint> examTaskPrintQueryWrapper = new QueryWrapper<>();
            examTaskPrintQueryWrapper.lambda().eq(ExamTaskPrint::getPrintPlanId, printPlanId).eq(ExamTaskPrint::getCourseCode, courseCode).eq(ExamTaskPrint::getPaperNumber, paperNumber);
            List<ExamTaskPrint> examTaskPrints = this.list(examTaskPrintQueryWrapper);
            for (ExamTaskPrint examTaskPrint : examTaskPrints) {
                List<String> classIds = Arrays.asList(examTaskPrint.getClassId().split(","));
                for (String classId : classIds) {
                    if (stringList.contains(classId)) {
                        stringList.remove(classId);
                    }
                }
            }
        }

        if (Objects.nonNull(examTaskPrintId)) {
            ExamTaskPrint examTaskPrint = this.getById(examTaskPrintId);
            if (Objects.isNull(examTaskPrint)) {
                throw ExceptionResultEnum.ERROR.exception("数据不存在");
            }
            String classId = examTaskPrint.getClassId();
            if (StringUtils.isNotBlank(classId)) {
                String[] classIds = classId.split(",");
                for (String id : classIds) {
                    stringList.add(id);
                }
            }
        }

        if (!CollectionUtils.isEmpty(stringList)) {
            List<TaskPrintClassDto> taskPrintClassDtos = basicStudentService.listByClass(schoolId, stringList);
            return taskPrintClassDtos;
        }
        return null;
    }

    @Override
    public List<TaskPrintHouseDto> listHouse() {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        List<TaskPrintHouseDto> houseDtos = this.baseMapper.listTaskPrintHouse(schoolId, OrgTypeEnum.PRINTING_HOUSE.name());
        return houseDtos;
    }

    @Override
    public List<TaskPrintExtendFieldsDto> listTaskPrintExtendFields() {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        BasicExamRule basicExamRule = basicExamRuleService.getBySchoolId(schoolId);
        if (basicExamRule == null) {
            throw ExceptionResultEnum.ERROR.exception("通用规则未设置");
        }
        if (Objects.nonNull(basicExamRule.getExtendFields())) {
            List<TaskPrintExtendFieldsDto> taskPrintExtendFieldsDtos = JSONObject.parseArray(basicExamRule.getExtendFields(), TaskPrintExtendFieldsDto.class);
            if (!CollectionUtils.isEmpty(taskPrintExtendFieldsDtos)) {
                taskPrintExtendFieldsDtos = taskPrintExtendFieldsDtos.stream().filter(m -> m.getEnable()).collect(Collectors.toList());
                return taskPrintExtendFieldsDtos;
            }
        }
        return null;
    }

    @Override
    public void submitTaskPrint(ExamTaskPrintParams examTaskPrintParams) throws IOException {
        if (Objects.isNull(examTaskPrintParams.getPrintPlanId())) {
            throw ExceptionResultEnum.ERROR.exception("印刷计划不能为空");
        }
        List<Long> list = examTaskPrintParams.getList();
        if (CollectionUtils.isEmpty(list)) {
            throw ExceptionResultEnum.ERROR.exception("没有可提交数据");
        }
        // 调用生成pdf方法
        for (Long examDetailId : list) {
            Map<String, Object> map = tbTaskService.saveTask(TaskTypeEnum.CREATE_PDF, examTaskPrintParams.getPrintPlanId(), (SysUser) ServletUtil.getRequestUser(), examDetailId);
//            asyncCreatePdfTempleteService.createPdf(map, null);
            MqDto mqDto = new MqDto(MqTagEnum.PDF.getCode(), map, String.valueOf(map.get(SystemConstant.TB_TASK_ID)));
            redisUtil.sendMessage(mqDto.getTopic(), mqDto);
        }
    }

    @Override
    public List<TaskPrintClassDto> listExamTaskClass(String courseCode) {
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        List<TaskPrintClassDto> taskPrintClassDtos = new ArrayList<>();
        BasicCourse basicCourse = basicCourseService.findByCourseCode(courseCode, schoolId);
        // 1.判断教学表中是否有数据
        List<TeachCourse> teachCourseDatasource = teachCourseService.list(new QueryWrapper<TeachCourse>().lambda()
                .eq(TeachCourse::getSchoolId, schoolId)
                .eq(TeachCourse::getUserId, requestUser.getId()));
        if (teachCourseDatasource != null && teachCourseDatasource.size() > 0) {
            // 如果该用户创建了任意教学课程，则走教学课程查询逻辑
            List<TeachCourse> teachCourseList = teachCourseDatasource.stream().filter(e -> basicCourseService.getById(e.getBasicCourseId()).getCode().equals(courseCode)).collect(Collectors.toList());
            if (teachCourseList.size() > 1) {
                throw ExceptionResultEnum.ERROR.exception("基础信息管理中【" + basicCourse.getName() + "】教学课程信息存在多条数据异常");
            }
            if (teachCourseList.size() == 0) {
                // 没创建该教学课程
                throw ExceptionResultEnum.ERROR.exception("请优先在基础信息管理中创建【" + basicCourse.getName() + "】的教学课程信息");
            }
            TeachCourse teachCourse = teachCourseList.get(0);
            List<TeachClazz> teachClazzList = teachClazzService.list(new QueryWrapper<TeachClazz>().lambda().in(TeachClazz::getTeachCourseId, teachCourse.getId()));
            for (TeachClazz teachClazz : teachClazzList) {
                TaskPrintClassDto dto = new TaskPrintClassDto();
                dto.setClassId(String.valueOf(teachClazz.getId()));
                dto.setTeachBasicEnum(TeachBasicEnum.TEACH_CLAZZ);
                dto.setClassName(teachClazz.getTeachClazzName());
                dto.setStudentCount(teachStudentService.count(new QueryWrapper<TeachStudent>().lambda().eq(TeachStudent::getTeachClazzId, teachClazz.getId())));
                taskPrintClassDtos.add(dto);
            }
        } else {
            List<BasicUserCourse> courseList = basicUserCourseService.listBySchoolIdAndCourseCode(schoolId, courseCode);
            Set<String> stringList = courseList.stream().map(m -> String.valueOf(m.getClazzId())).collect(Collectors.toSet());

            if (!CollectionUtils.isEmpty(stringList)) {
                taskPrintClassDtos = basicStudentService.listByClass(schoolId, stringList);
            }
        }
        return taskPrintClassDtos;
    }

    private void validateClass(List<ExamTaskPrint> examTaskPrints, List<String> classIds) {
        if (!CollectionUtils.isEmpty(examTaskPrints)) {
            for (ExamTaskPrint taskPrint : examTaskPrints) {
                List<String> hisClassIds = Arrays.asList(taskPrint.getClassId().split(","));
                for (String classId : classIds) {
                    if (hisClassIds.contains(classId)) {
                        String clazzNamesByClazzIds = examDetailService.findClazzNamesByClazzIds(classId, ",");
                        throw ExceptionResultEnum.ERROR.exception(clazzNamesByClazzIds + "已分配考场");
                    }
                }
            }
        }
    }

}
