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

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.StudentPayLogQueryInfo;
import com.ym.mec.biz.dal.page.VipClassQueryInfo;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.entity.ImGroupModel;
import com.ym.mec.common.entity.ImUserModel;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.page.QueryInfo;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.util.collection.MapUtil;
import org.apache.commons.lang3.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 java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ClassGroupServiceImpl extends BaseServiceImpl<Integer, ClassGroup> implements ClassGroupService {

    @Autowired
    private ClassGroupDao classGroupDao;
    @Autowired
    private TeacherAttendanceDao teacherAttendanceDao;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private ClassGroupRelationService classGroupRelationService;
    @Autowired
    private ClassGroupStudentMapperDao classGroupStudentMapperDao;
    @Autowired
    private ClassGroupRelationDao classGroupRelationDao;
    @Autowired
    private ClassGroupTeacherMapperService classGroupTeacherMapperService;
    @Autowired
    private TeacherDefaultMusicGroupSalaryService teacherDefaultMusicGroupSalaryService;
    @Autowired
    private CourseScheduleService courseScheduleService;
    @Autowired
    private StudentRegistrationDao studentRegistrationDao;
    @Autowired
    private MusicGroupStudentFeeDao musicGroupStudentFeeDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;

    @Override
    public BaseDAO<Integer, ClassGroup> getDAO() {
        return classGroupDao;
    }

    @Override
    public List<ClassGroup> findClassGroup4Teacher(Integer teacherId) {
        return classGroupDao.findClassGroup4Teacher(teacherId);
    }

    @Override
    public List<ClassGroup> findClassGroup(String musicGroupId, Integer mixClassGroupId) {
        if (null == mixClassGroupId) {
            return classGroupDao.findAllMixClassGroup(musicGroupId);
        } else {
            return classGroupDao.findMixClassChildClassGroup(mixClassGroupId);
        }
    }

    @Override
    public List<ClassGroup> findAllNormalClassGroupByMusicGroupId(String musicGroupId) {
        return classGroupDao.findAllNormalClassGroupByMusicGroupId(musicGroupId);
    }

    @Override
    public List<ClassGroup> findAllMixClassGroupByMusicGroupId(String musicGroupId) {
        List<ClassGroup> allMixClassGroup = classGroupDao.findAllMixClassGroup(musicGroupId);
        for (ClassGroup mixClassGroup : allMixClassGroup) {
            mixClassGroup.setClassNames(classGroupDao.findMixClassChildClassGroupNames(mixClassGroup.getId()).getName());
        }
        return allMixClassGroup;
    }

    @Override
    public List<ClassGroup> findAllClassGroupByMusicGroup(String musicGroupId) {
        List<ClassGroup> allMixClassGroup = classGroupDao.findAllClassGroupByMusicGroup(musicGroupId);
        return allMixClassGroup;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup addClassGroup(ClassGroup classGroup) throws Exception {
        Date date = new Date();
        classGroup.setCreateTime(date);
        classGroup.setUpdateTime(date);
        classGroup.setType(ClassGroupTypeEnum.NORMAL);
        String userIds = classGroup.getUserIds();
        String[] userIdArr = userIds.split(",");

        classGroup.setStudentNum(userIdArr.length);
        insert(classGroup);

        //2、插入班级学生关联关系
        List<ClassGroupStudentMapper> classGroupStudentList = new ArrayList<>();
        for (String userId : userIdArr) {
            ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
            classGroupStudentMapper.setClassGroupId(classGroup.getId());
            classGroupStudentMapper.setUserId(Integer.parseInt(userId));
            classGroupStudentMapper.setCreateTime(date);
            classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentList.add(classGroupStudentMapper);
            StudentRegistration studentRegistration = new StudentRegistration();
            studentRegistration.setClassGroupId(classGroup.getId());
            studentRegistration.setUserId(Integer.getInteger(userId));
            studentRegistration.setMusicGroupId(classGroup.getMusicGroupId());
            studentRegistrationDao.updateByUserIdAndMusicGroupId(studentRegistration);
        }

        classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentList);

        return classGroup;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup addMixClassGroup(String musicGroupId, String name, String classGroupIds) throws Exception {
        Date date;
        date = new Date();

        List<ClassGroup> classGroups = findClassGroupByIds(classGroupIds);
        int studentNum = 0; //学生数
        String subjectIds = "";
        for (ClassGroup classGroup : classGroups) {
            studentNum += classGroup.getStudentNum();
            subjectIds += subjectIds.isEmpty() ? classGroup.getSubjectIdList() : "," + classGroup.getSubjectIdList();
        }

        //1、插入班级
        ClassGroup classGroup = new ClassGroup();
        classGroup.setMusicGroupId(musicGroupId);
        classGroup.setSubjectIdList(subjectIds);
        classGroup.setName(name);
        classGroup.setType(ClassGroupTypeEnum.MIX);
        classGroup.setCreateTime(date);
        classGroup.setUpdateTime(date);
        insert(classGroup);

        //2、插入班级关联关系
        List<ClassGroupRelation> classGroupRelationList = new ArrayList<>();
        for (ClassGroup cGroup : classGroups) {
            ClassGroupRelation classGroupRelation = new ClassGroupRelation();
            classGroupRelation.setClassGroupId(classGroup.getId());
            classGroupRelation.setSubClassGroupId(cGroup.getId());
            classGroupRelation.setCreateTime(date);
            classGroupRelationList.add(classGroupRelation);
        }
        classGroupRelationService.classGroupRelationsInsert(classGroupRelationList);
        return classGroup;
    }

    @Override
    public List<ClassGroup> findClassGroupByIds(String ids) {
        return classGroupDao.findClassGroupByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<HighClassGroupDto> addHighClassGroup(List<HighClassGroupDto> highClassGroupList) throws Exception {
        for (HighClassGroupDto highClassGroup : highClassGroupList) {
            //1、插入班级信息
            Date date;
            date = new Date();
            highClassGroup.setCreateTime(date);
            highClassGroup.setUpdateTime(date);
            highClassGroup.setType(ClassGroupTypeEnum.HIGH);
            insert(highClassGroup);

            //2、插入班级关联老师
            ClassGroupTeacherMapper classGroupTeacherMapper = new ClassGroupTeacherMapper();
            classGroupTeacherMapper.setMusicGroupId(highClassGroup.getMusicGroupId());
            classGroupTeacherMapper.setClassGroupId(highClassGroup.getId());
            classGroupTeacherMapper.setTeacherRole(TeachTypeEnum.BISHOP);
            classGroupTeacherMapper.setUserId(highClassGroup.getUserId());
            classGroupTeacherMapper.setCreateTime(date);
            classGroupTeacherMapper.setUpdateTime(date);
            classGroupTeacherMapperService.insert(classGroupTeacherMapper);

            //3、插入班级排课信息
            List<CourseSchedule> courseScheduleList = new ArrayList<>();
            int i = 0;
            LocalDateTime now = LocalDateTime.ofInstant(highClassGroup.getStartDate().toInstant(), ZoneId.systemDefault());
            while (true) {
                now = now.plusDays(i);
                int dayOfWeek = now.getDayOfWeek().getValue();

                if (highClassGroup.getDayOfWeek().equals(dayOfWeek)) {
                    CourseSchedule courseSchedule = new CourseSchedule();
                    Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
                    Date classDate = Date.from(instant);

                    courseSchedule.setClassGroupId(highClassGroup.getUserId());
                    courseSchedule.setStatus(CourseStatusEnum.NOT_START);
                    courseSchedule.setClassDate(classDate);
                    courseSchedule.setStartClassTime(highClassGroup.getStartClassTime());
                    courseSchedule.setEndClassTime(highClassGroup.getEndClassTime());
                    courseSchedule.setTeacherId(highClassGroup.getUserId().longValue());
                    courseSchedule.setActualTeacherId(highClassGroup.getUserId().longValue());
                    courseSchedule.setCreateTime(date);
                    courseSchedule.setUpdateTime(date);
                    courseSchedule.setTeachMode(TeachModeEnum.OFFLINE);
                    courseScheduleList.add(courseSchedule);
                    i++;
                }
                if (highClassGroup.getCourseTimes().equals(i)) {
                    break;
                }
            }
            courseScheduleService.batchAddCourseSchedule(courseScheduleList);
        }
        return highClassGroupList;
    }

    @Override
    public List<TeacherMusicClassInfoDto> getTeacherMusicClass(Integer teacherId) {
        List<TeacherMusicClassInfoDto> teacherMusics = classGroupDao.queryGroupCourses(teacherId);
        //获取老师在当前乐团出勤次数
        if(teacherMusics != null && teacherMusics.size() > 0){
            HashMap<String,Object> param = new HashMap<>();
            param.put("teacherId",teacherId);
            param.put("attendanceStatus",YesOrNoEnum.YES);
            teacherMusics.forEach(e->{
                param.put("musicGroupId",e.getMusicGroupId());
                e.setAttendanceNum(teacherAttendanceDao.getTeacherPersonalAttendancesCount(param));
            });
        }
        return teacherMusics;
    }

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

    @Override
    public List<ClassGroupTeachersDto> getClassGroupAndTeachers(String musicGroupId,String type) {
        List<ClassGroupTeachersDto> classGroupAndTeachersList = classGroupDao.findClassGroupByMusicGroupId(musicGroupId,type);

        List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroupTeacherMapperService.findClassGroupTeachers(classGroupAndTeachersList);

        for (ClassGroupTeachersDto classGroupAndTeachers : classGroupAndTeachersList) {
            List<ClassGroupTeacherMapper> oneClassGroupTeacherMapperList = new ArrayList<>();
            for (ClassGroupTeacherMapper classGroupTeacherMapper : classGroupTeacherMapperList) {
                if (classGroupTeacherMapper.getClassGroupId().equals(classGroupAndTeachers.getId())) {
                    oneClassGroupTeacherMapperList.add(classGroupTeacherMapper);
                }
            }
            classGroupAndTeachers.setClassGroupTeacherMapperList(oneClassGroupTeacherMapperList);
        }
        return classGroupAndTeachersList;
    }

    @Override
    public List<ClassGroupTeachersDto> getClassGroupAndTeacherSalary(String musicGroupId, SalarySettlementTypeEnum type) throws Exception {
        //乐团班级及班级老师
        List<ClassGroupTeachersDto> classGroupAndTeachers = getClassGroupAndTeachers(musicGroupId,"NORMAL,MIX,HIGH");

        for (ClassGroupTeachersDto classGroupAndTeacher : classGroupAndTeachers) {
            //班级的教师列表
            List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroupAndTeacher.getClassGroupTeacherMapperList();
            for (ClassGroupTeacherMapper classGroupTeacherMapper : classGroupTeacherMapperList) {
                //获取老师的默认课酬
                String courseType = classGroupAndTeacher.getType().equals(ClassGroupTypeEnum.NORMAL) ? "SINGLE" : classGroupAndTeacher.getType().getCode();
                List<TeacherDefaultMusicGroupSalary> teacherSalaryByUserIdAndType = teacherDefaultMusicGroupSalaryService.getTeacherSalaryByUserIdAndType(classGroupTeacherMapper.getUserId(), courseType, type);
                if (teacherSalaryByUserIdAndType == null) {
                    throw new Exception("userId："+classGroupTeacherMapper.getUserId()+"名字："+classGroupTeacherMapper.getUserName()+" 老师没有设置课酬");
                }
                classGroupTeacherMapper.setTeacherDefaultMusicGroupSalaryList(teacherSalaryByUserIdAndType);
            }

        }
        return classGroupAndTeachers;
    }

    @Override
    public PageInfo<CourseListDto> queryCoursePage(QueryInfo queryInfo, Integer userId) {
        queryInfo.setSearch(userId.toString());
        PageInfo<CourseListDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List<CourseListDto> courseListDtos = null;
        int count = classGroupDao.countCoursePage(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            courseListDtos = classGroupDao.queryCoursePage(params);
            courseListDtos.forEach(e -> {
                if ("VIP".equals(e.getTeachMode())) {
                    //获取vip课的学生名称列表
                    List<String> vipStuNames = classGroupDao.findVipStuNames(e.getMusicGroupId());
                    if (vipStuNames != null && vipStuNames.size() > 0) {
                        StringUtils.join(vipStuNames, ",");
                        e.setStudentNames(StringUtils.join());
                    }
                } else {
                    //获取学员乐团课的续费状态
                    MusicGroupStudentFee musicGroupStudentFee = musicGroupStudentFeeDao.findByUser(userId, e.getMusicGroupId());
                    if (musicGroupStudentFee != null) {
                        e.setPaymentStatus(musicGroupStudentFee.getPaymentStatus());
                    }
                }
            });
        }
        if (count == 0) {
            courseListDtos = new ArrayList<>();
        }
        pageInfo.setRows(courseListDtos);
        return pageInfo;
    }

    @Override
    public List<ImGroupModel> queryUserGroups(Integer userId, String search) {
        List<ImGroupModel> imGroupModels = musicGroupDao.queryUserGroups(userId, search);

        if (imGroupModels != null && imGroupModels.size() > 0) {
            //获取相关的所有乐团
            Set<String> musicGroupIds = imGroupModels.stream().map(e -> e.getId()).collect(Collectors.toSet());
            List<MusicGroup> musicGroups = musicGroupDao.queryListByIds(musicGroupIds);

            //获取乐团群用户总数map
            List<Map<String, BigDecimal>> musicGroupUserNums = musicGroupDao.countMusicGroupUserNum(musicGroupIds);
            Map<String, BigDecimal> musicGroupUserNumMap = MapUtil.convertMybatisMap(musicGroupUserNums);
            imGroupModels.forEach(e -> {
                MusicGroup musicGroup = musicGroups.stream().filter(mg -> mg.getId().equals(e.getId())).findFirst().get();
                //获取教学老师id列表
                Set<Integer> teachers = musicGroupDao.queryTeacherIds(e.getId());
                teachers.add(musicGroup.getTeamTeacherId());
                teachers.add(musicGroup.getEducationalTeacherId());
                teachers.add(musicGroup.getOperatorUserId());
                teachers.add(musicGroup.getDirectorUserId());
                teachers.removeAll(Collections.singleton(null));
                //获取乐团群用户总数
                BigDecimal count = musicGroupUserNumMap.get(e.getId());
                e.setCount(count == null?0:count.intValue() + teachers.size());
                e.setId("mg" + e.getId());
            });
        } else {
            imGroupModels = new ArrayList<>();
        }
        List<ImGroupModel> imGroupModels1 = classGroupDao.queryUserGroups(userId, search);
        if (imGroupModels1 != null && imGroupModels1.size() > 0) {
            Set<String> classGroupIds = imGroupModels1.stream().map(e -> e.getId()).collect(Collectors.toSet());
            //获取班级老师总数map
            List<Map<Integer, Integer>> nums = classGroupDao.countTeacherNums(StringUtils.join(classGroupIds,","));
            Map<Integer, Integer> numsMap = MapUtil.convertMybatisMap(nums);
            imGroupModels1.forEach(e -> {
                Integer num = numsMap.get(e.getId());
                e.setCount(num == null?0:num + e.getCount());
                e.setId("cg" + e.getId());
            });
            imGroupModels.addAll(imGroupModels1);
        }
        return imGroupModels;
    }

    @Override
    public List<ImUserModel> findGroupUsers(String groupId) {
        if (groupId.startsWith("mg")) {
            return musicGroupDao.findGroupUsers(groupId.substring(2));
        }
        return classGroupDao.findGroupUsers(groupId.substring(2));
    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup addStudent(ClassGroup classGroup, int userId) {
        Date date = new Date();
        //增加班级人数
        classGroup.setCreateTime(date);
        classGroupDao.addStudentNum(classGroup);
        //插入关联关系
        ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
        classGroupStudentMapper.setClassGroupId(classGroup.getId());
        classGroupStudentMapper.setUserId(userId);
        classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
        classGroupStudentMapper.setCreateTime(date);
        classGroupStudentMapperDao.insert(classGroupStudentMapper);
        return classGroup;
    }

    @Override
    public List<ClassGroup> findNoClassSubjects(String musicGroupId) {
        return classGroupDao.findNoClassSubjects(musicGroupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSingle(Integer classGroupId) {
        //删除学员班级关联关系
        classGroupStudentMapperDao.deleteByClassId(classGroupId);
        //删除班级
        classGroupDao.delete(classGroupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delMix(Integer classGroupId) {
        //删除班级关系
        classGroupRelationDao.deleteByClassId(classGroupId);
        //删除合奏班
        classGroupDao.delete(classGroupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addMusicGroupTeam(Integer teacherId, String musicGroupId) throws Exception {
        //所有学员都已经分配
        List<StudentRegistration> students = studentRegistrationDao.getNoClassStuBySubjectId(musicGroupId, null);
        if(students != null && students.size() > 0){
            throw new Exception("还有学员未分配班级");
        }
        //所有单技班都有合奏班
        List<ClassGroup> classGroupList = classGroupDao.findNoClassSubjects(musicGroupId);
        if(classGroupList != null && classGroupList.size() > 0){
            throw new Exception("还有单技班未分配合奏");
        }
        //设置教学主管
        MusicGroup musicGroup = new MusicGroup();
        musicGroup.setId(musicGroupId);
        musicGroup.setDirectorUserId(teacherId);
        musicGroup.setUpdateTime(new Date());
        musicGroupDao.update(musicGroup);
    }

    @Override
    public List<TeacherClassGroupDto> findTeacherClassGroups() {
        SysUser user = sysUserFeignService.queryUserInfo();
        if(Objects.isNull(user)){
            throw new BizException("请登录");
        }

        List<TeacherClassGroupDto> teacherMusicClassGroup = classGroupDao.findTeacherMusicClassGroup(user.getId().longValue());


        return null;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean updateClassStudentNum(Long classGroupId, Integer num) {
        ClassGroup classGroup=classGroupDao.lockClassGroup(classGroupId);
        if(Objects.isNull(classGroup)){
            throw new BizException("班级不存在");
        }
        classGroup.setStudentNum(classGroup.getStudentNum()+num);
        classGroup.setUpdateTime(new Date());

        classGroupDao.update(classGroup);

        return true;
    }
}