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

import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.dal.dto.VipGroupGiveCourseSortDto;
import com.ym.mec.biz.dal.entity.*;
import com.ym.mec.biz.dal.enums.GroupType;
import com.ym.mec.biz.dal.enums.TeachModeEnum;
import com.ym.mec.biz.dal.enums.VipGroupActivityTypeEnum;
import com.ym.mec.biz.dal.enums.VipGroupStatusEnum;
import com.ym.mec.biz.service.CourseScheduleStudentPaymentService;
import com.ym.mec.biz.service.SysUserCashAccountService;
import com.ym.mec.common.constant.CommonConstants;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.service.impl.BaseServiceImpl;
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.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CourseScheduleStudentPaymentServiceImpl extends BaseServiceImpl<Long, CourseScheduleStudentPayment>  implements CourseScheduleStudentPaymentService {
	
	@Autowired
	private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
	@Autowired
	private VipGroupDao vipGroupDao;
	@Autowired
	private VipGroupActivityDao vipGroupActivityDao;
	@Autowired
	private CourseScheduleDao courseScheduleDao;
	@Autowired
	private ClassGroupStudentMapperDao classGroupStudentMapperDao;
	@Autowired
	private SysUserCashAccountService sysUserCashAccountService;

	@Override
	public BaseDAO<Long, CourseScheduleStudentPayment> getDAO() {
		return courseScheduleStudentPaymentDao;
	}

	@Override
	public int createCourseScheduleStudentPaymentForVipGroup(Long vipGroupId, Integer userId) {
		VipGroup vipGroupApplyBaseInfoDto=vipGroupDao.get(vipGroupId);

		if(Objects.isNull(vipGroupApplyBaseInfoDto)){
			throw new BizException("未找到相关vip课程");
		}

		//获取活动信息
		VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroupApplyBaseInfoDto.getVipGroupActivityId().intValue());

		List<CourseSchedule> vipGroupCourseSchedules=courseScheduleDao.findGroupCourseSchedules(vipGroupId,GroupType.VIP.getCode());

		if(CollectionUtils.isEmpty(vipGroupCourseSchedules)){
			throw new BizException("未获取到排课信息");
		}

        int giveClassTimes=0;
        if(vipGroupApplyBaseInfoDto.getStatus().equals(VipGroupStatusEnum.APPLYING)
                &&Objects.nonNull(vipGroupActivity)
                &&vipGroupActivity.getType().equals(VipGroupActivityTypeEnum.GIVE_CLASS)
                &&vipGroupCourseSchedules.size()>=Integer.parseInt(vipGroupActivity.getAttribute1())){
            giveClassTimes=Integer.parseInt(vipGroupActivity.getAttribute2());
        }

		List<CourseScheduleStudentPayment> courseScheduleStudentPayments=new ArrayList<>();
		Map<TeachModeEnum, List<CourseSchedule>> courseScheduleGroupByTeachMode = vipGroupCourseSchedules.stream().collect(Collectors.groupingBy(CourseSchedule::getTeachMode));
		for(TeachModeEnum teachModeEnum:courseScheduleGroupByTeachMode.keySet()){
			List<CourseSchedule> courseSchedules = courseScheduleGroupByTeachMode.get(teachModeEnum)
					.stream()
					.sorted(Comparator.comparing(CourseSchedule::getStartClassTime)).collect(Collectors.toList());
			for(int i=0;i<courseSchedules.size();i++) {
				//创建学生课程应缴费记录
				CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
				courseScheduleStudentPayment.setUserId(userId);
	            courseScheduleStudentPayment.setGroupType(courseSchedules.get(i).getGroupType());
	            courseScheduleStudentPayment.setMusicGroupId(courseSchedules.get(i).getMusicGroupId());
				courseScheduleStudentPayment.setCourseScheduleId(courseSchedules.get(i).getId());
				courseScheduleStudentPayment.setClassGroupId(courseSchedules.get(i).getClassGroupId());

				if (teachModeEnum == TeachModeEnum.ONLINE) {
					//学生线上单节课应缴费计算
					switch (vipGroupActivity.getType()) {
						case BASE_ACTIVITY:
							courseScheduleStudentPayment.setExpectPrice(vipGroupApplyBaseInfoDto.getOnlineClassesUnitPrice());
							break;
						case DISCOUNT:
							courseScheduleStudentPayment.setExpectPrice(
									vipGroupApplyBaseInfoDto.getOnlineClassesUnitPrice().multiply(
											new BigDecimal(vipGroupActivity.getAttribute1())
													.divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).setScale(CommonConstants.DECIMAL_FINAL_PLACE,BigDecimal.ROUND_HALF_UP)
									)
							);
							break;
						case GIVE_CLASS:
							if (vipGroupApplyBaseInfoDto.getGiveTeachMode() == teachModeEnum
									&& i >= (courseSchedules.size()-giveClassTimes)) {
								courseScheduleStudentPayment.setExpectPrice(new BigDecimal(0));
							} else {
								courseScheduleStudentPayment.setExpectPrice(vipGroupApplyBaseInfoDto.getOnlineClassesUnitPrice());
							}
							break;
						default:
							throw new BizException("活动类型错误!");
					}
				}else{
					//学生线下单节课应缴费计算
					switch (vipGroupActivity.getType()) {
						case BASE_ACTIVITY:
							courseScheduleStudentPayment.setExpectPrice(vipGroupApplyBaseInfoDto.getOfflineClassesUnitPrice());
							break;
						case DISCOUNT:
							courseScheduleStudentPayment.setExpectPrice(
									vipGroupApplyBaseInfoDto.getOfflineClassesUnitPrice().multiply(
											new BigDecimal(vipGroupActivity.getAttribute1())
													.divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).setScale(CommonConstants.DECIMAL_FINAL_PLACE,BigDecimal.ROUND_HALF_UP)
									)
							);
							break;
						case GIVE_CLASS:
							if (vipGroupApplyBaseInfoDto.getGiveTeachMode() == teachModeEnum
                                    && i >= (courseSchedules.size()-giveClassTimes)) {
								courseScheduleStudentPayment.setExpectPrice(new BigDecimal(0));
							} else {
								courseScheduleStudentPayment.setExpectPrice(vipGroupApplyBaseInfoDto.getOfflineClassesUnitPrice());
							}
							break;
						default:
							throw new BizException("活动类型错误!");
					}
				}
				courseScheduleStudentPayments.add(courseScheduleStudentPayment);
			}
		}
		return courseScheduleStudentPaymentDao.batchInsert(courseScheduleStudentPayments);
	}

    @Override
    public int deleteStudentCourseSchedule(Integer userId, List<CourseSchedule> courseScheduleList) {
		return courseScheduleStudentPaymentDao.deleteStudentCourseSchedule(userId,courseScheduleList);
    }

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void createCourseScheduleStudentPaymentByCourseSchedules(List<CourseSchedule> courseSchedules) {
		if(CollectionUtils.isEmpty(courseSchedules)){
			return;
		}

		List<CourseScheduleStudentPayment> courseScheduleStudentPayments=new ArrayList<>();

		BigDecimal zeroPrice=new BigDecimal(0);

		//班级编号列表
		List<Integer> classGroupIds = courseSchedules.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
		Map<Integer, List<CourseSchedule>> courseSchedulesByClassGroupMap = courseSchedules.stream().collect(Collectors.groupingBy(CourseSchedule::getClassGroupId));

		//班级学生对应列表
		List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findByClassGroups(classGroupIds);
		Map<Integer, List<ClassGroupStudentMapper>> studentsByClassMap = classGroupStudentMappers.stream().collect(Collectors.groupingBy(ClassGroupStudentMapper::getClassGroupId));

		courseSchedulesByClassGroupMap.forEach((classGroupId,courseSchedulesByClassGroup)->{
			List<ClassGroupStudentMapper> studentsWithClassGroup = studentsByClassMap.get(classGroupId);
			if(CollectionUtils.isEmpty(studentsWithClassGroup)){
				return;
			}
			studentsWithClassGroup.forEach(classGroupStudent->{
				VipGroup vipGroup=null;
				if(classGroupStudent.getGroupType().equals(GroupType.VIP)){
					vipGroup=vipGroupDao.get(Long.valueOf(classGroupStudent.getMusicGroupId()));
				}
				for (CourseSchedule courseSchedule : courseSchedulesByClassGroup) {
					int i = courseScheduleStudentPaymentDao.checkStudentHaveCourse(courseSchedule.getId(), classGroupStudent.getUserId());
					if(i>0){
						continue;
					}
					if(courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.VIP)){
						CourseScheduleStudentPayment courseScheduleStudentPayment=new CourseScheduleStudentPayment(
								courseSchedule.getId(),
								classGroupStudent.getUserId(),
								courseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)?vipGroup.getOnlineClassesUnitPrice():vipGroup.getOfflineClassesUnitPrice(),
								courseSchedule.getClassGroupId()
						);
						courseScheduleStudentPayment.setGroupType(classGroupStudent.getGroupType());
						courseScheduleStudentPayment.setMusicGroupId(classGroupStudent.getMusicGroupId());
						List<CourseScheduleStudentPayment> otherPayments = courseScheduleStudentPaymentDao.findByCourseSchedule(courseSchedule.getId());
						if(!CollectionUtils.isEmpty(otherPayments)){
							courseScheduleStudentPayment.setExpectPrice(otherPayments.get(0).getExpectPrice());
						}
						if(Objects.isNull(courseScheduleStudentPayment.getExpectPrice())){
							courseScheduleStudentPayment.setExpectPrice(zeroPrice);
						}
						sysUserCashAccountService.appendCourseBalance(classGroupStudent.getUserId(), courseScheduleStudentPayment.getExpectPrice().negate());
						courseScheduleStudentPayments.add(courseScheduleStudentPayment);
					}else{
						CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment(
								courseSchedule.getId(),
								classGroupStudent.getUserId(),
								zeroPrice,
								courseSchedule.getClassGroupId());
						courseScheduleStudentPayment.setGroupType(classGroupStudent.getGroupType());
						courseScheduleStudentPayment.setMusicGroupId(classGroupStudent.getMusicGroupId());
						courseScheduleStudentPayments.add(courseScheduleStudentPayment);
					}
				}
			});
		});
		if(!CollectionUtils.isEmpty(courseScheduleStudentPayments)){
			courseScheduleStudentPaymentDao.batchInsert(courseScheduleStudentPayments);
		}
	}

	@Override
	public int batchInsert(List<CourseScheduleStudentPayment> courseScheduleStudentPayments) {
		return courseScheduleStudentPaymentDao.batchInsert(courseScheduleStudentPayments);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateVipGiveCourse(Long vipGroupId) {
		List<VipGroupGiveCourseSortDto> vipGroupSortCourseByGroup = courseScheduleStudentPaymentDao.findVipGroupSortCourseByGroup(vipGroupId.toString());
		Map<Integer, List<VipGroupGiveCourseSortDto>> userCourseMap = vipGroupSortCourseByGroup.stream().collect(Collectors.groupingBy(VipGroupGiveCourseSortDto::getUserId));

        BigDecimal zero = new BigDecimal("0.00");

		List<CourseScheduleStudentPayment> needUpdatePayments=new ArrayList<>();
		for (Map.Entry<Integer, List<VipGroupGiveCourseSortDto>> integerListEntry : userCourseMap.entrySet()) {
			List<VipGroupGiveCourseSortDto> courses = integerListEntry.getValue();
			Map<BigDecimal, Long> expectPriceCountMap = courses.stream()
					.collect(Collectors.groupingBy(VipGroupGiveCourseSortDto::getExpectPrice, Collectors.counting()));
			Long zeroPriceNum = expectPriceCountMap.get(zero);
			if(Objects.isNull(zeroPriceNum)||zeroPriceNum<=0){
				break;
			}

			List<VipGroupGiveCourseSortDto> zeroExpectPricePayments = courses.stream()
					.filter(vipGroupGiveCourseSortDto -> vipGroupGiveCourseSortDto.getExpectPrice().compareTo(zero)==0)
					.collect(Collectors.toList());

			courses.sort(Comparator.comparing(VipGroupGiveCourseSortDto::getCourseStartTime).reversed());
			for (int i=0;i<courses.size();i++) {
				if(i>zeroExpectPricePayments.size()-1){
					break;
				}

				VipGroupGiveCourseSortDto vipGroupGiveCourseSortDto=courses.get(i);

				if(!vipGroupGiveCourseSortDto.getId().equals(zeroExpectPricePayments.get(i).getId())
						&&!vipGroupGiveCourseSortDto.getTeachMode().equals(zeroExpectPricePayments.get(i).getTeachMode())){
					throw new BizException("不支持将不同教学形式的课程调整到赠送课时后");
				}

				if(!vipGroupGiveCourseSortDto.getId().equals(zeroExpectPricePayments.get(i).getId())){
					needUpdatePayments.add(new CourseScheduleStudentPayment(vipGroupGiveCourseSortDto.getId(),zeroExpectPricePayments.get(i).getCourseScheduleId()));
					needUpdatePayments.add(new CourseScheduleStudentPayment(zeroExpectPricePayments.get(i).getId(),vipGroupGiveCourseSortDto.getCourseScheduleId()));
				}
			}
		}

		if(!CollectionUtils.isEmpty(needUpdatePayments)){
			courseScheduleStudentPaymentDao.batchUpdate(needUpdatePayments);
		}
	}
}
