package com.ym.mec.biz.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ym.mec.auth.api.client.SysUserFeignService;
import com.ym.mec.auth.api.entity.SysUser;
import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.dal.dto.*;
import com.ym.mec.biz.dal.entity.*;
import com.ym.mec.biz.dal.enums.*;
import com.ym.mec.biz.dal.page.TeacherAttendanceComplaintsQueryInfo;
import com.ym.mec.biz.dal.page.TeacherCloseQueryInfo;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.redis.service.RedisCache;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext.MessageSender;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.ym.mec.biz.dal.enums.ComplaintsStatusEnum.REPEAL;
import static com.ym.mec.biz.dal.enums.SignInStatusEnum.*;

@Service
public class TeacherAttendanceServiceImpl extends BaseServiceImpl<Long, TeacherAttendance>  implements TeacherAttendanceService {

	@Autowired
	private TeacherAttendanceDao teacherAttendanceDao;
	@Autowired
	private StudentAttendanceDao studentAttendanceDao;
	@Autowired
	private CourseScheduleDao courseScheduleDao;
	@Autowired
	private TeacherDao teacherDao;
	@Autowired
	private CourseHomeworkService courseHomeworkService;
	@Autowired
	private StudentCourseHomeworkDao studentCourseHomeworkDao;
	@Autowired
	private SysUserFeignService sysUserFeignService;
	@Autowired
	private CourseScheduleService courseScheduleService;
	@Autowired
	private SysConfigDao sysConfigDao;
	@Autowired
	private SysConfigService sysConfigService;
	@Autowired
	private SysMessageService sysMessageService;
	@Autowired
	private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
	@Autowired
	private ClassGroupDao classGroupDao;
	@Autowired
	private SubjectDao subjectDao;
	@Autowired
	private SchoolDao schoolDao;

	@Autowired
	private RedisCache<String,Object> redisCache;

	@Autowired
	private CourseHomeworkDao courseHomeworkDao;

	@Autowired
	private StudentServeService studentServeService;

	@Override
	public BaseDAO<Long, TeacherAttendance> getDAO() {
		return teacherAttendanceDao;
	}

	@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
	@Override
	public Map<String, Object> addTeacherAttendanceRecord(TeacherSignOutDto teacherSignOutDto) {
		SysUser user = sysUserFeignService.queryUserInfo();
		teacherDao.getLocked(user.getId());
		if(Objects.isNull(user)){
			throw new BizException("请登录");
		}

		if(Objects.isNull(teacherSignOutDto.getTeacherAttendanceInfo().getCourseScheduleId())){
			throw new BizException("请选择课程!");
		}

		Map<String,Object> result=new HashMap<>();

		TeacherAttendance teacherAttendance=teacherAttendanceDao.findByTeacherAttendanceInfo(user.getId().longValue(),teacherSignOutDto.getTeacherAttendanceInfo().getCourseScheduleId());

		Date date = new Date();
		if(Objects.isNull(teacherAttendance)){
			teacherAttendance=teacherSignOutDto.getTeacherAttendanceInfo();
			teacherAttendance.setTeacherId(user.getId());
			teacherAttendance.setCreateTime(date);
		}else if(teacherAttendance.getSignInTime() != null && teacherAttendance.getSignOutTime() != null){
			throw new BizException("当前课程已签到");
		}

		TeacherAttendanceDto currentCourseDetail = courseScheduleDao.getCurrentCourseDetail(teacherSignOutDto.getTeacherAttendanceInfo().getCourseScheduleId(),user.getId());
		if(Objects.isNull(currentCourseDetail)){
			throw new BizException("课程不存在");
		}

		teacherAttendance.setMusicGroupId(currentCourseDetail.getMusicGroupId());
		teacherAttendance.setClassGroupId(currentCourseDetail.getClassId());
		teacherAttendance.setRemark(teacherSignOutDto.getTeacherAttendanceInfo().getRemark());
		teacherAttendance.setSignOutRemark(teacherSignOutDto.getTeacherAttendanceInfo().getSignOutRemark());
		int advanceSignMinutes = Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ADVANCE_SIGN_IN_MINUTES));
		int advanceSignOutMinutes = Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ADVANCE_SIGN_OUT_MINUTES));
		int offlineSignInEarlyForwardTime = Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.OFFLINE_SIGN_IN_EARLY_FORWARD_TIME));

		CourseSchedule courseSchedule = courseScheduleDao.get(teacherAttendance.getCourseScheduleId());
		teacherAttendance.setGroupType(courseSchedule.getGroupType());
		if(courseSchedule == null){
			throw new BizException("课程信息不存在");
		}

		Date tomorrow = DateUtil.addDays1(date, 1);

		if(tomorrow.before(courseSchedule.getStartClassTime())){
			throw new BizException("明天的课程不能进行签到");
		}

		School school = schoolDao.get(courseSchedule.getSchoolId());

		String classDate = DateUtil.format(courseSchedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
		String startClassTime = DateUtil.format(courseSchedule.getStartClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
		String endClassTime = DateUtil.format(courseSchedule.getEndClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
		//上课时间
		Date classStartDateTime = DateUtil.stringToDate(classDate + " " + startClassTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
		Date classEndDateTime = DateUtil.stringToDate(classDate + " " + endClassTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
		Date classEndDateAdd60Minutes = DateUtil.addMinutes(classEndDateTime, advanceSignOutMinutes);
		Date add60Minutes = DateUtil.addMinutes(classStartDateTime, offlineSignInEarlyForwardTime * -1);
		Date add20Minutes = DateUtil.addMinutes(classStartDateTime, advanceSignMinutes * -1);
		if(teacherAttendance.getSignInTime() == null && teacherSignOutDto.getTeacherAttendanceInfo().getStatus().equals(SignStatusEnum.SIGN_IN.getCode())){

			if(StringUtils.isBlank(teacherSignOutDto.getTeacherAttendanceInfo().getSignInLongitudeLatitude())){
				throw new BizException("未获取到您的位置");
			}

			//是否在范围内
			boolean isInScore = true;
			if(StringUtils.isBlank(school.getLongitudeLatitude())){
				if(teacherSignOutDto.getTeacherAttendanceInfo().getUpdate().equals(YesOrNoEnum.YES.getCode())){
					school.setLongitudeLatitude(teacherSignOutDto.getTeacherAttendanceInfo().getSignInLongitudeLatitude());
					schoolDao.update(school);
				}else{
					isInScore = false;
				}
			}else{
			    teacherAttendance.setSignInLongitudeLatitude(teacherSignOutDto.getTeacherAttendanceInfo().getSignInLongitudeLatitude());
				SysConfig sysConfig = sysConfigService.findByParamName(SysConfigService.ATTENDANCE_RANGE);
				double attendanceRange = Double.valueOf(sysConfig.getParanValue());
				double distance = MapUtil.distance(teacherSignOutDto.getTeacherAttendanceInfo().getSignInLongitudeLatitude(),
						school.getLongitudeLatitude());
				if(distance>attendanceRange){
					isInScore=false;
				}
			}

			teacherAttendance.setCurrentClassTimes(courseScheduleDao.countCurrentTimes(teacherAttendance.getClassGroupId(),courseSchedule.getStartClassTime()) + 1);
			teacherAttendance.setSignInLongitudeLatitude(teacherSignOutDto.getTeacherAttendanceInfo().getSignInLongitudeLatitude());
			if (currentCourseDetail.getEndClassTime().before(date)){
				throw new BizException("该课程已结束，不能进行签到!");
			}

			boolean enableIgnoreAttendanceTime = false;
			if(Objects.nonNull(courseSchedule.getSchoolId())){
				enableIgnoreAttendanceTime = courseScheduleService.enableIgnoreAttendanceTime(currentCourseDetail.getStartClassTime(),
						user.getId(),
						currentCourseDetail.getSchoolId().intValue());
			}
			teacherAttendance.setSignInTime(date);
			teacherAttendance.setSignInStatus(YesOrNoEnum.YES);
			result.put("signInStatus",0);
			if(!isInScore){
				teacherAttendance.setSignInStatus(YesOrNoEnum.NO);
			}else if(enableIgnoreAttendanceTime){
				//连堂课，可忽略正常时间签到范围
			}else if(date.compareTo(add20Minutes) <= 0&&date.compareTo(add60Minutes)>=0){
				//正常签到范围(开始前60分钟  ~  开始之前20分钟)
				if(!isInScore){
					teacherAttendance.setSignInStatus(YesOrNoEnum.NO);
				}
			}else if(date.compareTo(add20Minutes) > 0){
				//异常签到范围(开始之后  ~  结束之前)
				teacherAttendance.setSignInStatus(YesOrNoEnum.NO);
				result.put("signInStatus",1);
			}else {
				throw new BizException("签到时间异常");
			}
			if(YesOrNoEnum.NO.equals(teacherAttendance.getSignInStatus())&&StringUtils.isEmpty(teacherAttendance.getRemark())&&!teacherSignOutDto.isNotRturnErrorInfo()){
				//当前为异常签到，请填写原因!
				result.put("status",2);
				return result;
			}
			teacherAttendance.setSignInDeviceNo(teacherSignOutDto.getTeacherAttendanceInfo().getDeviceNum());
			if(Objects.nonNull(teacherAttendance.getId())){
				teacherAttendanceDao.update(teacherAttendance);
			}else{
				teacherAttendanceDao.insert(teacherAttendance);
			}
			return result;
		}else if(teacherAttendance.getSignOutTime() == null && teacherSignOutDto.getTeacherAttendanceInfo().getStatus().equals(SignStatusEnum.SIGN_OUT.getCode())){
			int i = studentAttendanceDao.countByCourseSchedule(courseSchedule.getId());
			if(i<=0){
				throw new BizException("请先点名");
			}

			//是否在范围内
			boolean isInScore = false;
			if(StringUtils.isBlank(school.getLongitudeLatitude())){
				if(teacherSignOutDto.getTeacherAttendanceInfo().getUpdate().equals(YesOrNoEnum.YES.getCode())){
					school.setLongitudeLatitude(teacherSignOutDto.getTeacherAttendanceInfo().getSignInLongitudeLatitude());
					schoolDao.update(school);
				}
			}else if(StringUtils.isNotBlank(teacherSignOutDto.getTeacherAttendanceInfo().getSignOutLongitudeLatitude())){
			    teacherAttendance.setSignOutLongitudeLatitude(teacherSignOutDto.getTeacherAttendanceInfo().getSignOutLongitudeLatitude());
				SysConfig sysConfig = sysConfigService.findByParamName(SysConfigService.ATTENDANCE_RANGE);
				double attendanceRange = Double.valueOf(sysConfig.getParanValue());
				double distance = MapUtil.distance(teacherSignOutDto.getTeacherAttendanceInfo().getSignOutLongitudeLatitude(),
						school.getLongitudeLatitude());
				if(distance<=attendanceRange){
					isInScore=true;
				}
			}

			if(Objects.isNull(teacherAttendance.getSignInTime())){
				throw new BizException("未签到不可点名和签退");
			}

			//正常签退范围（结束后1小时内）
			teacherAttendance.setSignOutTime(date);
			teacherAttendance.setSignOutAttachments(teacherSignOutDto.getCourseHomeworkInfo().getAttachments());
			ClassGroup classGroup = classGroupDao.get(courseSchedule.getClassGroupId());
			teacherAttendance.setCurrentClassTimes(classGroup.getCurrentClassTimes() + 1);
			if(!isInScore){
				teacherAttendance.setSignOutStatus(YesOrNoEnum.NO);
				result.put("signOutStatus",1);
			}else if(date.compareTo(classEndDateTime) >= 0 && date.compareTo(classEndDateAdd60Minutes) <= 0 && DateUtil.isSameDay(date, classEndDateTime)){
				teacherAttendance.setSignOutStatus(YesOrNoEnum.YES);
				result.put("signOutStatus",0);
			}else if(date.compareTo(classEndDateAdd60Minutes) > 0 && DateUtil.isSameDay(date, classEndDateTime)){
				teacherAttendance.setSignOutStatus(YesOrNoEnum.NO);
				result.put("signOutStatus",1);
			}else {
				throw new BizException("签退时间异常");
			}
			if(YesOrNoEnum.NO.equals(teacherAttendance.getSignOutStatus())&&StringUtils.isEmpty(teacherAttendance.getSignOutRemark())&&!teacherSignOutDto.isNotRturnErrorInfo()){
				//当前为异常签退，请填写原因!
				result.put("status",2);
				return result;
			}
			teacherAttendance.setSignOutDeviceNo(teacherSignOutDto.getTeacherAttendanceInfo().getDeviceNum());
			if(Objects.nonNull(teacherAttendance.getId())){
				teacherAttendanceDao.update(teacherAttendance);
			}else{
				teacherAttendanceDao.insert(teacherAttendance);
			}

			if(StringUtils.isNotBlank(teacherSignOutDto.getCourseHomeworkInfo().getContent())){
				CourseHomework courseHomework = courseHomeworkDao.findByCourseSchedule(teacherAttendance.getCourseScheduleId());
				if(Objects.isNull(courseHomework)){
					//新增课堂作业
					courseHomework=teacherSignOutDto.getCourseHomeworkInfo();
					courseHomework.setCourseScheduleId(teacherAttendance.getCourseScheduleId());
					courseHomework.setMusicGroupId(currentCourseDetail.getMusicGroupId());
					courseHomework.setGroupType(teacherAttendance.getGroupType());
					courseHomework.setClassGroupId(currentCourseDetail.getClassId().intValue());
					courseHomework.setExpiryDate(DateUtil.addDays(date,7));

					courseHomeworkService.insert(courseHomework);

					List<StudentCourseHomework> studentCourseHomeworks = studentCourseHomeworkDao
							.constructInitialStudentHomeworkRecordsWithPayment(teacherAttendance.getCourseScheduleId(),
									courseHomework.getId());
					if(CollectionUtils.isEmpty(studentCourseHomeworks)){
						throw new BizException("此课程没有学生");
					}
					Set<Integer> serveStudentIds = studentServeService.getStudentWithCourse(teacherAttendance.getCourseScheduleId());
					Iterator<StudentCourseHomework> iterator = studentCourseHomeworks.iterator();
					while (iterator.hasNext()){
						StudentCourseHomework next = iterator.next();
						if(!serveStudentIds.contains(next.getUserId())){
							iterator.remove();
						}
					}
					courseHomework.setExpectNum(studentCourseHomeworks.size());
					if(!CollectionUtils.isEmpty(studentCourseHomeworks)){
						courseHomeworkService.update(courseHomework);

						studentCourseHomeworkDao.batchInsertStudentCourseHomeworkRecord(studentCourseHomeworks);
						List<Integer> studentIds = studentCourseHomeworks.stream().map(StudentCourseHomework::getUserId).collect(Collectors.toList());
						studentServeService.updateExercisesSituation(courseSchedule.getClassDate(), studentIds, teacherAttendance.getTeacherId());
					}
				}else{
					courseHomework.setContent(teacherSignOutDto.getCourseHomeworkInfo().getContent());
					courseHomework.setAttachments(teacherSignOutDto.getCourseHomeworkInfo().getAttachments());
					courseHomeworkService.update(courseHomework);
				}
			}
			return result;
		}

		result.put("status",0);
		result.put("currentTime",date);

		return result;
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public void addTeacherAttendanceSignOut(Long firstCourseId, Integer userId,String deviceNum) {
		Date date = new Date();
		//签退
		CourseSchedule courseSchedule = courseScheduleDao.get(firstCourseId);
		List<CourseSchedule> courseSchedules = new ArrayList<>();
		courseSchedules.add(courseSchedule);
		CourseSchedule cs = courseSchedule;
		String continueCourseTime = sysConfigDao.findConfigValue(SysConfigService.ONLINE_CONTINUE_COURSE_TIME);
		if(StringUtils.isEmpty(continueCourseTime)){
			continueCourseTime = "5";
		}
		while (true){
			//获取当前课程的所有连堂课列表
			String courseClassDate = DateUtil.format(cs.getClassDate(), DateUtil.DEFAULT_PATTERN);
			String courseEndDateTime = DateUtil.format(cs.getEndClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
			cs = courseScheduleDao.queryTeacherContinueCourse(cs,continueCourseTime,courseClassDate + " " + courseEndDateTime);
			//存在连堂课
			if(cs != null){
				courseSchedules.add(cs);
			}else {
				break;
			}
		}
		String courseClassDate;
		String courseStartDateTime;
		String courseEndDateTime;
		Boolean isBreak = false;
		for (int i = courseSchedules.size() - 1; i >= 0; i--) {
			if(isBreak){
				break;
			}
			CourseSchedule schedule = courseSchedules.get(i);
			courseClassDate = DateUtil.format(schedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
			courseStartDateTime = DateUtil.format(schedule.getStartClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
			Date startDateTime = DateUtil.stringToDate(courseClassDate + " " + courseStartDateTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
			courseEndDateTime = DateUtil.format(schedule.getEndClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
			Date endDateTime = DateUtil.stringToDate(courseClassDate + " " + courseEndDateTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
			//不是最后一节课
			if(i == courseSchedules.size() - 1){
				if(date.after(endDateTime)){
					isBreak = upsetAttendance(userId,startDateTime,date,YesOrNoEnum.YES,schedule,firstCourseId,deviceNum);
				}else {
					isBreak = upsetAttendance(userId,startDateTime,date,YesOrNoEnum.NO,schedule,firstCourseId,deviceNum);
				}
			}else {
				isBreak = upsetAttendance(userId,startDateTime,endDateTime,YesOrNoEnum.YES,schedule,firstCourseId,deviceNum);
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void addTeacherAttendanceSignIn(Long firstCourseId, Integer userId, Long courseScheduleId,String deviceNum) {
		ClassGroup classGroup = classGroupDao.findByCourseSchedule(courseScheduleId.intValue(),0);
		TeacherAttendance teacherAttendance=teacherAttendanceDao.findByTeacherAttendanceInfo(userId.longValue(),courseScheduleId);
		if(Objects.isNull(teacherAttendance)){
			teacherAttendance=new TeacherAttendance();
			teacherAttendance.setGroupType(classGroup.getGroupType());
			teacherAttendance.setCourseScheduleId(courseScheduleId);
			teacherAttendance.setTeacherId(userId);
			teacherAttendance.setMusicGroupId(classGroup.getMusicGroupId());
			teacherAttendance.setClassGroupId(classGroup.getId());
			teacherAttendance.setTeacherId(userId);
			teacherAttendance.setSignInDeviceNo(deviceNum);
			teacherAttendance.setCurrentScheduleId(firstCourseId);
			teacherAttendanceDao.insert(teacherAttendance);
		}else {
			if(StringUtils.isEmpty(teacherAttendance.getSignInDeviceNo())){
				teacherAttendance.setSignInDeviceNo(deviceNum);
			}
			teacherAttendance.setCurrentScheduleId(firstCourseId);
			teacherAttendance.setGroupType(classGroup.getGroupType());
			teacherAttendance.setTeacherId(userId);
			teacherAttendance.setClassGroupId(classGroup.getId());
			teacherAttendance.setMusicGroupId(classGroup.getMusicGroupId());
		}
		//签到
		if(teacherAttendance.getSignInTime() == null){
			Date date = new Date();
			CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleId);
			String classDate = DateUtil.format(courseSchedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
			String startClassTime = DateUtil.format(courseSchedule.getStartClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
			Date classStartDateTime = DateUtil.stringToDate(classDate + " " + startClassTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
			YesOrNoEnum yesOrNoEnum = courseScheduleService.enableOnlyNormalAttendance(courseSchedule.getStartClassTime(),
					userId.longValue(),
					false,
					null);
			teacherAttendance.setSignInTime(date);
			teacherAttendance.setSignInStatus(YesOrNoEnum.YES);
			teacherAttendance.setCurrentClassTimes(classGroup.getCurrentClassTimes() + 1);
			Date add1Minutes = DateUtil.addMinutes(classStartDateTime, -1);
			int secondsBetween = DateUtil.secondsBetween(date, add1Minutes);

			if(yesOrNoEnum != YesOrNoEnum.YES && secondsBetween <= 0){
				teacherAttendance.setSignInStatus(YesOrNoEnum.NO);
			}
			teacherAttendanceDao.update(teacherAttendance);
			if(courseSchedule.getTeachMode() == TeachModeEnum.ONLINE){
				//获取所有当前课程的学生列表
				Map<Integer,String> userMap = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertMybatisMap(courseScheduleDao.findStudentMap(courseScheduleId))),HashMap.class);
				if(userMap != null && userMap.size() > 0){
					String name = subjectDao.findNames(classGroup.getSubjectIdList());
					sysMessageService.batchSendMessage(MessageSender.JIGUANG,MessageTypeEnum.STUDENT_PUSH_ONLINE_COURSE_ACTION,userMap,
							null,0,"6?sealClassId=" + courseScheduleId + "&subjectName=" + name ,"STUDENT",courseSchedule.getName());
				}
			}
		}else if(StringUtils.isNotEmpty(teacherAttendance.getSignInDeviceNo())){
			teacherAttendance.setSignInDeviceNo(deviceNum);
			teacherAttendanceDao.update(teacherAttendance);
		}
	}

	public Boolean upsetAttendance(Integer userId,Date signInTime,Date signOutTime,YesOrNoEnum status,CourseSchedule courseSchedule,Long courseScheduleId,String deviceNum){
		TeacherAttendance teacherAttendance = teacherAttendanceDao.findByTeacherAttendanceInfo(userId.longValue(),courseSchedule.getId());
		Boolean flag = false;
		Long courseId = teacherAttendanceDao.findFirstSign(courseScheduleId,userId);
		//如果当前课程是第一次签到的课程那么不更新签到时间，并且退出下次循环
		if(courseId != null && courseId.equals(courseSchedule.getId())){
			flag = true;
		}
		if(teacherAttendance == null){
			teacherAttendance = new TeacherAttendance();
			teacherAttendance.setGroupType(courseSchedule.getGroupType());
			teacherAttendance.setTeacherId(userId);
			teacherAttendance.setMusicGroupId(courseSchedule.getMusicGroupId());
			teacherAttendance.setClassGroupId(courseSchedule.getClassGroupId());
			teacherAttendance.setCourseScheduleId(courseSchedule.getId());
			teacherAttendance.setSignInStatus(YesOrNoEnum.YES);
			teacherAttendance.setSignOutStatus(status);
			teacherAttendance.setSignOutTime(signOutTime);
			teacherAttendance.setSignInTime(signInTime);
			teacherAttendance.setCurrentScheduleId(courseScheduleId);
			teacherAttendance.setSignInDeviceNo(deviceNum);
			teacherAttendance.setSignOutDeviceNo(deviceNum);
			teacherAttendanceDao.insert(teacherAttendance);
		}else {
			teacherAttendance.setSignOutDeviceNo(deviceNum);
			teacherAttendance.setSignOutStatus(status);
			teacherAttendance.setSignOutTime(signOutTime);
			teacherAttendance.setCurrentScheduleId(courseScheduleId);
			if(!flag){
				teacherAttendance.setSignInTime(signInTime);
				teacherAttendance.setSignInStatus(YesOrNoEnum.YES);
			}
			teacherAttendanceDao.update(teacherAttendance);
		}
		return flag;
	}

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

		List<TeacherPersonalAttendanceDto> dataList = null;
		int count = teacherAttendanceDao.getTeacherPersonalAttendancesCount(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = teacherAttendanceDao.getTeacherPersonalAttendances(params);
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

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

		List<TeacherAttendancesDto> dataList = null;
		int count = teacherAttendanceDao.countTeacherAttendances(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = teacherAttendanceDao.queryTeacherAttendances(params);
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public boolean pushNoSignOutMessage() {
		Integer minutes = Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.SIGN_OUT_MESSAGE_PUSH_MINUTE));;

		List<Mapper> list = teacherAttendanceDao.queryNoSignOutListByOverMinutes(minutes);
		if(CollectionUtils.isEmpty(list)){
			return true;
		}
		List<Long> courseScheduleIds = list.stream().map(m -> m.getCourseScheduleId().longValue()).collect(Collectors.toList());

		List<CourseSchedule> courseSchedules = courseScheduleDao.findByCourseScheduleIds(courseScheduleIds);
		Map<Long, CourseSchedule> idCourseMap = courseSchedules.stream().collect(Collectors.toMap(CourseSchedule::getId, c -> c, (c1, c2) -> c1));

		List<CourseScheduleTeacherSalary> courseScheduleTeacherSalarys = courseScheduleTeacherSalaryDao.findByCourseSchedules(courseScheduleIds);
		Map<Long, List<CourseScheduleTeacherSalary>> courseTeacherSalaryMap = new HashMap<>();
		if(!CollectionUtils.isEmpty(courseScheduleTeacherSalarys)){
			courseTeacherSalaryMap = courseScheduleTeacherSalarys.stream().collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getCourseScheduleId));
		}

		for (Mapper mapper : list) {
			Map<Integer, String> receivers = new HashMap<Integer, String>();
			Integer userId = (Integer) mapper.getKey();
			receivers.put(userId, userId + "");

			String key = "SignOut_" + userId + "_" + mapper.getCourseScheduleId();

			CourseSchedule courseSchedule = idCourseMap.get(mapper.getCourseScheduleId().longValue());

			List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = courseTeacherSalaryMap.get(mapper.getCourseScheduleId().longValue());
			TeachTypeEnum teachType = TeachTypeEnum.BISHOP;
			if(!CollectionUtils.isEmpty(courseScheduleTeacherSalaries)){
				for (CourseScheduleTeacherSalary courseScheduleTeacherSalary : courseScheduleTeacherSalaries) {
					if(mapper.getKey().equals(courseScheduleTeacherSalary.getUserId())){
						teachType = courseScheduleTeacherSalary.getTeacherRole();
					}
				}
			}

			if (!redisCache.exists(key)) {
				sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_SIGN_OUT_MESSAGE, receivers, null, 0,
						"5?courseScheduleId=" + mapper.getCourseScheduleId() + "&teacherRole=" + teachType.getCode(), "TEACHER",
						mapper.getValue() + (Objects.isNull(courseSchedule)?"":("(" + DateUtil.format(courseSchedule.getStartClassTime(), "yyyy年MM月dd日 HH时mm分") + ")")));
				redisCache.put(key, 1, (int) DateUtil.getTomorrowZeroSeconds());
			}
		}
		return true;
	}

	@Override
	public List<TeacherAbnormalAttendanceInfoDto> findTeacherAbnormalSignInCourseScheduleRecord(Integer organId, Date date, Integer signInStatus) {
		return teacherAttendanceDao.findTeacherAbnormalSignInCourseScheduleRecord(organId,date,signInStatus);
	}

	@Override
	public List<Date> findTeacherAbnormalSignInDates(Integer organId, Date date) {
		return teacherAttendanceDao.findTeacherAbnormalSignInDates(organId,date);
	}

	@Override
	public Map countTeacherAbnormalSignInClassTimes(Integer organId, Date date) {
		Map<String,Integer> result=new HashMap<>();
		result.put("abnormalSignInNum",teacherAttendanceDao.countTeacherAbnormalSignInClassTimes(organId,date,YesOrNoEnum.NO.getCode()));
		result.put("noSignInNum",teacherAttendanceDao.countTeacherAbnormalSignInClassTimes(organId,date,null));
		return result;
	}

	@Override
	public TeacherSignOutDto getTeacherSignDetail(Integer courseScheduleId, Integer userId) {
		if(Objects.isNull(courseScheduleId)){
			throw new BizException("请指定课程");
		}
		TeacherSignOutDto teacherSignDetail = new TeacherSignOutDto();
		TeacherAttendance teacherAttendanceInfo = teacherAttendanceDao.findByTeacherAttendanceInfo(userId.longValue(), courseScheduleId.longValue());
		teacherSignDetail.setTeacherAttendanceInfo(teacherAttendanceInfo);
		CourseHomework courseHomewok = courseHomeworkDao.findByCourseSchedule(courseScheduleId.longValue());
		if(Objects.nonNull(teacherAttendanceInfo)&&Objects.nonNull(courseHomewok)){
			courseHomewok.setAttachments(teacherAttendanceInfo.getSignOutAttachments());
		}
		teacherSignDetail.setCourseHomeworkInfo(courseHomewok);
		return teacherSignDetail;
	}

	@Override
	public TeacherAttendance getTeacherPersonalAttendance(Integer courseScheduleId) {
		return teacherAttendanceDao.getMainTeacherAttendance(courseScheduleId);
	}

	@Override
	public void updateTeacherAttendance(TeacherAttendance teacherAttendanceInfo) {
		if(Objects.isNull(teacherAttendanceInfo.getCourseScheduleId())){
			throw new BizException("请指定课程");
		}
		if(Objects.isNull(teacherAttendanceInfo.getSignInStatus())){
			throw new BizException("请指定签到状态");
		}
		if(Objects.isNull(teacherAttendanceInfo.getSignOutStatus())){
			throw new BizException("请指定签退状态");
		}
		CourseSchedule courseSchedule = courseScheduleDao.get(teacherAttendanceInfo.getCourseScheduleId());
		if(Objects.isNull(courseSchedule)){
			throw new BizException("课程不存在");
		}

		List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = courseScheduleTeacherSalaryDao.findByCourseSchedule(teacherAttendanceInfo.getCourseScheduleId());
		if(!CollectionUtils.isEmpty(courseScheduleTeacherSalaries)&&Objects.nonNull(courseScheduleTeacherSalaries.get(0).getSettlementTime())){
			throw new BizException("此课程已结算");
		}

		if(Objects.isNull(teacherAttendanceInfo.getTeacherId())||teacherAttendanceInfo.getTeacherId()<=0){
			if(Objects.isNull(courseSchedule.getActualTeacherId())){
				throw new BizException("请指定教师");
			}
			teacherAttendanceInfo.setTeacherId(courseSchedule.getActualTeacherId());
		}
		TeacherAttendance teacherAttendance=teacherAttendanceDao.findByTeacherAttendanceInfo(teacherAttendanceInfo.getTeacherId().longValue(),teacherAttendanceInfo.getCourseScheduleId());

		Date date = new Date();
		if(Objects.isNull(teacherAttendance)){
			teacherAttendance=new TeacherAttendance();
			teacherAttendance.setGroupType(courseSchedule.getGroupType());
			teacherAttendance.setMusicGroupId(courseSchedule.getMusicGroupId());
			teacherAttendance.setClassGroupId(courseSchedule.getClassGroupId());
			teacherAttendance.setCourseScheduleId(courseSchedule.getId());
			teacherAttendance.setTeacherId(teacherAttendanceInfo.getTeacherId());
			teacherAttendance.setCreateTime(date);
		}
		teacherAttendance.setSignInTime(date);
		teacherAttendance.setSignInStatus(teacherAttendanceInfo.getSignInStatus());
		teacherAttendance.setSignOutTime(date);
		teacherAttendance.setSignOutStatus(teacherAttendanceInfo.getSignOutStatus());

		SysUser sysUser = sysUserFeignService.queryUserInfo();
		StringBuilder remark=new StringBuilder("补签到,");
		remark.append(sysUser.getRealName());
		teacherAttendance.setRemark(remark.toString());

		if(Objects.isNull(teacherAttendance.getId())){
			teacherAttendanceDao.insert(teacherAttendance);
		}else{
			teacherAttendanceDao.update(teacherAttendance);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void cleanCourseTeacherSignOut(Long courseId) {
		teacherAttendanceDao.cleanCourseTeacherSignOut(courseId);
	}

	@Override
	public TeacherAttendance findByTeacherAttendanceInfo(Long courseId, Integer teacherId) {
		return teacherAttendanceDao.findByTeacherAttendanceInfo(teacherId.longValue(),courseId);
	}

	@Override
	public TeacherAttendanceDetailDto getTeacherPersonalAttendanceDetail(Integer courseScheduleId) {
		TeacherAttendance teacherAttendance = teacherAttendanceDao.getMainTeacherAttendance(courseScheduleId);
		CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleId.longValue());
		TeacherAttendanceDetailDto result = new TeacherAttendanceDetailDto();
		result.setStatus(courseSchedule.getStatus());
		result.setTeachMode(courseSchedule.getTeachMode());
		result.setType(courseSchedule.getType());
		result.setTeacherName(teacherDao.queryNameById(courseSchedule.getActualTeacherId()));
		result.setAttendClassTime(teacherAttendanceDao.getAttendClassTime(courseScheduleId));
		result.setSchool(schoolDao.get(courseSchedule.getSchoolId()));
		if(teacherAttendance != null){
			result.setIsSignIn(Objects.isNull(teacherAttendance.getSignInStatus())?3:teacherAttendance.getSignInStatus().getCode());
			result.setIsSignOut(Objects.isNull(teacherAttendance.getSignOutStatus())?3:teacherAttendance.getSignOutStatus().getCode());
			result.setSignInStatusEnum(result.getIsSignIn() == 1?NORMAL:result.getIsSignIn() == 0?UNUSUAL:NO);
			result.setSignOutStatusEnum(result.getIsSignOut() == 1?SignOutStatusEnum.NORMAL:result.getIsSignOut() == 0? SignOutStatusEnum.UNUSUAL: SignOutStatusEnum.NO);
			result.setSignInTime(teacherAttendance.getSignInTime());
			result.setSignOutTime(teacherAttendance.getSignOutTime());
			result.setRemark(teacherAttendance.getRemark());
			int studentNum = studentAttendanceDao.countByCourseSchedule(courseScheduleId.longValue());
			if (Objects.nonNull(studentNum)) {
				result.setIsCallNames(studentNum > 0 ? YesOrNoEnum.YES : YesOrNoEnum.NO);
			} else {
				result.setIsCallNames(YesOrNoEnum.NO);
			}
		}
		return result;
	}

	@Override
	public void pushTeacherExceptionAttendanceTask() {
		Date date = new Date();
		String format = DateUtil.format(date, DateUtil.DEFAULT_PATTERN);
		Set<Integer> teacherId = teacherAttendanceDao.queryTeacherExceptionAttendance(format);
		if(teacherId == null || teacherId.size() == 0){
			return;
		}
		Map<Integer,String> receivers = new HashMap(teacherId.size());
		teacherId.forEach(e->{
			receivers.put(e,e.toString());
		});
		String url = new StringBuffer("10?date=").append(format).toString();
		sysMessageService.batchSendMessage(MessageSender.JIGUANG,MessageTypeEnum.PUSH_TEACHER_EXCEPTION_ATTENDANCE,receivers,null,0,url,"TEACHER",format);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public synchronized void addComplaints(Long courseScheduleId, String content,String url) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if(Objects.isNull(user)){
			throw new BizException("请登录");
		}
		TeacherAttendance teacherAttendance = teacherAttendanceDao.findByTeacherAttendanceInfo(user.getId().longValue(), courseScheduleId);

		CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleId);
		if(courseSchedule == null){
			throw new BizException("课程不存在");
		}
		if(teacherAttendance == null){
			teacherAttendance = new TeacherAttendance();
			teacherAttendance.setMusicGroupId(courseSchedule.getMusicGroupId());
			teacherAttendance.setTeacherId(user.getId());
			teacherAttendance.setClassGroupId(courseSchedule.getClassGroupId());
			teacherAttendance.setGroupType(courseSchedule.getGroupType());
			teacherAttendance.setCourseScheduleId(courseScheduleId);
			teacherAttendanceDao.insert(teacherAttendance);
		}else if(teacherAttendance.getComplaintsStatus() != null && teacherAttendance.getComplaintsStatus() != REPEAL){
            throw new BizException("请勿重复提交考勤申述");
        }
		//如果课程时间在两天前
		Date date = new Date();
        int i = DateUtil.daysBetween(courseSchedule.getClassDate(), DateUtil.stringToDate(DateUtil.format(date,DateUtil.DEFAULT_PATTERN),DateUtil.DEFAULT_PATTERN));
        if(i > 1){
			throw new BizException("超出可申述时间");
		}
		teacherAttendance.setIsComplaints(1);
		teacherAttendance.setComplaintsStatus(ComplaintsStatusEnum.WAIT);
		teacherAttendance.setComplaintsContent(content);
		teacherAttendance.setComplaintsTime(date);
		teacherAttendance.setUrl(url);
		teacherAttendanceDao.update(teacherAttendance);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void repealComplaints(Long courseScheduleId) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if(Objects.isNull(user)){
			throw new BizException("请登录");
		}
		TeacherAttendance teacherAttendance = teacherAttendanceDao.findByTeacherAttendanceInfo(user.getId().longValue(), courseScheduleId);
		if(teacherAttendance == null){
			throw new BizException("考勤信息不存在");
		}
		if(teacherAttendance.getComplaintsStatus() == ComplaintsStatusEnum.WAIT){
			teacherAttendance.setComplaintsStatus(REPEAL);
			teacherAttendanceDao.update(teacherAttendance);
		}else {
			throw new BizException("操作失败: 当前申述状态不允许撤销");
		}
	}

	@Override
	public PageInfo<TeacherAttendanceComplaintsDto> queryTeacherAttendanceComplaints(TeacherAttendanceComplaintsQueryInfo queryInfo) {
		PageInfo<TeacherAttendanceComplaintsDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<>();
		MapUtil.populateMap(params, queryInfo);
		List<TeacherAttendanceComplaintsDto> dataList = null;
		int count = teacherAttendanceDao.countTeacherAttendanceComplaints(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = teacherAttendanceDao.queryTeacherAttendanceComplaints(params);
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void agreeTeacherAttendanceComplaints(Integer signInStatus, Integer signOutStatus, long teacherAttendanceId,String content) {
		TeacherAttendance teacherAttendance = teacherAttendanceDao.get(teacherAttendanceId);
		if(teacherAttendance == null){
			throw new BizException("考勤信息不存在");
		}
		if(teacherAttendance.getComplaintsStatus() == ComplaintsStatusEnum.WAIT){
			if(signInStatus != null && signOutStatus != null){
				teacherAttendance.setUpdateAttendanceEnum(UpdateAttendanceEnum.ALL);
			}else if (signInStatus != null){
				teacherAttendance.setUpdateAttendanceEnum(UpdateAttendanceEnum.SIGN_IN);
			}else if (signOutStatus != null){
				teacherAttendance.setUpdateAttendanceEnum(UpdateAttendanceEnum.SIGN_OUT);
			}
			StringBuffer remark = new StringBuffer("同意异常考勤申述");
			CourseSchedule courseSchedule = courseScheduleDao.get(teacherAttendance.getCourseScheduleId());
			String classDate = DateUtil.format(courseSchedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
			if(signInStatus != null && teacherAttendance.getSignInStatus() != YesOrNoEnum.YES){
				if(teacherAttendance.getSignInTime() != null){
					remark.append("  原签到时间: ").append(DateUtil.format(teacherAttendance.getSignInTime(),DateUtil.EXPANDED_DATE_TIME_FORMAT));
				}
				String startTime = DateUtil.format(courseSchedule.getStartClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
				Date date = DateUtil.stringToDate(classDate + ' ' + startTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
				teacherAttendance.setSignInTime(DateUtil.addMinutes(date,-1));
				teacherAttendance.setSignInStatus(YesOrNoEnum.YES);
			}
			if(signOutStatus != null && teacherAttendance.getSignOutStatus() != YesOrNoEnum.YES){
				if(teacherAttendance.getSignOutTime() != null){
					remark.append("  原签退时间: ").append(DateUtil.format(teacherAttendance.getSignOutTime(),DateUtil.EXPANDED_DATE_TIME_FORMAT));
				}
				String endTime = DateUtil.format(courseSchedule.getEndClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
				Date date = DateUtil.stringToDate(classDate + ' ' + endTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
				teacherAttendance.setSignOutTime(date);
				teacherAttendance.setSignOutStatus(YesOrNoEnum.YES);
			}
			teacherAttendance.setDisposeContent(content);
			SysUser user = sysUserFeignService.queryUserInfo();
			if(user != null && user.getId() != null){
				teacherAttendance.setOperator(user.getId());
			}
			teacherAttendance.setComplaintsStatus(ComplaintsStatusEnum.PASS);
			teacherAttendance.setRemark(remark.toString());
			teacherAttendanceDao.update(teacherAttendance);
			String format = DateUtil.format(courseSchedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
			Map<Integer, String> receivers = new HashMap<>(1);
			receivers.put(teacherAttendance.getTeacherId(),teacherAttendance.getTeacherId().toString());
			sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_ATTENDANCE_COMPLAINTS_RESULT, receivers, null, 0, null, "TEACHER",
					format,courseSchedule.getName(),"通过");
		}else {
			throw new BizException("操作失败: 当前申述状态不允许该操作");
		}
	}

	@Override
	public void rejectTeacherAttendanceComplaints(long teacherAttendanceId,String content) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if(Objects.isNull(user)){
			throw new BizException("请登录");
		}
		TeacherAttendance teacherAttendance = teacherAttendanceDao.get(teacherAttendanceId);
		if(teacherAttendance == null){
			throw new BizException("考勤信息不存在");
		}
		if(teacherAttendance.getComplaintsStatus() == ComplaintsStatusEnum.WAIT){
			teacherAttendance.setDisposeContent(content);
			teacherAttendance.setOperator(user.getId());
			teacherAttendance.setComplaintsStatus(ComplaintsStatusEnum.REJECT);
			teacherAttendanceDao.update(teacherAttendance);
			CourseSchedule courseSchedule = courseScheduleDao.get(teacherAttendance.getCourseScheduleId());
			String format = DateUtil.format(courseSchedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
			Map<Integer, String> receivers = new HashMap<>(1);
			receivers.put(teacherAttendance.getTeacherId(),teacherAttendance.getTeacherId().toString());
			sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_ATTENDANCE_COMPLAINTS_RESULT, receivers, null, 0, null, "TEACHER",
					format,courseSchedule.getName(),"拒绝");
		}else {
			throw new BizException("操作失败: 当前申述状态不允许该操作");
		}
	}
}
