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

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.ym.mec.auth.api.client.SysUserFeignService;
import com.ym.mec.auth.api.entity.SysUser;
import com.ym.mec.biz.dal.dao.ClassGroupDao;
import com.ym.mec.biz.dal.dao.ClassGroupStudentMapperDao;
import com.ym.mec.biz.dal.dao.ClassGroupTeacherMapperDao;
import com.ym.mec.biz.dal.dao.ClassGroupTeacherSalaryDao;
import com.ym.mec.biz.dal.dao.CourseScheduleDao;
import com.ym.mec.biz.dal.dao.CourseScheduleTeacherSalaryDao;
import com.ym.mec.biz.dal.dao.StudentApplyRefundsDao;
import com.ym.mec.biz.dal.dao.StudentPaymentOrderDao;
import com.ym.mec.biz.dal.dao.StudentVipGroupPaymentDao;
import com.ym.mec.biz.dal.dao.SubjectDao;
import com.ym.mec.biz.dal.dao.SysUserCashAccountDetailDao;
import com.ym.mec.biz.dal.dao.TeacherDefaultVipGroupSalaryDao;
import com.ym.mec.biz.dal.dao.VipGroupActivityDao;
import com.ym.mec.biz.dal.dao.VipGroupCategoryDao;
import com.ym.mec.biz.dal.dao.VipGroupClassGroupMapperDao;
import com.ym.mec.biz.dal.dao.VipGroupDao;
import com.ym.mec.biz.dal.dao.VipGroupDefaultClassesUnitPriceDao;
import com.ym.mec.biz.dal.dto.StudentVipGroupDetailDto;
import com.ym.mec.biz.dal.dto.TeachingRecordBaseInfo;
import com.ym.mec.biz.dal.dto.VipGroupApplyBaseInfoDto;
import com.ym.mec.biz.dal.dto.VipGroupApplyDto;
import com.ym.mec.biz.dal.dto.VipGroupBuyParamsDto;
import com.ym.mec.biz.dal.dto.VipGroupCostCountDto;
import com.ym.mec.biz.dal.dto.VipGroupCostCountParamsDto;
import com.ym.mec.biz.dal.dto.VipGroupManageDetailDto;
import com.ym.mec.biz.dal.dto.VipGroupSalaryBaseInfo;
import com.ym.mec.biz.dal.dto.VipGroupSalaryDto;
import com.ym.mec.biz.dal.dto.VipGroupSalarySettlementDto;
import com.ym.mec.biz.dal.entity.ClassGroup;
import com.ym.mec.biz.dal.entity.ClassGroupTeacherMapper;
import com.ym.mec.biz.dal.entity.ClassGroupTeacherSalary;
import com.ym.mec.biz.dal.entity.CourseSchedule;
import com.ym.mec.biz.dal.entity.CourseSchedule.CourseScheduleType;
import com.ym.mec.biz.dal.entity.StudentApplyRefunds;
import com.ym.mec.biz.dal.entity.StudentPaymentOrder;
import com.ym.mec.biz.dal.entity.StudentVipGroupPayment;
import com.ym.mec.biz.dal.entity.SysUserCashAccount;
import com.ym.mec.biz.dal.entity.SysUserCashAccountDetail;
import com.ym.mec.biz.dal.entity.TeacherDefaultVipGroupSalary;
import com.ym.mec.biz.dal.entity.VipGroup;
import com.ym.mec.biz.dal.entity.VipGroupActivity;
import com.ym.mec.biz.dal.entity.VipGroupCategory;
import com.ym.mec.biz.dal.entity.VipGroupClassGroupMapper;
import com.ym.mec.biz.dal.entity.VipGroupDefaultClassesUnitPrice;
import com.ym.mec.biz.dal.enums.AuditStatusEnum;
import com.ym.mec.biz.dal.enums.ClassGroupTypeEnum;
import com.ym.mec.biz.dal.enums.CourseStatusEnum;
import com.ym.mec.biz.dal.enums.DealStatusEnum;
import com.ym.mec.biz.dal.enums.OrderTypeEnum;
import com.ym.mec.biz.dal.enums.PlatformCashAccountDetailTypeEnum;
import com.ym.mec.biz.dal.enums.TeachModeEnum;
import com.ym.mec.biz.dal.enums.TeachTypeEnum;
import com.ym.mec.biz.dal.enums.VipGroupActivityTypeEnum;
import com.ym.mec.biz.dal.enums.VipGroupStatusEnum;
import com.ym.mec.biz.dal.enums.YesOrNoEnum;
import com.ym.mec.biz.dal.page.StudentVipGroupQueryInfo;
import com.ym.mec.biz.dal.page.VipGroupAttendanceQueryInfo;
import com.ym.mec.biz.dal.page.VipGroupQueryInfo;
import com.ym.mec.biz.dal.page.VipGroupSalaryQueryInfo;
import com.ym.mec.biz.dal.page.VipGroupTeachingRecordQueryInfo;
import com.ym.mec.biz.service.ClassGroupService;
import com.ym.mec.biz.service.CourseScheduleRewardsRulesService;
import com.ym.mec.biz.service.CourseScheduleService;
import com.ym.mec.biz.service.CourseScheduleStudentPaymentService;
import com.ym.mec.biz.service.CourseScheduleTeacherSalaryService;
import com.ym.mec.biz.service.PayService;
import com.ym.mec.biz.service.SysUserCashAccountDetailService;
import com.ym.mec.biz.service.SysUserCashAccountService;
import com.ym.mec.biz.service.VipGroupService;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.entity.ImGroupMember;
import com.ym.mec.common.entity.ImGroupModel;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.im.ImFeignService;
import com.ym.mec.util.collection.MapUtil;

@Service
public class VipGroupServiceImpl extends BaseServiceImpl<Long, VipGroup> implements VipGroupService {
	
	@Autowired
	private VipGroupDao vipGroupDao;
	@Autowired
	private ClassGroupDao classGroupDao;
	@Autowired
	private ClassGroupService classGroupService;
	@Autowired
	private VipGroupClassGroupMapperDao vipGroupClassGroupMapperDao;
	@Autowired
	private ClassGroupTeacherMapperDao classGroupTeacherMapperDao;
	@Autowired
	private CourseScheduleService courseScheduleService;
	@Autowired
	private CourseScheduleDao courseScheduleDao;
	@Autowired
	private VipGroupDefaultClassesUnitPriceDao vipGroupDefaultClassesUnitPriceDao;
	@Autowired
	private VipGroupActivityDao vipGroupActivityDao;
	@Autowired
	private VipGroupCategoryDao vipGroupCategoryDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private TeacherDefaultVipGroupSalaryDao teacherDefaultVipGroupSalaryDao;
    @Autowired
    private StudentPaymentOrderDao studentPaymentOrderDao;
    @Autowired
    private StudentVipGroupPaymentDao studentVipGroupPaymentDao;
    @Autowired
	private StudentApplyRefundsDao studentApplyRefundsDao;
	
	@Autowired
	private SysUserCashAccountService sysUserCashAccountService;

    @Autowired
	private SysUserCashAccountDetailDao sysUserCashAccountDetailDao;
    @Autowired
	private ClassGroupTeacherSalaryDao classGroupTeacherSalaryDao;

    @Autowired
	private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
    @Autowired
	private ImFeignService imFeignService;
    @Autowired
	private SubjectDao subjectDao;
    @Autowired
	private CourseScheduleTeacherSalaryService courseScheduleTeacherSalaryService;
    @Autowired
	private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
	@Autowired
	private PayService payService;
	@Autowired
	private ClassGroupStudentMapperDao classGroupStudentMapperDao;

	@Autowired
	private CourseScheduleRewardsRulesService courseScheduleRewardsRulesService;

	private SysUserCashAccountDetailService sysUserCashAccountDetailService;

	@Override
	public BaseDAO<Long, VipGroup> getDAO() {
		return vipGroupDao;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void createVipGroup(VipGroupApplyDto vipGroup) {

		if (Objects.isNull(vipGroup.getVipGroupApplyBaseInfo().getUserId())){
			throw new BizException("请选择指导老师");
		}

	    if(vipGroup.getCourseSchedules().size()!=(vipGroup.getVipGroupApplyBaseInfo().getOfflineClassesNum()+vipGroup.getVipGroupApplyBaseInfo().getOnlineClassesNum())){
	        throw new BizException("课时总数不匹配!");
        }

        Map<TeachModeEnum, List<CourseSchedule>> courseScheduleGroup = vipGroup.getCourseSchedules().stream().collect(Collectors.groupingBy(CourseSchedule::getTeachMode));

	    if((Objects.isNull(courseScheduleGroup.get(TeachModeEnum.OFFLINE))&&vipGroup.getVipGroupApplyBaseInfo().getOfflineClassesNum()!=0)
				||(!Objects.isNull(courseScheduleGroup.get(TeachModeEnum.OFFLINE))&&(courseScheduleGroup.get(TeachModeEnum.OFFLINE).size()<vipGroup.getVipGroupApplyBaseInfo().getOfflineClassesNum()))){
	        throw new BizException("线下课课时数量安排有误!");
        }
        if((Objects.isNull(courseScheduleGroup.get(TeachModeEnum.ONLINE))&&vipGroup.getVipGroupApplyBaseInfo().getOnlineClassesNum()!=0)
				||(!Objects.isNull(courseScheduleGroup.get(TeachModeEnum.ONLINE))&&(courseScheduleGroup.get(TeachModeEnum.ONLINE).size()<vipGroup.getVipGroupApplyBaseInfo().getOnlineClassesNum()))){
            throw new BizException("线上课课时数量安排有误!");
        }

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

		//生成vip课信息
		VipGroupApplyBaseInfoDto vipGroupApplyBaseInfoDto=vipGroup.getVipGroupApplyBaseInfo();
		List<String> bySubIds = subjectDao.findBySubIds(vipGroupApplyBaseInfoDto.getSubjectIdList());
		StringBuffer className=new StringBuffer(StringUtils.join(bySubIds,","));
		className.append("•");
		className.append(vipGroupApplyBaseInfoDto.getName());
		vipGroupApplyBaseInfoDto.setName(className.toString());
		vipGroupApplyBaseInfoDto.setTotalPrice(countVipGroupPredictFee(vipGroupApplyBaseInfoDto,
				vipGroupApplyBaseInfoDto.getOnlineClassesUnitPrice(),
				vipGroupApplyBaseInfoDto.getOfflineClassesUnitPrice()).get("totalPrice"));
		vipGroupApplyBaseInfoDto.setStatus(VipGroupStatusEnum.APPLYING);
		vipGroupDao.insert(vipGroupApplyBaseInfoDto);

		//获取vip课类型信息
		VipGroupCategory vipGroupCategory = vipGroupCategoryDao.get(vipGroup.getVipGroupApplyBaseInfo().getVipGroupCategoryId().intValue());

		//创建班级信息
		ClassGroup classGroup=new ClassGroup();
		classGroup.setSubjectIdList(vipGroupApplyBaseInfoDto.getSubjectIdList());
		classGroup.setExpectStudentNum(vipGroupCategory.getStudentNum());
		classGroup.setName(vipGroupApplyBaseInfoDto.getName());
		classGroup.setExpectStudentNum(vipGroupApplyBaseInfoDto.getExpectStudentNum());
		classGroup.setTotalClassTimes(vipGroupApplyBaseInfoDto.getOnlineClassesNum()+vipGroupApplyBaseInfoDto.getOfflineClassesNum());
		classGroup.setType(ClassGroupTypeEnum.VIP);
		classGroup.setDelFlag(YesOrNoEnum.NO);
		classGroupDao.insert(classGroup);

		//创建vip课班级关联记录
		VipGroupClassGroupMapper vipGroupClassGroupMapper=new VipGroupClassGroupMapper();
		vipGroupClassGroupMapper.setVipGroupId(vipGroupApplyBaseInfoDto.getId());
		vipGroupClassGroupMapper.setClassGroupId(classGroup.getId());
		vipGroupClassGroupMapperDao.insert(vipGroupClassGroupMapper);

		//创建融云班级群
		// 指导老师加入群组
		ImGroupMember[] imGroupMembers = { new ImGroupMember(vipGroup.getVipGroupApplyBaseInfo().getUserId().toString())};
		// 创建群组
		imFeignService.groupCreate(new ImGroupModel(classGroup.getId().toString(), imGroupMembers, classGroup.getName()));

		//创建班级老师关联记录
		ClassGroupTeacherMapper classGroupTeacherMapper=new ClassGroupTeacherMapper();
		classGroupTeacherMapper.setTeacherRole(TeachTypeEnum.BISHOP);
		classGroupTeacherMapper.setUserId(vipGroupApplyBaseInfoDto.getUserId());
		classGroupTeacherMapperDao.insert(classGroupTeacherMapper);

		//创建班级与老师课酬记录
		ClassGroupTeacherSalary classGroupTeacherSalary=new ClassGroupTeacherSalary();
		classGroupTeacherSalary.setTeacherRole(TeachTypeEnum.BISHOP);
		classGroupTeacherSalary.setUserId(vipGroupApplyBaseInfoDto.getUserId());
		classGroupTeacherSalary.setSalary(vipGroupApplyBaseInfoDto.getOfflineTeacherSalary());
		classGroupTeacherSalary.setOnlineClassesSalary(vipGroupApplyBaseInfoDto.getOnlineTeacherSalary());
		classGroupTeacherSalaryDao.insert(classGroupTeacherSalary);

		//课程信息调整
		vipGroup.getCourseSchedules().forEach(courseSchedule -> {
		    if(courseSchedule.getEndClassTime().after(vipGroupActivity.getCoursesEndTime())
                &&courseSchedule.getStartClassTime().before(vipGroupActivity.getCoursesStartTime())){
		        throw new BizException("课时安排时间超出范围!");
            }
		    courseSchedule.setTeacherId(vipGroupApplyBaseInfoDto.getUserId().longValue());
			courseSchedule.setStatus(CourseStatusEnum.NOT_START);
		    courseSchedule.setType(CourseSchedule.CourseScheduleType.VIP);
			courseSchedule.setClassGroupId(classGroup.getId());
		});
		courseScheduleService.batchAddCourseSchedule(vipGroup.getCourseSchedules());

		//创建老师单节课课酬信息
		courseScheduleTeacherSalaryService.createCourseScheduleTeacherVipSalary(vipGroupApplyBaseInfoDto,
				vipGroup.getCourseSchedules(),
				vipGroupApplyBaseInfoDto.getOnlineTeacherSalary(),
				vipGroupApplyBaseInfoDto.getOfflineTeacherSalary());
	}

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

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

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

		List<VipGroup> dataList = null;
		int count = vipGroupDao.countVipGroupByOrgan(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = vipGroupDao.findAllByOrgan(params);
			List<Long> vipGroupIds = dataList.stream().map(vipGroup -> vipGroup.getId()).collect(Collectors.toList());

		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public Map<String, Object> findVipGroupTeachingRecord(VipGroupTeachingRecordQueryInfo queryInfo) {
		if(Objects.isNull(queryInfo.getVipGroupId())){
			throw new BizException("请指定vip课程!");
		}
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<>();
		MapUtil.populateMap(params, queryInfo);

		List dataList = null;
		int count = vipGroupDao.countTeachingRecord(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = vipGroupDao.findTeachingRecord(params);
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		TeachingRecordBaseInfo classTimes = vipGroupDao.getClassTimes(queryInfo.getVipGroupId());
		classTimes.setIsSalaryNum(vipGroupDao.countIsSalaryNum(queryInfo.getVipGroupId()));
		classTimes.setComplaintsNum(vipGroupDao.countComplaintsNum(queryInfo.getVipGroupId()));
		Map<String,Object> result=new HashMap<>();
		result.put("pageInfo",pageInfo);
		result.put("baseInfo",classTimes);
		return result;
	}

	@Override
	public TeachingRecordBaseInfo findTeachingRecordBaseInfo(Long vipGroupId) {
        TeachingRecordBaseInfo classTimes = vipGroupDao.getClassTimes(vipGroupId);
        classTimes.setIsSalaryNum(vipGroupDao.countIsSalaryNum(vipGroupId));
        classTimes.setComplaintsNum(vipGroupDao.countComplaintsNum(vipGroupId));
        return classTimes;
	}

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

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

	@Override
	public VipGroupManageDetailDto getVipGroupDetail(Long vipGroupId) {
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定vip课程");
		}
		VipGroupManageDetailDto vipGroupBaseInfo = vipGroupDao.getVipGroupBaseInfo(vipGroupId);
		vipGroupBaseInfo.setSubjectName(StringUtils.join(subjectDao.findBySubIds(vipGroupBaseInfo.getSubjectIdList()),","));
		return vipGroupBaseInfo;
	}

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

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

	@Override
	public StudentVipGroupDetailDto getVipGroupShowDetail(Long vipGroupId) {
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定vip课程");
		}
        StudentVipGroupDetailDto vipGroupDetail = vipGroupDao.getVipGroupDetail(vipGroupId);
        vipGroupDetail.setNumberOfClasses(vipGroupDao.countTeacherVipGroups(vipGroupDetail.getTeacherId().longValue()));
        return vipGroupDetail;
	}

	@Override
	public VipGroupCostCountDto vipGroupCostCount(VipGroupCostCountParamsDto vipGroupCostCountParamsDto) {
        SysUser user = sysUserFeignService.queryUserInfo();
        TeacherDefaultVipGroupSalary teacherDefaultVipGroupSalary = teacherDefaultVipGroupSalaryDao.findByTeacherAndCategory(user.getId().longValue(), vipGroupCostCountParamsDto.getVipGroupCategoryId());
        VipGroupDefaultClassesUnitPrice vipGroupDefaultClassesUnitPrice = vipGroupDefaultClassesUnitPriceDao.get(vipGroupCostCountParamsDto.getVipGroupDefaultClassesUnitPriceId().intValue());
		VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroupCostCountParamsDto.getVipGroupActivityId().intValue());
        VipGroupSalarySettlementDto vipGroupSalarySettlementDto = JSON.parseObject(vipGroupActivity.getSalarySettlementJson(), VipGroupSalarySettlementDto.class);
        BigDecimal offlineClassNum=new BigDecimal(vipGroupCostCountParamsDto.getOfflineClassesNum());
        BigDecimal onlineClassNum=new BigDecimal(vipGroupCostCountParamsDto.getOnlineClassesNum());


        //教师课酬
        BigDecimal teacherOnlineSalary,teacherOfflineSalary,teacherSalary;
        switch (vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSalarySettlementType()){
            case TEACHER_DEFAULT:
                teacherOnlineSalary=teacherDefaultVipGroupSalary.getOnlineClassesSalary().multiply(onlineClassNum);
                break;
            case RATIO_DISCOUNT:
                teacherOnlineSalary=vipGroupDefaultClassesUnitPrice.getOnlineClassesUnitPrice().multiply(vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue()).multiply(onlineClassNum);
                break;
            case FIXED_SALARY:
                teacherOnlineSalary=vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue().multiply(onlineClassNum);
                break;
             default:
                 throw new BizException("未指定课酬结算标准!");
        }
        switch (vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSalarySettlementType()){
            case TEACHER_DEFAULT:
                teacherOfflineSalary=teacherDefaultVipGroupSalary.getOfflineClassesSalary().multiply(offlineClassNum);
                break;
            case RATIO_DISCOUNT:
                teacherOfflineSalary=vipGroupDefaultClassesUnitPrice.getOfflineClassesUnitPrice().multiply(vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue()).multiply(offlineClassNum);
                break;
            case FIXED_SALARY:
                teacherOfflineSalary=vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue().multiply(offlineClassNum);
                break;
            default:
                throw new BizException("未指定课酬结算标准!");
        }
        teacherSalary=teacherOnlineSalary.add(teacherOfflineSalary);
        return new VipGroupCostCountDto(null,teacherSalary);
    }

    /**
     * @Author: Joburgess
     * @Date: 2019/10/2
     * 计算VIP课程预计收费
     */
    @Override
    public Map<String,BigDecimal> countVipGroupPredictFee(VipGroup vipGroup,BigDecimal onlineClassesUnitPrice,BigDecimal offlineClassesUnitPrice){
		if(Objects.isNull(vipGroup.getUserId())){
			throw new BizException("请指定教师");
		}

		if(Objects.isNull(vipGroup.getVipGroupCategoryId())){
			throw new BizException("请指定课程形式");
		}

    	TeacherDefaultVipGroupSalary teacherDefaultVipGroupSalary = teacherDefaultVipGroupSalaryDao.findByTeacherAndCategory(vipGroup.getUserId().longValue(),
				vipGroup.getVipGroupCategoryId());

		VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroup.getVipGroupActivityId().intValue());

		if(Objects.isNull(vipGroupActivity)){
			throw new BizException("指定的活动方案不存在");
		}

		VipGroupSalarySettlementDto vipGroupSalarySettlementDto = JSON.parseObject(vipGroupActivity.getSalarySettlementJson(), VipGroupSalarySettlementDto.class);

		if(Objects.isNull(vipGroupSalarySettlementDto)){
			throw new BizException("课酬结算方案错误");
		}

		Map<String,BigDecimal> results=new HashMap<>(1);

		BigDecimal offlineClassNum=new BigDecimal(vipGroup.getOfflineClassesNum());
		BigDecimal onlineClassNum=new BigDecimal(vipGroup.getOnlineClassesNum());
		BigDecimal onlineVipGroupCharge = onlineClassesUnitPrice.multiply(onlineClassNum);
		BigDecimal offlineVipGroupCharge = offlineClassesUnitPrice.multiply(offlineClassNum);

		//教师课酬线上单课酬计算
		switch (vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSalarySettlementType()){
			case TEACHER_DEFAULT:
				if(Objects.isNull(teacherDefaultVipGroupSalary)){
					throw new BizException("未设置教师默认课酬");
				}
				results.put("onlineTeacherSalary",teacherDefaultVipGroupSalary.getOfflineClassesSalary());
				break;
			case RATIO_DISCOUNT:
				results.put("onlineTeacherSalary",onlineClassesUnitPrice.multiply((vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue())));
				break;
			case FIXED_SALARY:
				results.put("onlineTeacherSalary",vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue());
				break;
			default:
				throw new BizException("未指定课酬结算标准!");
		}
		//教师线下单课酬计算
		switch (vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSalarySettlementType()){
			case TEACHER_DEFAULT:
				if(Objects.isNull(teacherDefaultVipGroupSalary)){
					throw new BizException("未设置教师默认课酬");
				}
				results.put("offlineTeacherSalary",teacherDefaultVipGroupSalary.getOfflineClassesSalary());
				break;
			case RATIO_DISCOUNT:
				results.put("offlineTeacherSalary",offlineClassesUnitPrice.multiply(vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue()));
				break;
			case FIXED_SALARY:
				results.put("offlineTeacherSalary",vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue());
				break;
			default:
				throw new BizException("未指定课酬结算标准!");
		}

		//课程购买费用计算
		BigDecimal totalPrice;
		switch (vipGroupActivity.getType()){
			case BASE_ACTIVITY:
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				break;
			case DISCOUNT:
				BigDecimal discount=new BigDecimal(vipGroupActivity.getAttribute1());
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				totalPrice=totalPrice.multiply(discount);
				break;
			case GIVE_CLASS:
				if(vipGroup.getGiveTeachMode()==TeachModeEnum.OFFLINE){
					if(offlineClassNum.compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))>-1){
						offlineClassNum=offlineClassNum.subtract(new BigDecimal(vipGroupActivity.getAttribute2()));
					}
					offlineVipGroupCharge = offlineClassesUnitPrice.multiply(offlineClassNum);
				}else if(vipGroup.getGiveTeachMode()==TeachModeEnum.ONLINE){
					if(onlineClassNum.compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))>-1){
						onlineClassNum=onlineClassNum.subtract(new BigDecimal(vipGroupActivity.getAttribute2()));
					}
					onlineVipGroupCharge = onlineClassesUnitPrice.multiply(onlineClassNum);
				}else{
					throw new BizException("请指定赠送课程类型!");
				}
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				break;
			default:
				throw new BizException("活动类型错误!");
		}
		results.put("totalPrice",totalPrice);
        return results;
    }

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Map buyVipGroup(VipGroupBuyParamsDto vipGroupBuyParams) throws Exception {
		SysUser user = sysUserFeignService.queryUserInfo();

		StudentPaymentOrder byStudentVipGroup = studentPaymentOrderDao.findByStudentVipGroup(vipGroupBuyParams.getVipGroupId(), user.getId().longValue());

		if(Objects.nonNull(byStudentVipGroup)){
			throw new BizException("订单已存在!");
		}

		VipGroup vipGroup = vipGroupDao.get(vipGroupBuyParams.getVipGroupId());

		if(vipGroup.getStatus()!=VipGroupStatusEnum.APPLYING){
			throw new BizException("该课程已结束报名!");
		}

		VipGroupClassGroupMapper vipGroupClassGroupMapper = vipGroupClassGroupMapperDao.findByVipGroupId(vipGroup.getId());

		VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroup.getVipGroupActivityId().intValue());
		StudentPaymentOrder studentPaymentOrder=new StudentPaymentOrder();
		studentPaymentOrder.setUserId(user.getId());
		String orderNo=StringUtils.join(new String[]{user.getId().toString(),String.valueOf(System.currentTimeMillis())});
		studentPaymentOrder.setOrderNo(orderNo);
		studentPaymentOrder.setType(OrderTypeEnum.SMALL_CLASS_TO_BUY);
		studentPaymentOrder.setExpectAmount(vipGroup.getTotalPrice());
		if(vipGroupActivity.getType()==VipGroupActivityTypeEnum.DISCOUNT){
			studentPaymentOrder.setActualAmount(studentPaymentOrder.getExpectAmount().multiply(new BigDecimal(vipGroupActivity.getAttribute1())));
		}else{
			studentPaymentOrder.setActualAmount(studentPaymentOrder.getExpectAmount());
		}
		studentPaymentOrder.setMusicGroupId(vipGroup.getId().toString());
		studentPaymentOrder.setClassGroupId(vipGroupClassGroupMapper.getClassGroupId());
		studentPaymentOrderDao.insert(studentPaymentOrder);

		StudentVipGroupPayment studentVipGroupPayment=new StudentVipGroupPayment();
		studentVipGroupPayment.setUserId(user.getId());
		studentVipGroupPayment.setVipGroupId(vipGroup.getId());
		studentVipGroupPayment.setClassGroupId(vipGroupClassGroupMapper.getClassGroupId());
		studentVipGroupPayment.setStudentPaymentOrderId(studentPaymentOrder.getId());
		studentVipGroupPaymentDao.insert(studentVipGroupPayment);

		//更新班级人数，如果订单支付失败则减少
		classGroupService.updateClassStudentNum(vipGroupClassGroupMapper.getClassGroupId().longValue(),1);

		//生成回调地址
		Map payMap = payService.getPayMap(
				vipGroup.getTotalPrice(),
				orderNo,
				"https://pay.dayaedu.com/api/yqpay/notify",
				"http://dev.dayaedu.com",
				"vip课购买",
				vipGroup.getName());

		return payMap;

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void orderCallback(String callbackParams) {
		/*
		根据回调信息调整订单状态及vip课程状态等相关信息
		 */
		Long vipGroupId=1L,userId=1L;

		VipGroup vipGroup = vipGroupDao.get(vipGroupId);

		//生成学生单课缴费信息
		courseScheduleStudentPaymentService.createCourseScheduleStudentPaymentForVipGroup(vipGroupId,userId);

		VipGroupClassGroupMapper vipGroupClassGroupMapper = vipGroupClassGroupMapperDao.findByVipGroupId(vipGroupId);

		//更新订单状态
		StudentPaymentOrder studentPaymentOrder=studentPaymentOrderDao.findByStudentVipGroup(vipGroupId,userId);
		studentPaymentOrder.setStatus(DealStatusEnum.SUCCESS);
		studentPaymentOrderDao.update(studentPaymentOrder);

		//将学生加入到班级，更新班级报名状态及人数信息
		ClassGroup classGroup = classGroupDao.get(vipGroupClassGroupMapper.getClassGroupId());
		int classStudents = classGroupDao.countClassStudent(vipGroupClassGroupMapper.getClassGroupId().longValue());
		if(classGroup.getExpectStudentNum()==classStudents){
			vipGroup.setStatus(VipGroupStatusEnum.FINISH);
			vipGroupDao.update(vipGroup);
		}
		classGroup.setStudentNum(classGroup.getStudentNum()+1);
		classGroupDao.update(classGroup);

	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void applyRefund(Long vipGroupId,Long studentId) {
		SysUser sysUser=sysUserFeignService.queryUserInfo();
    	if(null==studentId){
    		studentId=sysUser.getId().longValue();
		}
		StudentApplyRefunds studentApplyRefunds=new StudentApplyRefunds();
		StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.findByStudentVipGroup(vipGroupId,studentId);
		if(null==studentPaymentOrder){
			throw new BizException("未找到相关订单信息！");
		}
		VipGroup vipGroup=vipGroupDao.get(vipGroupId);
		//剩余课时数
		Map surplusClassTimes=MapUtil.convertMybatisMap(vipGroupDao.countSurplusClassTimes(vipGroupId));
		studentApplyRefunds.setExpectAmount(countVipGroupPredictFee(vipGroup,
				new BigDecimal(surplusClassTimes.get(TeachModeEnum.ONLINE.getCode()).toString()),
				new BigDecimal(surplusClassTimes.get(TeachModeEnum.OFFLINE.getCode()).toString())).get("totalPrice"));
		studentApplyRefunds.setStatus(AuditStatusEnum.ING);
		String orderNo=StringUtils.join(new String[]{studentId.toString(),String.valueOf(System.currentTimeMillis())});
		studentApplyRefunds.setOrderNo(orderNo);
		studentApplyRefunds.setOrigPaymentOrderId(studentPaymentOrder.getId());
		studentApplyRefunds.setUserId(studentId.intValue());
		studentApplyRefundsDao.insert(studentApplyRefunds);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void applyRefundAudit(StudentApplyRefunds studentApplyRefunds) {
    	if(Objects.isNull(studentApplyRefunds.getId())){
    		throw new BizException("请指定退费订单!");
		}

		StudentApplyRefunds oldStudentApplyRefunds=studentApplyRefundsDao.get(studentApplyRefunds.getId());

		StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.get(oldStudentApplyRefunds.getOrigPaymentOrderId());
		if(null==studentPaymentOrder){
			throw new BizException("未找到原订单信息！");
		}

		oldStudentApplyRefunds.setStatus(studentApplyRefunds.getStatus());
		if(null==studentApplyRefunds.getActualAmount()){
			oldStudentApplyRefunds.setActualAmount(oldStudentApplyRefunds.getExpectAmount());
		}else{
			oldStudentApplyRefunds.setActualAmount(studentApplyRefunds.getActualAmount());
		}
		oldStudentApplyRefunds.setRemark(studentApplyRefunds.getRemark());
		studentApplyRefundsDao.update(oldStudentApplyRefunds);
		switch (studentApplyRefunds.getStatus()){
			case PASS:
				sysUserCashAccountService.updateBalance(oldStudentApplyRefunds.getUserId(),oldStudentApplyRefunds.getActualAmount());
				SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(studentApplyRefunds.getUserId().intValue());
				SysUserCashAccountDetail sysUserCashAccountDetail=new SysUserCashAccountDetail();
				sysUserCashAccountDetail.setUserId(studentApplyRefunds.getUserId());
				sysUserCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.REFUNDS);
				sysUserCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
				sysUserCashAccountDetail.setAmount(oldStudentApplyRefunds.getActualAmount());
				sysUserCashAccountDetail.setBalance(sysUserCashAccount.getBalance());
				sysUserCashAccountDetail.setAttribute(oldStudentApplyRefunds.getId().toString());
				sysUserCashAccountDetailDao.insert(sysUserCashAccountDetail);

				classGroupStudentMapperDao.deleteStudentByClassGroupId(studentPaymentOrder.getClassGroupId().longValue(),
						studentPaymentOrder.getUserId().longValue());
				break;
			case REJECT:

				break;
			default:
				throw new BizException("审核状态错误!");
		}
	}

	@Override
	public Map<String, Object> findVipGroupSalarys(VipGroupSalaryQueryInfo queryInfo) {

    	if(Objects.isNull(queryInfo.getVipGroupId())){
    		throw new BizException("请指定vip课程!");
		}

		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);

		List<VipGroupSalaryDto> dataList = null;
		int count = courseScheduleTeacherSalaryDao.countVipGroupSalarys(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = courseScheduleTeacherSalaryDao.findVipGroupSalarys(params);
			dataList.forEach(vipGroupSalaryDto -> {
				if(Objects.isNull(vipGroupSalaryDto.getExpectSalary())){
					vipGroupSalaryDto.setExpectSalary(new BigDecimal(0));
				}
				if(Objects.isNull(vipGroupSalaryDto.getActualSalary())){
					vipGroupSalaryDto.setActualSalary(new BigDecimal(0));
					vipGroupSalaryDto.setIsSalary(YesOrNoEnum.NO);
				}else{
					vipGroupSalaryDto.setIsSalary(YesOrNoEnum.YES);
				}
				vipGroupSalaryDto.setDeductionFee(vipGroupSalaryDto.getExpectSalary().subtract(vipGroupSalaryDto.getActualSalary()));
			});
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);

		VipGroupSalaryBaseInfo vipGroupSalaryBaseInfo = vipGroupDao.getVipGroupSalaryInfo(queryInfo.getVipGroupId());
		if(Objects.isNull(vipGroupSalaryBaseInfo)){
			vipGroupSalaryBaseInfo=new VipGroupSalaryBaseInfo();
		}
		if(Objects.isNull(vipGroupSalaryBaseInfo.getExpectTotalSalary())){
			vipGroupSalaryBaseInfo.setExpectTotalSalary(new BigDecimal(0));
		}
		if(Objects.isNull(vipGroupSalaryBaseInfo.getTotalSalary())){
			vipGroupSalaryBaseInfo.setTotalSalary(new BigDecimal(0));
		}
		vipGroupSalaryBaseInfo.setTotalFeeDeduction(vipGroupSalaryBaseInfo.getExpectTotalSalary().subtract(vipGroupSalaryBaseInfo.getTotalSalary()));
		vipGroupSalaryBaseInfo.setFeeDeductionNum(vipGroupDao.countVipGroupDeductionNum(queryInfo.getVipGroupId()));

		Map<String,Object> result=new HashMap<>();
		result.put("pageInfo",pageInfo);
		result.put("baseInfo",vipGroupSalaryBaseInfo);
		return result;
	}

	@Override
	public List<String> findVipGroupAttendanceStudents(Long courseScheduleId) {
    	if(Objects.isNull(courseScheduleId)){
    		throw new BizException("请指定课程");
		}
		return courseScheduleDao.findStudentNamesByCourseSchedule(courseScheduleId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void stopGroup(Long vipGroupId) {
    	if(Objects.isNull(vipGroupId)){
    		throw new BizException("请指定vip课");
		}
		VipGroup vipGroup = vipGroupDao.get(vipGroupId);
    	if(Objects.isNull(vipGroup)){
    		throw new BizException("该课程不存在");
		}
    	if(vipGroup.getStatus()==VipGroupStatusEnum.FINISH||vipGroup.getStatus()==VipGroupStatusEnum.CANCEL){
    		throw new BizException("该课程已结束或者已被停止,无法进行此操作");
		}
    	if(vipGroup.getStatus()==VipGroupStatusEnum.NOT_START){
			vipGroup.setStatus(VipGroupStatusEnum.CANCEL);
    		vipGroupDao.update(vipGroup);
    		return;
		}
		List<Map<Long, BigDecimal>> maps = vipGroupDao.countSurplusCourseFee(vipGroupId);
    	if(CollectionUtils.isEmpty(maps)||(maps.size()==1&&Objects.isNull(maps.get(0)))){
			vipGroup.setStatus(VipGroupStatusEnum.CANCEL);
			vipGroupDao.update(vipGroup);
			return;
		}
		Map<Long, BigDecimal> studentSurplusClassFees = MapUtil.convertMybatisMap(maps);
    	for(Long userId:studentSurplusClassFees.keySet()){
			StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.findByStudentVipGroup(vipGroupId,userId);
			if(null==studentPaymentOrder){
				throw new BizException("未找到相关订单信息！");
			}
			sysUserCashAccountService.updateBalance(userId.intValue(),studentSurplusClassFees.get(userId));
			SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(userId.intValue());
			SysUserCashAccountDetail sysUserCashAccountDetail=new SysUserCashAccountDetail();
			sysUserCashAccountDetail.setUserId(userId.intValue());
			sysUserCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.REFUNDS);
			sysUserCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
			sysUserCashAccountDetail.setAmount(studentSurplusClassFees.get(userId));
			sysUserCashAccountDetail.setBalance(sysUserCashAccount.getBalance());
			sysUserCashAccountDetail.setAttribute(studentPaymentOrder.getOrderNo());
			sysUserCashAccountDetailDao.insert(sysUserCashAccountDetail);
		}
		vipGroup.setStatus(VipGroupStatusEnum.CANCEL);
		vipGroupDao.update(vipGroup);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public boolean awardedMonthlyRewards() {
		List<Map<Integer, Integer>> list = courseScheduleDao.queryVipGroupTeachereClassTimesByMonth(new Date(), CourseStatusEnum.OVER);

		if (list != null && list.size() > 0) {

			Integer organId = null, teacherId = null, coursesTimes = 0;

			for (Map<Integer, Integer> map : list) {
				organId = map.get("organ_id_");
				teacherId = map.get("teacher_id_");
				coursesTimes = map.get("times");

				BigDecimal decimal = courseScheduleRewardsRulesService.queryRewardsAmount(organId, CourseScheduleType.VIP, coursesTimes);
				if (decimal.doubleValue() > 0) {
					sysUserCashAccountDetailService.addCashAccountDetail(teacherId, decimal, "", SysUserCashAccountDetailService.ORGAN,
							PlatformCashAccountDetailTypeEnum.REWARDS, null, DealStatusEnum.SUCCESS, "分部奖励");
				}
			}
		}

		return true;
	}
}