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

import com.ym.mec.biz.dal.dao.CourseScheduleDao;
import com.ym.mec.biz.dal.dto.ClassDateAdjustDto;
import com.ym.mec.biz.dal.dto.CourseScheduleDto;
import com.ym.mec.biz.dal.dto.TeacherAttendanceDto;
import com.ym.mec.biz.dal.entity.CourseSchedule;
import com.ym.mec.biz.dal.enums.ParamEnum;
import com.ym.mec.biz.service.CourseScheduleService;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.service.impl.BaseServiceImpl;

import com.ym.mec.common.utils.DateUtils;
import io.swagger.models.auth.In;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CourseScheduleServiceImpl extends BaseServiceImpl<Long, CourseSchedule>  implements CourseScheduleService {
	
	@Autowired
	private CourseScheduleDao courseScheduleDao;

	@Override
	public BaseDAO<Long, CourseSchedule> getDAO() {
		return courseScheduleDao;
	}

	@Override
	public TeacherAttendanceDto getCurrentCourseDetail(Long courseID) {
		TeacherAttendanceDto currentCourseDetail = courseScheduleDao.getCurrentCourseDetail(courseID);
		currentCourseDetail.setCurrentTime(new Date());
		currentCourseDetail.setTeacherAttendanceTimeGap(ParamEnum.TEACHER_ATTENDANCE_TIME_GAP);
		return currentCourseDetail;
	}

	@Override
	public void batchAddCourseSchedule(List<CourseSchedule> courseSchedules) {
		checkCourseSchedule(courseSchedules);
		courseScheduleDao.batchAddCourseSchedules(courseSchedules);
	}

	@Override
	public void batchUpdateCourseSchedule(List<CourseSchedule> courseSchedules, Long musicGroupID) {
		checkCourseSchedule(courseSchedules);
        courseScheduleDao.deleteCourseSchedulesByMusicGroupID(musicGroupID);
        courseScheduleDao.batchAddCourseSchedules(courseSchedules);
	}

	@Override
	public List<CourseScheduleDto> getCourseSchedulesWithDate(Date classDate) {
		return courseScheduleDao.getCourseSchedulesWithDate(classDate);
	}

	@Override
	public List<Date> getCourseScheduleDateByMonth(Long musicGroupID, Date month) {
		return courseScheduleDao.getCourseScheduleDateByMonth(musicGroupID,month);
	}

	/**
	 * 判断课程安排中是否存在冲突
	 * 计算课程课次
	 * @param courseSchedules
	 * @return
	 */
	private void checkCourseSchedule(List<CourseSchedule> courseSchedules){
		Map<Date, List<CourseSchedule>> collect = courseSchedules.stream().collect(Collectors.groupingBy(CourseSchedule::getClassDate));
		for(Date keyDate:collect.keySet()){
			List<CourseSchedule> currentCourses=collect.get(keyDate);
			Map<Date, List<CourseSchedule>> collect1 = currentCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getStartClassTime));
			if(currentCourses.size()==collect1.size()){
				continue;
			}else{
				for(Date keyDate2:collect1.keySet()){
					List<CourseSchedule> currentCourses1=collect1.get(keyDate2);
					if(currentCourses1.size()>ParamEnum.ONE.getCode()){
						Map<Long, List<CourseSchedule>> collect2 = currentCourses1.stream().collect(
								Collectors.groupingBy(CourseSchedule::getTeacherId));
						for (Long teacherID:collect2.keySet()){
							if(collect2.get(teacherID).size()>ParamEnum.ONE.getCode()){
								throw new BizException(new SimpleDateFormat("yyyy-MM-dd").format(keyDate)+"日的课程安排在教师分配上有冲突!");
							}
						}
						List<Integer> repeatClassGroupIds = currentCourses1.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
						Integer[] counts=courseScheduleDao.countStudentInClass(repeatClassGroupIds);
						for (Integer i:counts){
							if (i>ParamEnum.ONE.getCode()){
								throw new BizException(new SimpleDateFormat("yyyy-MM-dd").format(keyDate)+"日的课程安排有学生重复!");
							}
						}
					}
				}
			}
		}
		//课次创建
//		Map<Integer, List<CourseSchedule>> classGroupByID = courseSchedules.stream().collect(Collectors.groupingBy(CourseSchedule::getClassGroupId));
//		List<Long> ids=new ArrayList<>();
//		for (Integer key:classGroupByID.keySet()){
//			ids.add(Long.valueOf(key));
//		}
//		Map<Integer, Integer> maxClassTimes = convertToMap(courseScheduleDao.getMaxClassTimeByClassIds(ids));
//		courseSchedules.clear();
//		for (Integer key:classGroupByID.keySet()){
//			Integer maxClassTime = null == maxClassTimes.get(key) ? 0 : maxClassTimes.get(key);
//			for(CourseSchedule courseSchedule:classGroupByID.get(key)){
//				courseSchedules.add(courseSchedule);
//			}
//		}
	}

	private Map<Integer,Integer> convertToMap(String[] result){
		Map<Integer,Integer> map=new HashMap<>();
		for(String s:result){
			map.put(Integer.valueOf(s.split(",")[0]),Integer.valueOf(s.split(",")[1]));
		}
		return map;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void classStartDateAdjust(ClassDateAdjustDto classDateAdjustDto) {
		//单次调整课时
		if(null==classDateAdjustDto.getAdjustStartTime()&&null==classDateAdjustDto.getAdjustEndTime()){
			ArrayList<Date> dates = new ArrayList<>();
			dates.add(classDateAdjustDto.getClassDate());
			List<CourseSchedule> coursesByDates = courseScheduleDao.findOverLapCoursesInDay(dates,classDateAdjustDto.getStartClassTime(),classDateAdjustDto.getEndClassTime());
			//判断是否存在同时间上课的班级
			if(null==coursesByDates||coursesByDates.size()<=0){
				courseScheduleDao.update(classDateAdjustDto);
			}else{
				coursesByDates.forEach(courseSchedule -> {
					if(courseSchedule.getTeacherId().equals(classDateAdjustDto.getTeacherId())){
						//存在时间重叠，需要前端重新调整
						throw new BizException("所选教师在当天课程安排上存在重叠!");
					}
				});
				List<Integer> repeatClassGroupIds = coursesByDates.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
				checkStudentIsRepeat(repeatClassGroupIds);
				courseScheduleDao.update(classDateAdjustDto);
			}
		}else{
			//根据时间段调整课时
			List<Date> dates= DateUtils.getWeekDays(classDateAdjustDto.getAdjustStartTime(),classDateAdjustDto.getAdjustEndTime(),classDateAdjustDto.getWeekNum());
			List<CourseSchedule> coursesByDates = courseScheduleDao.findOverLapCoursesInDay(dates,classDateAdjustDto.getStartClassTime(),classDateAdjustDto.getEndClassTime());
			//判断是否存在同时间上课的班级
			if(null==coursesByDates||coursesByDates.size()<=0){
				createNewCourseByAdjust(dates,classDateAdjustDto);
			}else{
				//判断教师是否在时间安排上存在冲突
				SimpleDateFormat s1=new SimpleDateFormat("yyyy-MM-dd"),
						s2=new SimpleDateFormat("HH:mm:ss"),
						s3=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				List<CourseSchedule> teacherCoursesInDates = courseScheduleDao.findTeacherCoursesInDates(dates, classDateAdjustDto.getTeacherId());
				teacherCoursesInDates.forEach(courseSchedule -> {
					Date updateStartClassTime = null,updateEndClassTime=null;
					try {
						updateStartClassTime=s3.parse(s1.format(courseSchedule.getClassDate())+" "+s2.format(classDateAdjustDto.getStartClassTime()));
						updateEndClassTime=s3.parse(s1.format(courseSchedule.getClassDate())+" "+s2.format(classDateAdjustDto.getEndClassTime()));
					} catch (ParseException e) {
						e.printStackTrace();
					}
					boolean isDuplication=(courseSchedule.getStartClassTime().after(updateStartClassTime)
							&&courseSchedule.getStartClassTime().before(updateEndClassTime))
							||(updateStartClassTime.after(courseSchedule.getStartClassTime())
							&&updateStartClassTime.before(courseSchedule.getEndClassTime()));
					if(isDuplication){
						throw new BizException("在所选时段内教师上课时间存在重复！");
					}

				});
				//判断学生在时间安排上是否存在冲突
				Map<Date, List<CourseSchedule>> collect = coursesByDates.stream().collect(Collectors.groupingBy(CourseSchedule::getClassDate));
				for(Date keyDate:collect.keySet()){
					List<Integer> repeatClassGroupIds = collect.get(keyDate).stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
					checkStudentIsRepeat(repeatClassGroupIds);
				}
				createNewCourseByAdjust(dates,classDateAdjustDto);
			}
		}
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void courseSwap(Long courseScheduleId1, Long courseScheduleId2) {
		List<CourseSchedule> courseSchedules = courseScheduleDao.findCourseSchedulesByIds(new Long[]{courseScheduleId1, courseScheduleId2});
		CourseSchedule temp=new CourseSchedule();
		BeanUtils.copyProperties(courseSchedules.get(0),temp);
		courseSchedules.get(0).setClassDate(courseSchedules.get(1).getClassDate());
		courseSchedules.get(0).setStartClassTime(courseSchedules.get(1).getStartClassTime());
		courseSchedules.get(0).setEndClassTime(courseSchedules.get(1).getEndClassTime());
		courseSchedules.get(1).setClassDate(temp.getClassDate());
		courseSchedules.get(1).setStartClassTime(temp.getStartClassTime());
		courseSchedules.get(1).setEndClassTime(temp.getEndClassTime());
		courseScheduleDao.update(courseSchedules.get(0));
		courseScheduleDao.update(courseSchedules.get(1));
	}

    @Override
    public List<CourseSchedule> findClassGroupCourseSchedules(List classGroupList) {
		return courseScheduleDao.findClassGroupCourseSchedules(classGroupList);
    }

    /**
	 * @Author: Joburgess
	 * @Date: 2019/9/24
	 * 检测学生是否存在重复
	 */
	private void checkStudentIsRepeat(List<Integer> studentIds){
		Integer[] counts=courseScheduleDao.countStudentInClass(studentIds);
		for (Integer i:counts){
			if (i>ParamEnum.ONE.getCode()){
				throw new BizException("所选课程安排日期有学生重复!");
			}
		}
	}

	/**
	 * @Author: Joburgess
	 * @Date: 2019/9/24
	 * 根据课时调整信息增加新课程
	 */
	private void createNewCourseByAdjust(List<Date> dates,ClassDateAdjustDto classDateAdjustDto){
		CourseSchedule schedule=courseScheduleDao.get(classDateAdjustDto.getId());
		List<CourseSchedule> courseSchedules=new ArrayList<>();
		courseScheduleDao.delete(classDateAdjustDto.getId());
		for (Date date:dates){
			CourseSchedule courseSchedule=new CourseSchedule();
			BeanUtils.copyProperties(schedule,courseSchedule);
			courseSchedule.setClassDate(date);
			courseSchedule.setStartClassTime(classDateAdjustDto.getStartClassTime());
			courseSchedule.setEndClassTime(classDateAdjustDto.getEndClassTime());
			courseSchedule.setTeacherId(classDateAdjustDto.getTeacherId());
			courseSchedules.add(courseSchedule);
		}
		courseScheduleDao.batchAddCourseSchedules(courseSchedules);
	}

}