package com.keao.edu.user.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.keao.edu.auth.api.client.SysUserFeignService;
import com.keao.edu.auth.api.entity.SysUser;
import com.keao.edu.common.controller.BaseController;
import com.keao.edu.common.dal.BaseDAO;
import com.keao.edu.common.entity.HttpResponseResult;
import com.keao.edu.common.entity.SysConfig;
import com.keao.edu.common.enums.MessageTypeEnum;
import com.keao.edu.common.exception.BizException;
import com.keao.edu.common.page.PageInfo;
import com.keao.edu.common.service.IdGeneratorService;
import com.keao.edu.common.service.SysMessageService;
import com.keao.edu.common.service.impl.BaseServiceImpl;
import com.keao.edu.common.tenant.TenantContextHolder;
import com.keao.edu.im.api.client.ImFeignService;
import com.keao.edu.im.api.entity.MemberChangedMessage;
import com.keao.edu.im.api.entity.PublishMessageDto;
import com.keao.edu.thirdparty.message.provider.JiguangPushPlugin;
import com.keao.edu.thirdparty.message.provider.YimeiSmsPlugin;
import com.keao.edu.thirdparty.yqpay.DateUtils;
import com.keao.edu.user.api.entity.ExamRoom;
import com.keao.edu.user.api.entity.ExamRoomStudentRelation;
import com.keao.edu.user.api.enums.ExamModeEnum;
import com.keao.edu.user.dao.*;
import com.keao.edu.user.dto.*;
import com.keao.edu.user.entity.*;
import com.keao.edu.user.page.ExamRoomListQueryInfo;
import com.keao.edu.user.page.ExamRoomQueryInfo;
import com.keao.edu.user.service.*;
import com.keao.edu.util.collection.MapUtil;
import com.keao.edu.util.date.DateUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ExamRoomServiceImpl extends BaseServiceImpl<Long, ExamRoom> implements ExamRoomService {

	@Autowired
	private ExamRoomDao examRoomDao;
	@Autowired
	private ExamRoomStudentRelationService examRoomStudentRelationService;
	@Autowired
	private OrganizationService organizationService;
	@Autowired
	private ExamRegistrationDao examRegistrationDao;
	@Autowired
	private ExaminationBasicDao examinationBasicDao;
	@Autowired
	private SysUserDao sysUserDao;
	@Autowired
	private ExamTeacherSalaryService examTeacherSalaryService;
	@Autowired
	private ExamCertificationService examCertificationService;
	@Autowired
	private StudentExamResultDao studentExamResultDao;
	@Autowired
	private ExamReviewDao examReviewDao;
	@Autowired
	private ExamOrganizationRelationDao examOrganizationRelationDao;
	@Autowired
	private ExamLifecycleLogDao examLifecycleLogDao;
	@Autowired
	private ImFeignService imFeignService;
	@Autowired
	private SysUserFeignService sysUserFeignService;
	@Autowired
	private SysMessageService sysMessageService;
	@Autowired
	private ExamRoomStudentRelationDao examRoomStudentRelationDao;
	@Autowired
	private ExamCertificationDao examCertificationDao;
	@Autowired
	private ExamLocationDao examLocationDao;
	@Autowired
	private IdGeneratorService idGeneratorService;
	@Autowired
	private SysConfigService sysConfigService;
	@Autowired
	private StudentExamResultService studentExamResultService;

	@Override
	public BaseDAO<Long, ExamRoom> getDAO() {
		return examRoomDao;
	}

	@Override
	public PageInfo<ExamRoomListDto> queryExamRoomPage(ExamRoomListQueryInfo queryInfo) {
		PageInfo<ExamRoomListDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<>();
		MapUtil.populateMap(params, queryInfo);

//		List<Integer> childOrganIds = organizationService.getChildOrganIds(queryInfo.getOrganId(), true);
//		params.put("organIds", childOrganIds);
		SysUser sysUser = sysUserFeignService.queryUserInfo();
		params.put("teacherId",sysUser.getId());

		List<ExamRoomListDto> dataList = null;
		int count = examRoomDao.countExamRoomPage(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = examRoomDao.queryExamRoomPage(params);
			//获取考试学员数
			Set<Long> roomIds = dataList.stream().map(e -> e.getExamRoomId()).collect(Collectors.toSet());
			Map<Long, Integer> convertMybatisMap = MapUtil.convertMybatisMap(examRoomStudentRelationDao.getStudentNumMap(roomIds), Long.class, Integer.class);
			dataList.forEach(e->{
				e.setStudentNum(convertMybatisMap.get(e.getExamRoomId()));
			});
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public PageInfo<ExamRoomDto> queryExamRooms(ExamRoomQueryInfo queryInfo) {
		PageInfo<ExamRoomDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<>();
		MapUtil.populateMap(params, queryInfo);

		List<Integer> childOrganIds = organizationService.getChildOrganIds(queryInfo.getOrganId(), true);
		params.put("organIds", childOrganIds);

		List<ExamRoomDto> dataList = null;
		int count = examRoomDao.countExamRoom(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = examRoomDao.queryExamRoom(params);
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void createExamRoom(ExamRoom examRoom) {
		if(Objects.isNull(examRoom.getExaminationBasicId())){
			throw new BizException("请指定考级项目");
		}
		ExaminationBasic examinationBasic = examinationBasicDao.get(examRoom.getExaminationBasicId().longValue());
		if(Objects.isNull(examinationBasic)){
			throw new BizException("考级项目不存在");
		}
		if(Objects.isNull(examRoom.getExamMode())){
			throw new BizException("请指定考试类型");
		}
		if(ExamModeEnum.OFFLINE.equals(examRoom.getExamMode())&&Objects.isNull(examRoom.getExamLocationId())){
			throw new BizException("线下考试请指定考试地址");
		}
		if(StringUtils.isBlank(examRoom.getSubjectIdList())){
			throw new BizException("请指定考试专业");
		}
		if(Objects.isNull(examRoom.getMainTeacherUserId())){
			throw new BizException("请指定主考老师");
		}
		if(StringUtils.isBlank(examRoom.getExamTimeJson())){
			throw new BizException("请指定考试时间");
		}

		if(ExamModeEnum.ONLINE.equals(examRoom.getExamMode())){
			examRoom.setExamLocationId(null);
		}

		ExamOrganizationRelation examOrganizationRelation = examOrganizationRelationDao.getExamOrganizationRelation(examinationBasic.getId(), examRoom.getOrganId());
		if(Objects.isNull(examOrganizationRelation)||examOrganizationRelation.getIsAllowArrangeExam()==0){
			throw new BizException("无权操作");
		}

		examRoom.setTenantId(TenantContextHolder.getTenantId());
		examRoom.setExamPlanPushFlag(0);
		examRoom.setExamRoomStudentNum(0);
		if(StringUtils.isBlank(examRoom.getExamTimeJson())){
			examRoomDao.insert(examRoom);
			return;
		}

		List<Integer> teacherIds=new ArrayList<>();
		teacherIds.add(examRoom.getMainTeacherUserId());
		if(StringUtils.isNotBlank(examRoom.getAssistantTeacherUserIdList())){
			teacherIds.addAll(Arrays.stream(examRoom.getAssistantTeacherUserIdList().split(",")).map(id->Integer.valueOf(id)).collect(Collectors.toList()));
			HashSet<Integer> noRepeatTeacherIds = new HashSet<>(teacherIds);
			if(teacherIds.size()!=noRepeatTeacherIds.size()){
				throw new BizException("主考老师与监考老师不可重复");
			}
		}

		Map<Integer, String> teacherIdNameMap = this.getMap("sys_user", "id_", "real_name_", teacherIds, Integer.class, String.class);

		examRoom.setMainTeacherName(teacherIdNameMap.get(examRoom.getMainTeacherUserId()));
		if(StringUtils.isNotBlank(examRoom.getAssistantTeacherUserIdList())){
			List<Integer> assistantTeacherIds = Arrays.stream(examRoom.getAssistantTeacherUserIdList().split(",")).map(id -> Integer.valueOf(id)).collect(Collectors.toList());
			List<String> assistantTeacherNames = new ArrayList<>();
			for (Integer assistantTeacherId : assistantTeacherIds) {
				assistantTeacherNames.add(teacherIdNameMap.get(assistantTeacherId));
			}
			examRoom.setAssistantTeacherUserNameList(StringUtils.join(assistantTeacherNames, ","));
		}

		List<Integer> subjectIds = Arrays.stream(examRoom.getSubjectIdList().split(",")).map(e -> Integer.valueOf(e)).collect(Collectors.toList());
		Map<Integer, String> subjectIdNameMap = this.getMap("subject", "id_", "name_", subjectIds, Integer.class, String.class);
		examRoom.setSubjectNameList(StringUtils.join(subjectIdNameMap.values(),","));

		List<ExamRoom> examRooms=new ArrayList<>();
		List<JSONObject> examTimes = JSON.parseArray(examRoom.getExamTimeJson(), JSONObject.class);
		for (JSONObject examTime : examTimes) {
			ExamRoom er;
			try {
				er= (ExamRoom) BeanUtils.cloneBean(examRoom);
			} catch (Exception e) {
				throw new BizException("教室创建失败");
			}
			er.setExamStartTime(examTime.getDate("examStartTime"));
			er.setExamEndTime(examTime.getDate("examEndTime"));
			if(Objects.isNull(er.getExamStartTime())||Objects.isNull(er.getExamEndTime())){
				throw new BizException("请指定考试时间");
			}
			if(er.getExamStartTime().compareTo(er.getExamEndTime())>=0){
				throw new BizException("考试时间异常");
			}
			if(!DateUtils.isSameDay(er.getExamStartTime(), er.getExamEndTime())){
				throw new BizException("暂不支持跨天");
			}
			if(examinationBasic.getEnrollEndTime().compareTo(er.getExamStartTime())>0){
				throw new BizException("考试时间不可在报名结束时间之前");
			}
			examRooms.add(er);
		}
		checkRoomTeachers(examRooms);
		examRoomDao.batchInsert(examRooms);

		ExamRoomExamTimeDto examRoomExamTime = examRoomDao.getExamRoomExamTime(examRoom.getExaminationBasicId());

		if(Objects.isNull(examRoomExamTime)){
			examinationBasic.setActualExamStartTime(null);
			examinationBasic.setActualExamEndTime(null);
		}else{
			examinationBasic.setActualExamStartTime(DateUtils.truncate(examRoomExamTime.getExamStartTime(), Calendar.DAY_OF_MONTH));
			examinationBasic.setActualExamEndTime(DateUtils.ceiling(examRoomExamTime.getExamEndTime(), Calendar.DAY_OF_MONTH));
		}

		examinationBasicDao.update(examinationBasic);

		examTeacherSalaryService.teacherSalarySettlementWithExam(examinationBasic.getId());
	}

	@Override
	public ExamRoom updateExamRoom(ExamRoom examRoom) {
		if(Objects.isNull(examRoom.getId())){
			throw new BizException("请指定考场");
		}

		ExamRoom existExamRoom = examRoomDao.get(examRoom.getId());
		if(Objects.isNull(existExamRoom)){
			throw new BizException("考场不存在");
		}

		if(existExamRoom.getExamPlanPushFlag()==1){
			throw new BizException("无法修改");
		}

		ExaminationBasic examinationBasic = examinationBasicDao.get(examRoom.getExaminationBasicId().longValue());
		if(Objects.isNull(examinationBasic)){
			throw new BizException("考级项目不存在");
		}

		ExamOrganizationRelation examOrganizationRelation = examOrganizationRelationDao.getExamOrganizationRelation(existExamRoom.getExaminationBasicId(), examRoom.getOrganId());
		if(Objects.isNull(examOrganizationRelation)||examOrganizationRelation.getIsAllowArrangeExam()==0){
			throw new BizException("无权操作");
		}

		if(ExamModeEnum.ONLINE.equals(examRoom.getExamMode())){
			examRoom.setExamLocationId(null);
		}

		List<Integer> teacherIds=new ArrayList<>();
		teacherIds.add(examRoom.getMainTeacherUserId());
		if(StringUtils.isNotBlank(examRoom.getAssistantTeacherUserIdList())){
			teacherIds.addAll(Arrays.stream(examRoom.getAssistantTeacherUserIdList().split(",")).map(id->Integer.valueOf(id)).collect(Collectors.toList()));
			HashSet<Integer> noRepeatTeacherIds = new HashSet<>(teacherIds);
			if(teacherIds.size()!=noRepeatTeacherIds.size()){
				throw new BizException("主考老师与监考老师不可重复");
			}
		}

		Map<Integer, String> teacherIdNameMap = this.getMap("sys_user", "id_", "real_name_", teacherIds, Integer.class, String.class);

		examRoom.setMainTeacherName(teacherIdNameMap.get(examRoom.getMainTeacherUserId()));
		if(StringUtils.isNotBlank(examRoom.getAssistantTeacherUserIdList())){
			List<Integer> assistantTeacherIds = Arrays.stream(examRoom.getAssistantTeacherUserIdList().split(",")).map(id -> Integer.valueOf(id)).collect(Collectors.toList());
			List<String> assistantTeacherNames = new ArrayList<>();
			for (Integer assistantTeacherId : assistantTeacherIds) {
				assistantTeacherNames.add(teacherIdNameMap.get(assistantTeacherId));
			}
			examRoom.setAssistantTeacherUserNameList(StringUtils.join(assistantTeacherNames, ","));
		}

		List<Integer> subjectIds = Arrays.stream(examRoom.getSubjectIdList().split(",")).map(e -> Integer.valueOf(e)).collect(Collectors.toList());
		Map<Integer, String> subjectIdNameMap = this.getMap("subject", "id_", "name_", subjectIds, Integer.class, String.class);
		examRoom.setSubjectNameList(StringUtils.join(subjectIdNameMap.values(),","));

		if(Objects.isNull(examRoom.getExamStartTime())){
			examRoom.setExamStartTime(existExamRoom.getExamStartTime());
		}
		if(Objects.isNull(examRoom.getExamEndTime())){
			examRoom.setExamEndTime(existExamRoom.getExamEndTime());
		}

		if(examRoom.getExamStartTime().compareTo(examRoom.getExamEndTime())>=0){
			throw new BizException("考试时间异常");
		}

		if(!DateUtils.isSameDay(examRoom.getExamStartTime(), examRoom.getExamEndTime())){
			throw new BizException("暂不支持跨天");
		}

		if(examinationBasic.getEnrollEndTime().compareTo(examRoom.getExamStartTime())>0){
			throw new BizException("考试时间不可在报名结束时间之前");
		}

		List<ExamRoom> examRooms=new ArrayList<>(Arrays.asList(examRoom));
		checkRoomTeachers(examRooms);

		examRoomDao.update(examRoom);

		ExamRoomExamTimeDto examRoomExamTime = examRoomDao.getExamRoomExamTime(examRoom.getExaminationBasicId());
		if(Objects.isNull(examRoomExamTime)){
			examinationBasic.setActualExamStartTime(null);
			examinationBasic.setActualExamEndTime(null);
		}else{
			examinationBasic.setActualExamStartTime(DateUtils.truncate(examRoomExamTime.getExamStartTime(), Calendar.DAY_OF_MONTH));
			examinationBasic.setActualExamEndTime(DateUtils.ceiling(examRoomExamTime.getExamEndTime(), Calendar.DAY_OF_MONTH));
		}
		examinationBasicDao.update(examinationBasic);

		if(ExamModeEnum.OFFLINE.equals(examRoom.getExamMode())){
			ExamLocation examLocation = examLocationDao.get(examRoom.getExamLocationId());
			if(Objects.isNull(examLocation)){
				throw new BizException("考试地址不存在");
			}
			List<ExamRoomStudentRelation> examRoomStudents = examRoomStudentRelationDao.findStudentsWithExamRoom(examRoom.getId());
			List<Long> registIds = examRoomStudents.stream().map(ExamRoomStudentRelation::getExamRegistrationId).collect(Collectors.toList());
			examCertificationDao.updateExamAddress(examLocation.getAddress(), registIds);
		}

		examTeacherSalaryService.teacherSalarySettlementWithExam(examRoom.getExaminationBasicId());
		return examRoom;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteExamRooms(Integer organId,String examRoomIdsStr) {
		if(StringUtils.isBlank(examRoomIdsStr)){
			return;
		}
		List<Long> examRoomIds = Arrays.asList(examRoomIdsStr.split(",")).stream().map(e -> Long.valueOf(e)).collect(Collectors.toList());

		ExamRoom examRoom = examRoomDao.get(examRoomIds.get(0));

		if(examRoom.getExamPlanPushFlag()==1){
			throw new BizException("已发送考试安排，无法删除");
		}

		ExaminationBasic examinationBasic = examinationBasicDao.get(examRoom.getExaminationBasicId().longValue());
		if(Objects.isNull(examinationBasic)){
			throw new BizException("考级项目不存在");
		}

		ExamOrganizationRelation examOrganizationRelation = examOrganizationRelationDao.getExamOrganizationRelation(examRoom.getExaminationBasicId(), organId);
		if(Objects.isNull(examOrganizationRelation)||examOrganizationRelation.getIsAllowArrangeExam()==0){
			throw new BizException("无权操作");
		}

		List<ExamRoomStudentRelation> roomStudents = examRoomStudentRelationService.findStudentsWithExamRooms(examRoomIds);
		List<Long> registIds = roomStudents.stream().map(ExamRoomStudentRelation::getExamRegistrationId).collect(Collectors.toList());

		examRoomStudentRelationService.deleteWithExamRooms(examRoomIds);

		if(!CollectionUtils.isEmpty(registIds)){
			examCertificationService.deleteWithRegist(registIds);
			studentExamResultDao.deleteWithRegists(registIds);
		}

		examRoomDao.batchDeleteExamRooms(examRoomIds);

		ExamRoomExamTimeDto examRoomExamTime = examRoomDao.getExamRoomExamTime(examRoom.getExaminationBasicId());
		if(Objects.isNull(examRoomExamTime)){
			examinationBasic.setActualExamStartTime(null);
			examinationBasic.setActualExamEndTime(null);
		}else{
			examinationBasic.setActualExamStartTime(DateUtils.truncate(examRoomExamTime.getExamStartTime(), Calendar.DAY_OF_MONTH));
			examinationBasic.setActualExamEndTime(DateUtils.ceiling(examRoomExamTime.getExamEndTime(), Calendar.DAY_OF_MONTH));
		}
		examinationBasicDao.update(examinationBasic);

		examTeacherSalaryService.teacherSalarySettlementWithExam(examRoom.getExaminationBasicId());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public HttpResponseResult sendExamPlan(Integer organId, Integer examId, Integer operatorId) {
		if(Objects.isNull(examId)){
			throw new BizException("请指定考级项目");
		}
		ExaminationBasic exam = examinationBasicDao.get(examId.longValue());
		if(Objects.isNull(exam)){
			throw new BizException("考级项目不存在");
		}

		ExamOrganizationRelation examOrganizationRelation = examOrganizationRelationDao.getExamOrganizationRelation(exam.getId(), organId);
		if(Objects.isNull(examOrganizationRelation)||examOrganizationRelation.getIsAllowArrangeExam()==0){
			throw new BizException("无权操作");
		}

		int withoutExamRoomStudentNum = examRegistrationDao.countWithoutExamRoomStudentNum(null, examId);
		if(withoutExamRoomStudentNum>0){
			throw new BizException("存在未安排教室的学员");
		}
		examLifecycleLogDao.insert(new ExamLifecycleLog(examId, "确认考试安排", operatorId));
		List<ExamRoomStudentRelation> examRoomStudentWithOrgans = examRoomStudentRelationDao.getNoSendExamPlanRooms(examId.longValue(), null);

		if(CollectionUtils.isEmpty(examRoomStudentWithOrgans)){
			return BaseController.succeed("所有考场都已发送考试安排");
		}

		Set<Integer> locationIds = examRoomStudentWithOrgans.stream().filter(e -> Objects.nonNull(e.getExamLocationId())).map(ExamRoomStudentRelation::getExamLocationId).collect(Collectors.toSet());
		Map<Integer, String> idLocationMap = this.getMap("exam_location", "id_", "name_", new ArrayList(locationIds), Integer.class, String.class);

		Set<Integer> allStudentIds = examRoomStudentWithOrgans.stream().map(ExamRoomStudentRelation::getStudentId).collect(Collectors.toSet());
		Map<Integer, String> idPhoneMap = this.getMap("sys_user", "id_", "phone_", new ArrayList(allStudentIds), Integer.class, String.class);

		Set<Long> registIds = examRoomStudentWithOrgans.stream().map(ExamRoomStudentRelation::getExamRegistrationId).collect(Collectors.toSet());
		List<ExamRegistration> examRegistrations = examRegistrationDao.getRegists(new ArrayList<>(registIds));
		Map<Integer, ExamRegistration> studentRegistMap = examRegistrations.stream().collect(Collectors.toMap(ExamRegistration::getId, e -> e));

		Map<Long, List<ExamRoomStudentRelation>> examRoomStudentMap = examRoomStudentWithOrgans.stream().collect(Collectors.groupingBy(ExamRoomStudentRelation::getExamRoomId));

		Map<Integer, List<ExamRoom>> teacherExamRoomsMap = new HashMap<>();

		List<ExamRoom> needUpdateExamRooms = new ArrayList<>();
		List<ExamRegistration> updateRegistrations = new ArrayList<>();
		List<ExamCertification> examCertifications=new ArrayList<>();
		List<StudentExamResult> studentExamResults=new ArrayList<>();

		SysConfig baseH5UrlConfig = sysConfigService.findByParamName(SysConfigService.BASE_H5_URL);
		String baseH5Url = "";
		if(Objects.nonNull(baseH5UrlConfig)){
			baseH5Url = baseH5UrlConfig.getParanValue();
		}

		String baseUrl = "2?examRegistrationId=";
		String downloadUrl = baseH5Url + "/#/downLoad?memo=2&examRegistrationId=";

		for (Map.Entry<Long, List<ExamRoomStudentRelation>> examRoomStudentEntry : examRoomStudentMap.entrySet()) {
			List<ExamRoomStudentRelation> students = examRoomStudentEntry.getValue();
			Set<Integer> studentIds = students.stream().map(ExamRoomStudentRelation::getStudentId).collect(Collectors.toSet());
			if(CollectionUtils.isEmpty(studentIds)){
				continue;
			}
			ExamRoom examRoom=students.get(0);
			examRoom.setId(students.get(0).getExamRoomId());

			for (ExamRoomStudentRelation student : students) {
				ExamRegistration examRegistration = studentRegistMap.get(Integer.valueOf(student.getExamRegistrationId().toString()));
				if(Objects.isNull(examRegistration)){
					throw new BizException("学员信息错误");
				}
				ExamCertification ec=new ExamCertification();
				ec.setExamRegistrationId(student.getExamRegistrationId());
				ec.setExaminationBasicId(student.getExaminationBasicId());
				ec.setStudentId(student.getStudentId());
				ec.setCardNo(String.valueOf(idGeneratorService.generatorId()));
				ec.setSubjectId(examRegistration.getSubjectId());
				ec.setLevel(examRegistration.getLevel());
				ec.setExamStartTime(examRoom.getExamStartTime());
				ec.setExamEndTime(examRoom.getExamEndTime());
				if(ExamModeEnum.OFFLINE.equals(examRoom.getExamMode())){
					ec.setExamAddress(idLocationMap.get(student.getExamLocationId()));
				}
				ec.setTenantId(TenantContextHolder.getTenantId());
				examCertifications.add(ec);

				StudentExamResult ser = new StudentExamResult();
				ser.setExamRegistrationId(examRegistration.getId().longValue());
				ser.setExaminationBasicId(examRegistration.getExaminationBasicId());
				ser.setStudentId(examRegistration.getStudentId());
				ser.setIsFinishedExam(3);
				ser.setConfirmStatus(0);
				ser.setTenantId(TenantContextHolder.getTenantId());
				ser.setExamRoomId(student.getExamRoomId());
				studentExamResults.add(ser);

				examRegistration.setCardNo(ec.getCardNo());
				updateRegistrations.add(examRegistration);
			}

			needUpdateExamRooms.add(new ExamRoom(examRoom.getId(), 1));

			if(!teacherExamRoomsMap.containsKey(examRoom.getMainTeacherUserId())){
				teacherExamRoomsMap.put(examRoom.getMainTeacherUserId(), new ArrayList<>());
			}
			teacherExamRoomsMap.get(examRoom.getMainTeacherUserId()).add(examRoom);
			if(StringUtils.isNotBlank(examRoom.getAssistantTeacherUserIdList())){
				Set<Integer> ateacherIds = Arrays.stream(examRoom.getAssistantTeacherUserIdList().split(",")).map(e -> Integer.valueOf(e)).collect(Collectors.toSet());
				for (Integer ateacherId : ateacherIds) {
					if(!teacherExamRoomsMap.containsKey(ateacherId)){
						teacherExamRoomsMap.put(ateacherId, new ArrayList<>());
					}
					teacherExamRoomsMap.get(ateacherId).add(examRoom);
				}
			}

			Map<Integer, String> receiverMap = studentIds.stream().collect(Collectors.toMap(e->e, e->e.toString()));
			Map<Integer, String> phoneMap = idPhoneMap.entrySet().stream().filter(e->studentIds.contains(e.getKey())).collect(Collectors.toMap(e->e.getKey(), e->e.getValue()));

			MessageTypeEnum pushMessageType = MessageTypeEnum.EXAM_ROOM_CONFIRM_ONLINE_STUDENT_PUSH;
			MessageTypeEnum smsMessageType = MessageTypeEnum.EXAM_ROOM_CONFIRM_ONLINE_STUDENT_SMS;

			String examName = exam.getName();

			String examDayStr = DateUtil.dateToString(examRoom.getExamStartTime(), "MM月dd日");
			StringBuffer examTimeStr = new StringBuffer();
			examTimeStr.append(DateUtil.dateToString(examRoom.getExamStartTime(), "HH时mm分"));
			examTimeStr.append("-");
			examTimeStr.append(DateUtil.dateToString(examRoom.getExamEndTime(), "HH时mm分"));

			String locationName = "网络考场";
			if(ExamModeEnum.OFFLINE.equals(examRoom.getExamMode())){
				pushMessageType = MessageTypeEnum.EXAM_ROOM_CONFIRM_OFFLINE_STUDENT_PUSH;
				smsMessageType = MessageTypeEnum.EXAM_ROOM_CONFIRM_OFFLINE_STUDENT_SMS;
				locationName=idLocationMap.get(examRoom.getExamLocationId());
			}
			String url = baseUrl + students.get(0).getExamRegistrationId();
			sysMessageService.batchSendMessage(pushMessageType,
					receiverMap, null, 0, url, JiguangPushPlugin.PLUGIN_NAME,
					examName, examDayStr, examTimeStr, locationName);
			sysMessageService.batchSendMessage(smsMessageType,
					phoneMap, null, 0, null, YimeiSmsPlugin.PLUGIN_NAME,
					examName, examDayStr, examTimeStr, locationName, downloadUrl + students.get(0).getExamRegistrationId());
		}

		Map<Integer, String> idTeacherPhoneMap = this.getMap("sys_user", "id_", "phone_", new ArrayList(teacherExamRoomsMap.keySet()), Integer.class, String.class);
		for (Map.Entry<Integer, List<ExamRoom>> teacherRoomEntry : teacherExamRoomsMap.entrySet()) {
			String teacherPhone = idTeacherPhoneMap.get(teacherRoomEntry.getKey());
			Date examStartTime = teacherRoomEntry.getValue().stream().min(Comparator.comparing(ExamRoom::getExamStartTime)).get().getExamStartTime();
			String examStartTimeStr = DateUtil.dateToString(examStartTime, "MM月dd日 HH时mm分");
			int examRoomNum = teacherRoomEntry.getValue().size();
			Map<Integer, String> phoneMap = new HashMap<>();
			phoneMap.put(teacherRoomEntry.getKey(), teacherPhone);
			sysMessageService.batchSendMessage(MessageTypeEnum.EXAM_ROOM_CONFIRM_TEACHER_SMS,
												phoneMap, null, 0, null, YimeiSmsPlugin.PLUGIN_NAME,
												exam.getName(), examStartTimeStr, examRoomNum);
		}

		if(!CollectionUtils.isEmpty(needUpdateExamRooms)){
			examRoomDao.batchUpdate(needUpdateExamRooms);
		}
		if(!CollectionUtils.isEmpty(examCertifications)){
			examCertificationService.batchInsert(examCertifications);
		}
		if(!CollectionUtils.isEmpty(updateRegistrations)){
			examRegistrationDao.batchUpdate(updateRegistrations);
		}
		if(!CollectionUtils.isEmpty(studentExamResults)){
			studentExamResultDao.batchInsert(studentExamResults);
		}
		return BaseController.succeed("发送成功");
	}

	@Override
	public void tomorrowExamPlanRemind(String day) {
		LocalDate tomorrowDate = LocalDate.now().plusDays(1);
		String tomorrowDateStr = tomorrowDate.toString();
		if(StringUtils.isNotBlank(day)){
			tomorrowDateStr = day;
		}
		List<ExamRoomStudentRelation> tomorrowExamStudents = examRoomStudentRelationDao.getTomorrowExamStudents(tomorrowDateStr);
		if(CollectionUtils.isEmpty(tomorrowExamStudents)){
			return;
		}

		Set<Integer> allStudentIds = tomorrowExamStudents.stream().map(ExamRoomStudentRelation::getStudentId).collect(Collectors.toSet());
		Map<Integer, String> idPhoneMap = this.getMap("sys_user", "id_", "phone_", new ArrayList(allStudentIds), Integer.class, String.class);

		Map<Long, List<ExamRoomStudentRelation>> examRoomStudentMap = tomorrowExamStudents.stream().collect(Collectors.groupingBy(ExamRoomStudentRelation::getExamRoomId));

		Map<Integer, List<ExamRoom>> teacherExamRoomsMap = new HashMap<>();

		for (Map.Entry<Long, List<ExamRoomStudentRelation>> examRoomStudentEntry : examRoomStudentMap.entrySet()) {
			List<ExamRoomStudentRelation> students = examRoomStudentEntry.getValue();
			Set<Integer> studentIds = students.stream().map(ExamRoomStudentRelation::getStudentId).collect(Collectors.toSet());
			if(CollectionUtils.isEmpty(studentIds)){
				continue;
			}
			ExamRoom examRoom=students.get(0);
			examRoom.setId(students.get(0).getExamRoomId());

			if(!teacherExamRoomsMap.containsKey(examRoom.getMainTeacherUserId())){
				teacherExamRoomsMap.put(examRoom.getMainTeacherUserId(), new ArrayList<>());
			}
			teacherExamRoomsMap.get(examRoom.getMainTeacherUserId()).add(examRoom);
			if(StringUtils.isNotBlank(examRoom.getAssistantTeacherUserIdList())){
				Set<Integer> assistantTeacherIds = Arrays.stream(examRoom.getAssistantTeacherUserIdList().split(",")).map(e -> Integer.valueOf(e)).collect(Collectors.toSet());
				for (Integer assistantTeacherId : assistantTeacherIds) {
					if(!teacherExamRoomsMap.containsKey(assistantTeacherId)){
						teacherExamRoomsMap.put(assistantTeacherId, new ArrayList<>());
					}
					teacherExamRoomsMap.get(assistantTeacherId).add(examRoom);
				}
			}

			Map<Integer, String> receiverMap = studentIds.stream().collect(Collectors.toMap(e->e, e->e.toString()));
			Map<Integer, String> phoneMap = idPhoneMap.entrySet().stream().filter(e->studentIds.contains(e.getKey())).collect(Collectors.toMap(e->e.getKey(), e->e.getValue()));

			String examDayStr = DateUtil.dateToString(examRoom.getExamStartTime(), "MM月dd日");
			StringBuffer examTimeStr = new StringBuffer();
			examTimeStr.append(DateUtil.dateToString(examRoom.getExamStartTime(), "HH时mm分"));


			sysMessageService.batchSendMessage(MessageTypeEnum.BEFORE_EXAM_STUDENT_REMIND_PUSH,
					receiverMap, null, 0, null, JiguangPushPlugin.PLUGIN_NAME,
					examDayStr, examTimeStr.toString());
			sysMessageService.batchSendMessage(MessageTypeEnum.BEFORE_EXAM_STUDENT_REMIND_SMS,
					phoneMap, null, 0, null, YimeiSmsPlugin.PLUGIN_NAME,
					examDayStr, examTimeStr.toString());
		}

		String tomorrowDayStr=tomorrowDate.format(DateTimeFormatter.ofPattern("MM月dd日"));
		Map<Integer, String> idTeacherPhoneMap = this.getMap("sys_user", "id_", "phone_", new ArrayList(teacherExamRoomsMap.keySet()), Integer.class, String.class);
		for (Map.Entry<Integer, List<ExamRoom>> teacherRoomEntry : teacherExamRoomsMap.entrySet()) {
			String teacherPhone = idTeacherPhoneMap.get(teacherRoomEntry.getKey());
			Date examStartTime = teacherRoomEntry.getValue().stream().min(Comparator.comparing(ExamRoom::getExamStartTime)).get().getExamStartTime();
			String examStartTimeStr = DateUtil.dateToString(examStartTime, "HH时mm分");
			Date examEndTime = teacherRoomEntry.getValue().stream().max(Comparator.comparing(ExamRoom::getExamEndTime)).get().getExamEndTime();
			String examEndTimeStr = DateUtil.dateToString(examEndTime, "HH时mm分");
			int examRoomNum = teacherRoomEntry.getValue().size();
			Map<Integer, String> phoneMap = new HashMap<>();
			phoneMap.put(teacherRoomEntry.getKey(), teacherPhone);
			sysMessageService.batchSendMessage(MessageTypeEnum.BEFORE_EXAM_TEACHER_REMIND_SMS,
					phoneMap, null, 0, null, YimeiSmsPlugin.PLUGIN_NAME,
					tomorrowDayStr, examStartTimeStr, examEndTimeStr, examRoomNum);
		}
	}

	@Override
	public ExamRoomStatisticsDto getExamRoomStatisticsInfo(Integer organId, Long examId) {
		ExamRoomStatisticsDto examRoomStatisticsInfo=new ExamRoomStatisticsDto();

        List<Integer> childOrganIds = organizationService.getChildOrganIds(organId, true);

		examRoomStatisticsInfo.setTotalRegistrationStudentNum(examRegistrationDao.countTotalRegistrationStudentNumWithExam(childOrganIds, examId));
		examRoomStatisticsInfo.setInRoomStudentNum(examRegistrationDao.countInExamRoomStudentNum(childOrganIds, examId));

		List<ExamRoom> examRooms = examRoomDao.getWithExam(childOrganIds, examId);
		if(!CollectionUtils.isEmpty(examRooms)){
			examRoomStatisticsInfo.setExamRoomNum(examRooms.size());
			examRoomStatisticsInfo.setFirstExamTime(examRooms.stream().min(Comparator.comparing(ExamRoom::getExamStartTime)).get().getExamStartTime());
			examRoomStatisticsInfo.setLastExamTime(examRooms.stream().max(Comparator.comparing(ExamRoom::getExamStartTime)).get().getExamStartTime());
			Set<Integer> teacherIds=new HashSet<>();
			for (ExamRoom examRoom : examRooms) {
				if(Objects.nonNull(examRoom.getMainTeacherUserId())){
					teacherIds.add(examRoom.getMainTeacherUserId());
				}
				if(StringUtils.isNotBlank(examRoom.getAssistantTeacherUserIdList())){
					Set<Integer> assistantTeacherIds = Arrays.stream(examRoom.getAssistantTeacherUserIdList().split(",")).map(e -> Integer.valueOf(e)).collect(Collectors.toSet());
					teacherIds.addAll(assistantTeacherIds);
				}
			}
			examRoomStatisticsInfo.setExamRoomTeacherNum(teacherIds.size());
		}

        return examRoomStatisticsInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void checkRoomTeachers(List<ExamRoom> examRooms) {
		if(CollectionUtils.isEmpty(examRooms)){
			throw new BizException("考场信息异常");
		}
		Set<String> days=new HashSet<>();
		Map<Integer, List<ExamRoom>> teacherRoomMap = new HashMap<>();
		for (ExamRoom examRoom : examRooms) {
			if(Objects.nonNull(examRoom.getExamStartTime())){
				days.add(DateUtil.dateToString(examRoom.getExamStartTime(), "yyyy-MM-dd"));
			}
			if(Objects.nonNull(examRoom.getExamEndTime())){
				days.add(DateUtil.dateToString(examRoom.getExamEndTime(), "yyyy-MM-dd"));
			}
			if(Objects.nonNull(examRoom.getMainTeacherUserId())&&!teacherRoomMap.containsKey(examRoom.getMainTeacherUserId())){
				List<ExamRoom> teacherExamRooms=new ArrayList<>();
				teacherExamRooms.add(examRoom);
				teacherRoomMap.put(examRoom.getMainTeacherUserId(), teacherExamRooms);
			}else if(teacherRoomMap.containsKey(examRoom.getMainTeacherUserId())){
				teacherRoomMap.get(examRoom.getMainTeacherUserId()).add(examRoom);
			}
			if(StringUtils.isBlank(examRoom.getAssistantTeacherUserIdList())){
				continue;
			}
			String[] teacherStrIds = examRoom.getAssistantTeacherUserIdList().split(",");
			for (String teacherStrId : teacherStrIds) {
				if(!teacherRoomMap.containsKey(Integer.valueOf(teacherStrId))){
					List<ExamRoom> teacherExamRooms=new ArrayList<>();
					teacherExamRooms.add(examRoom);
					teacherRoomMap.put(Integer.valueOf(teacherStrId), teacherExamRooms);
				}else if(teacherRoomMap.containsKey(Integer.valueOf(teacherStrId))){
					teacherRoomMap.get(Integer.valueOf(teacherStrId)).add(examRoom);
				}
			}
		}
		if(CollectionUtils.isEmpty(days)){
			throw new BizException("考场信息异常");
		}
		List<ExamRoom> withDays = examRoomDao.getWithDays(new ArrayList<>(days));
		for (ExamRoom examRoom : withDays) {
			if(teacherRoomMap.containsKey(examRoom.getMainTeacherUserId())){
				teacherRoomMap.get(examRoom.getMainTeacherUserId()).add(examRoom);
			}
			if(StringUtils.isBlank(examRoom.getAssistantTeacherUserIdList())){
				continue;
			}
			String[] teacherStrIds = examRoom.getAssistantTeacherUserIdList().split(",");
			for (String teacherStrId : teacherStrIds) {
				if(teacherRoomMap.containsKey(Integer.valueOf(teacherStrId))){
					teacherRoomMap.get(Integer.valueOf(teacherStrId)).add(examRoom);
				}
			}
		}

		for (Map.Entry<Integer, List<ExamRoom>> teacherRoomEntry : teacherRoomMap.entrySet()) {
			List<ExamRoom> teacherRooms = teacherRoomEntry.getValue();
			teacherRooms.sort(Comparator.comparing(ExamRoom::getExamStartTime));
			for (int i = 0; i < teacherRooms.size(); i++) {
				if(i==0){
					continue;
				}
				ExamRoom preExamRoom=teacherRooms.get(i-1);
				ExamRoom currentExamRoom = teacherRooms.get(i);
				if(Objects.nonNull(preExamRoom.getId())&&preExamRoom.getId().equals(currentExamRoom.getId())){
					continue;
				}
				if(preExamRoom.getExamEndTime().compareTo(currentExamRoom.getExamStartTime())>0){
					SysUser sysUser = sysUserDao.get(teacherRoomEntry.getKey());
					throw new BizException("{}教师时间存在冲突", sysUser.getRealName());
				}
			}
		}
	}

	@Override
	public List<ExamRoom> getStudentEnableJoinRoom(Long registId) {
		if(Objects.isNull(registId)){
			throw new BizException("请指定报名信息");
		}
		ExamRegistration examRegistration = examRegistrationDao.get(registId);
		if(Objects.isNull(examRegistration)){
			throw new BizException("报名信息不存在");
		}
		return examRoomDao.getWithExamAndSubject(examRegistration.getExaminationBasicId(), examRegistration.getSubjectId());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void changeExamRoom(Long examRoomId, Integer openFlag) {
		ExamRoom examRoom = examRoomDao.get(examRoomId);
		examRoom.setId(examRoomId);
		examRoom.setOpenFlag(openFlag);
		if(StringUtils.isEmpty(examRoom.getAssistantTeacherUserIdList())){
			examRoom.setShieldUserId(examRoom.getMainTeacherUserId().toString());
		}else {
			examRoom.setShieldUserId(examRoom.getMainTeacherUserId() + "," + examRoom.getAssistantTeacherUserIdList());
		}
		if(openFlag == 0){
			examRoom.setExamFlag(openFlag);
		}
		examRoomDao.update(examRoom);
		SysUser sysUser = sysUserFeignService.queryUserInfo();
		//加群退群
		if(openFlag == 1){
			String studentIds = examRoomStudentRelationService.getStudentIds(examRoomId);
			StringBuffer stringBuffer = new StringBuffer();
			stringBuffer.append(examRoom.getMainTeacherUserId());
			ExaminationBasic examinationBasic = examinationBasicDao.get(examRoom.getExaminationBasicId());
			if(StringUtils.isNotEmpty(studentIds)){
				stringBuffer.append(",").append(studentIds);
			}
			if(StringUtils.isNotEmpty(examRoom.getAssistantTeacherUserIdList())){
				stringBuffer.append(",").append(examRoom.getAssistantTeacherUserIdList());
			}
			imFeignService.joinGroup(stringBuffer.toString(),examRoomId.toString(),examRoomId.toString());
			PublishMessageDto publishMessageDto = new PublishMessageDto();
			publishMessageDto.setUserId(sysUser.getId().toString());
			publishMessageDto.setRoomId(examRoomId.toString());
			MemberChangedMessage msg = new MemberChangedMessage(5, sysUser.getId().toString(),3);
			msg.setWaitNum(0);
			msg.setClassroomSwitch(0);
			msg.setOpenFlag(openFlag);
			Map<String,Object> paramMap = new HashMap<>(1);
			paramMap.put("studentQueue",examRoomStudentRelationService.queryNeedCheckingList(examRoomId));
			msg.setWebParamJson(JSONObject.toJSONString(paramMap));
			publishMessageDto.setMemberChangedMessage(msg);
			imFeignService.publishMessage(publishMessageDto);
			if(StringUtils.isNotEmpty(studentIds)){
				List<RoomStudentListDto> roomStudentListDtos = examRoomStudentRelationDao.queryStudentList(examRoomId);
//				List<ExamRoomStudentRelation> studentRelations = examRoomStudentRelationDao.findStudentsWithExamRoom(examRoomId);
				roomStudentListDtos.forEach(e->{
					Map<Integer, String> userPhoneMap = new HashMap<>(1);
					userPhoneMap.put(e.getStudentId(),e.getStudentId().toString());
					String notifyUrl = "3?examRegistrationId=" + e.getExamRegistrationId();
					sysMessageService.batchSendMessage(MessageTypeEnum.ACTION_EXAM_SIGN_PUSH,
							userPhoneMap, null, 0, notifyUrl, JiguangPushPlugin.PLUGIN_NAME,examinationBasic.getName());
				});
			}
			if(StringUtils.isNotEmpty(examRoom.getAssistantTeacherUserIdList())){
				String[] split = examRoom.getAssistantTeacherUserIdList().split(",");
				ArrayList<String> strings = new ArrayList<>(Arrays.asList(split));
				Map<Integer, String> map = getMap("sys_user", "id_", "phone_", strings, Integer.class, String.class);
				//给助教老师发送短信提醒
				sysMessageService.batchSendMessage(MessageTypeEnum.EXAM_ROOM_OPEN_SMS,
						map,null,null,null,YimeiSmsPlugin.PLUGIN_NAME,examinationBasic.getName());
			}
		}else {
			//没有未考试的学员
			Integer num = examRoomStudentRelationService.countSignInNum(examRoomId);
			if(num != null && num > 0){
				throw new BizException("操作失败：当前还有学员未考试");
			}
			//没有未评审的学员
//			HashMap<String,Object> map = new HashMap();
//			map.put("reviewFlag",0);
//			map.put("teacherId",examRoom.getMainTeacherUserId());
//			examReviewDao.countExamReviewRecordList(map);
			int i = examReviewDao.getCloseFlag(examRoomId);
			if(i > 0){
				throw new BizException("操作失败：还有老师没完成评审");
			}
//			imFeignService.dismissGroup(sysUser.getId().toString(),examRoomId.toString());
			studentExamResultService.calculateStudentExamAvgScore(examRoomId);
			imFeignService.destroyRoom(examRoomId,sysUser.getId().toString());
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public HttpResponseResult forceCloseExamRoom(Long examRoomId) {
		if(Objects.isNull(examRoomId)){
			throw new BizException("请指定考场");
		}
		ExamRoom examRoom = examRoomDao.get(examRoomId);
		if(Objects.isNull(examRoom)){
			throw new BizException("考场不存在");
		}
		examRoom.setOpenFlag(0);
//		imFeignService.dismissGroup(examRoom.getMainTeacherUserId().toString(),examRoomId.toString());
		imFeignService.destroyRoom(examRoomId,examRoom.getMainTeacherUserId().toString());
		examRoomDao.update(examRoom);
		studentExamResultService.calculateStudentExamAvgScore(examRoomId);
		return BaseController.succeed();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void cleanExamRoom() {
		List<ExamRoom> examRooms = examRoomDao.getHistoryOpenExamRoom();
		if(CollectionUtils.isEmpty(examRooms)){
			return;
		}
		for (ExamRoom examRoom : examRooms) {
			examRoom.setOpenFlag(0);
//			imFeignService.dismissGroup(examRoom.getMainTeacherUserId().toString(),examRoom.getId().toString());
			imFeignService.destroyRoom(examRoom.getId(),examRoom.getMainTeacherUserId().toString());
			studentExamResultService.calculateStudentExamAvgScore(examRoom.getId());
		}
		examRoomDao.batchUpdate(examRooms);
	}
}
