package com.yonge.cooleshow.biz.dal.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.biz.dal.dao.ImNetworkRoomDao;
import com.yonge.cooleshow.biz.dal.dao.SysConfigDao;
import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
import com.yonge.cooleshow.biz.dal.dto.*;
import com.yonge.cooleshow.biz.dal.entity.*;
import com.yonge.cooleshow.biz.dal.enums.*;
import com.yonge.cooleshow.biz.dal.service.*;
import com.yonge.cooleshow.biz.dal.support.IMHelper;
import com.yonge.cooleshow.common.constant.SysConfigConstant;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.utils.date.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 网络教室房间(ImNetworkRoom)表服务实现类
 *
 * @author zx
 * @since 2022-03-30 16:36:36
 */
@Service("imNetworkRoomService")
public class ImNetworkRoomServiceImpl extends ServiceImpl<ImNetworkRoomDao, ImNetworkRoom> implements ImNetworkRoomService {

    private final static Logger log = LoggerFactory.getLogger(ImNetworkRoomServiceImpl.class);

    @Resource
    private SysUserService sysUserService;
    @Resource
    private TeacherDao teacherDao;
    @Resource
    private ImNetworkRoomMemberService imNetworkRoomMemberService;
    @Resource
    private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
    @Resource
    private CourseScheduleStudentMusicSheetService courseScheduleStudentMusicSheetService;
    @Resource
    private CourseScheduleService courseScheduleService;
    @Resource
    private SysConfigDao sysConfigDao;
    @Resource
    private IMHelper imHelper;
    @Resource
    private MusicSheetAccompanimentService musicSheetAccompanimentService;
    @Resource
    private StudentAttendanceService studentAttendanceService;
    @Resource
    private TeacherAttendanceService teacherAttendanceService;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    private String QUIT_ROOM_SUCCESS = "quitRoomSuccess:";

    @Override
    public ImNetworkRoomDao getDao() {
        return this.baseMapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResponseResult<ImNetworkRoomResult> joinRoom(Long courseScheduleId) throws Exception {
        Long userId = sysUserService.getUserId();
        CourseSchedule courseSchedule = Optional.ofNullable(courseScheduleService.getById(courseScheduleId)).
                orElseThrow(()->new BizException("房间信息不存在"));
        UserRoleEnum userRole = UserRoleEnum.STUDENT;
        if(courseSchedule.getTeacherId().equals(userId)){
            userRole = UserRoleEnum.TEACHER;
        }
        log.info("joinRoom params：courseScheduleId:{},userRole:{},userId:{}",courseScheduleId,userRole,userId);
        BasicUserInfo sysUser = Optional.ofNullable(teacherDao.getBasicUserInfo(userId)).
                orElseThrow(()-> new BizException("用户信息不存在"));
        Date now = new Date();
        courseSchedule.setUpdatedTime(now);
        //是否提前进入教室
        if (roomNotStart(courseSchedule)) {
            return HttpResponseResult.failed(ImNetworkRoomErrorEnum.ROOM_NOT_START.getRemark());
        }
        String roomId = courseScheduleId.toString();
        ImNetworkRoomResult joinRoomResult = new ImNetworkRoomResult();
        //初始化房间信息
        ImNetworkRoom room = this.initRoom(roomId,courseScheduleId,userRole,sysUser.getUserId(),now);
        BeanUtils.copyProperties(room,joinRoomResult);
        //定时销毁房间
        //初始化房间用户信息
        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.initRoomMember(roomId,sysUser,userRole);
        joinRoomResult.setRoomMember(roomMember);
        //获取教室剩余时长
        joinRoomResult.setSurplusTime(DateUtil.secondsBetween(now, courseSchedule.getEndTime()));
        //获取房间所有成员
        List<ImNetworkRoomMember> roomMemberList = imNetworkRoomMemberService.getDao().queryByRoomId(roomId);
        joinRoomResult.setRoomMemberList(roomMemberList);
        //如果是老师，重置节拍器数据
        if(userRole == UserRoleEnum.TEACHER){
            courseScheduleStudentPaymentService.getDao().cleanPlayMidi(courseScheduleId);
            //获取所有学员的伴奏下载详情
            setMusicSheetList(roomMemberList,courseScheduleId);
        }else {
            //获取节拍器信息
            joinRoomResult.setMidiJson(courseScheduleStudentPaymentService.getMemberMidi(courseScheduleId,sysUser.getUserId()));
        }
        //课程结束后关闭教室的时间
        joinRoomResult.setAutoCloseNetworkRoomTime(sysConfigDao.findConfigValue(SysConfigConstant.DESTROY_EXPIRED_PRACTICE_ROOM_MINUTE));
        //创建、加入群聊
        IMApiResultInfo resultInfo = imHelper.joinGroup(new String[]{sysUser.getUserId().toString()}, roomId, roomId);
        if(resultInfo.getCode() != 200){
            log.error("加入群聊失败 resultInfo:{}",resultInfo);
        }
        return HttpResponseResult.succeed(joinRoomResult);
    }

    private void setMusicSheetList(List<ImNetworkRoomMember> roomMemberList,Long courseScheduleId){
        List<CourseScheduleStudentMusicSheetResult> musicSheetResults = courseScheduleStudentMusicSheetService.getDao().
                queryBySheetIdAndCourseId(null,courseScheduleId,null,null,null);
        if (!CollectionUtils.isEmpty(musicSheetResults)) {
            //分组塞到学员列表中
            Map<Long, List<CourseScheduleStudentMusicSheetResult>> musicSheetResultMap = musicSheetResults.stream().
                    collect(Collectors.groupingBy(e -> e.getUserId()));
            roomMemberList.forEach(e -> {
                if (musicSheetResultMap.containsKey(e.getUserId())) {
                    e.setMusicSheetResults(musicSheetResultMap.get(e.getUserId()));
                }
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void joinRoomSuccess(String roomId,Long userId) throws Exception {
        log.info("joinRoomSuccess: roomId={}, userId={}", roomId, userId);
        CourseSchedule courseSchedule = Optional.ofNullable(courseScheduleService.getById(roomId)).
                orElseThrow(()->new BizException("房间信息不存在"));
        BasicUserInfo sysUser = Optional.ofNullable(teacherDao.getBasicUserInfo(userId)).
                orElseThrow(()-> new BizException("用户信息不存在"));
        UserRoleEnum userRole = UserRoleEnum.STUDENT;
        if(Objects.equals(courseSchedule.getTeacherId(),userId)){
            userRole = UserRoleEnum.TEACHER;
            teacherAttendanceService.signIn(userId,courseSchedule);
        }else {
            studentAttendanceService.signIn(userId,courseSchedule);
        }
        Date now = new Date();
        //获取房间信息
        ImNetworkRoom room = this.initRoom(roomId, Long.parseLong(roomId), userRole, userId, now);
        //获取房间用户信息
        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.initRoomMember(roomId,sysUser,userRole);
        //发送人员变动消息
        publishMemberChangedMessage(roomMember);
        //sendDisplay
        this.sendDisplay(userId,room);
    }

    //发送人员变动消息
    private void publishMemberChangedMessage(ImNetworkRoomMember roomMember) throws Exception {
        ImNetworkRoomMemberChangedMessage msg = new ImNetworkRoomMemberChangedMessage(roomMember,ImNetworkRoomMemberChangedEnum.JOIN);
        //获取节拍器信息
        ImNetworkCustomMessage imNetworkCustomMessage = courseScheduleStudentPaymentService.getMemberMidi(Long.parseLong(roomMember.getRoomId()), roomMember.getUserId());
        msg.setMetronomeSwitch(imNetworkCustomMessage.getEnable());
        //获取伴奏信息
        ImNetworkRoomMusicSheetDownloadData musicSheetDownloadData = courseScheduleStudentPaymentService.getMemberExamSong(Long.parseLong(roomMember.getRoomId()), roomMember.getUserId());
        msg.setExamSongSwitch(musicSheetDownloadData.getEnable());
        imHelper.publishMessage(roomMember.getUserId().toString(), roomMember.getRoomId(), msg);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void joinRoomFailure(String roomId) {
        Long userId = sysUserService.getUserId();
        log.info("joinRoomFailure: roomId={}, userId={}", roomId, userId);
        imNetworkRoomMemberService.getDao().delByRidAndUid(roomId, userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void quitRoomSuccess(String roomId, Long userId) throws Exception {
        log.info("quitRoomSuccess: roomId={}, userId={}", roomId, userId);
        //防止幂等
        StringBuffer sb  = new StringBuffer(QUIT_ROOM_SUCCESS).append(roomId).append(userId);
        if (!redisTemplate.opsForValue().setIfAbsent(sb.toString(),userId,1l, TimeUnit.SECONDS)){
            log.info("quitRoomSuccess break: roomId={}, userId={}", roomId, userId);
            return;
        }
        ImNetworkRoomMember roomMember = imNetworkRoomMemberService.getDao().findByRidAndUid(roomId, userId);
        if(Objects.isNull(roomMember)){
            return;
        }
        CourseSchedule courseSchedule = Optional.ofNullable(courseScheduleService.getById(roomId))
                .orElseThrow(()->new BizException("房间信息不存在"));
        Long courseScheduleId = courseSchedule.getId();
        UserRoleEnum roleEnum = UserRoleEnum.STUDENT;
        if(Objects.equals(courseSchedule.getTeacherId(),userId)){
            roleEnum = UserRoleEnum.TEACHER;
            teacherAttendanceService.signOut(userId,courseSchedule);
        }else {
            //记录考勤签退
            studentAttendanceService.signOut(userId,courseSchedule);
        }
        ImNetworkRoom room = baseMapper.findByRoomId(roomId);
        if (roleEnum == UserRoleEnum.TEACHER){
            //如果老师退出房间，关闭伴奏
            courseScheduleStudentMusicSheetService.getDao().closePlayStatus(courseScheduleId,null);
            courseScheduleStudentPaymentService.getDao().adjustPlayMidi(courseScheduleId, null, null);
            courseScheduleStudentPaymentService.getDao().adjustExamSong(courseScheduleId, null, null);
            if (isUserDisplay(room.getDisplay(), userId)) {
                room.setDisplay("");
                this.updateDisplay(userId,room);
            }
            //老师退出房间，初始化节拍器和伴奏播放配置
            courseScheduleStudentPaymentService.adjustPlayMidiAndMusicSheet(courseSchedule.getId(), null, null,"");
        }
        int memberNum = imNetworkRoomMemberService.getDao().countByRoomId(roomId);
        if (memberNum <= 1) {
            imHelper.dismiss(userId.toString(), roomId);
            courseScheduleStudentMusicSheetService.getDao().closePlayStatus(courseSchedule.getId(),null);
            log.info("leaveRoomSuccess dismiss the room: {},userId: {}", roomId, userId);
        } else {
            ImNetworkRoomMemberChangedMessage msg = new ImNetworkRoomMemberChangedMessage(roomMember,ImNetworkRoomMemberChangedEnum.LEAVE);
            imHelper.publishMessage(userId.toString(), roomId, msg);
            imHelper.quit(new String[]{userId.toString()}, roomId);
            log.info("leaveRoomSuccess quit group: roomId={},userId: {}", roomId, userId);
        }
        //删房间用户信息
        imNetworkRoomMemberService.getDao().deleteById(roomMember.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendImPlayMidiMessage(ImNetworkCustomMessage customMessage) throws Exception {
        Long userId = sysUserService.getUserId();
        Long roomId = customMessage.getRoomId();
        log.info("sendImPlayMidiMessage: roomId={}, userId={}", roomId, userId);
        ImNetworkMetronomeMessage displayMessage = new ImNetworkMetronomeMessage(customMessage);
        imHelper.publishMessage(userId.toString(), roomId.toString(), displayMessage, 1);
        //记录节拍器信息
        courseScheduleStudentPaymentService.getDao().adjustPlayMidi(roomId,customMessage.getUserId(),customMessage.toString());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pushDownloadMusicSheetMsg(ImNetworkMusicSheetDto musicSheetDto) throws Exception {
        Long courseScheduleId = Optional.ofNullable(musicSheetDto).map(ImNetworkBaseDto::getRoomId).orElseThrow(() -> new BizException("房间编号不能为空"));
        Long accompanimentId = Optional.ofNullable(musicSheetDto).map(ImNetworkMusicSheetDto::getAccompanimentId).orElseThrow(() -> new BizException("伴奏编号不能为空"));
        log.info("pushDownloadMusicSheetMsg: courseScheduleId:{} ,accompanimentId:{} ,deviceType:{}", courseScheduleId,accompanimentId);
        Long userId = sysUserService.getUserId();
        List<CourseScheduleStudentMusicSheetResult> scheduleStudentMusicSheetResults = courseScheduleStudentMusicSheetService.getDao().
                queryBySheetIdAndCourseId(accompanimentId, courseScheduleId, null, null, 0);

        MusicSheetAccompaniment accompaniment = musicSheetAccompanimentService.getById(accompanimentId);
        if (scheduleStudentMusicSheetResults.size() == 0) {
            //第一次下载,生成数据
            List<CourseScheduleStudentPayment> courseScheduleStudentPayments = courseScheduleStudentPaymentService.getDao().queryByCourseId(courseScheduleId);
            Set<Long> studentIds = courseScheduleStudentPayments.stream().map(e -> e.getUserId()).collect(Collectors.toSet());
            studentIds.forEach(e -> {
                CourseScheduleStudentMusicSheetResult musicSheet = new CourseScheduleStudentMusicSheetResult();
                musicSheet.setMusicSheetAccompanimentId(accompanimentId);
                musicSheet.setSpeed(accompaniment.getSpeed());
                musicSheet.setCourseScheduleId(courseScheduleId);
                musicSheet.setUserId(e);
                scheduleStudentMusicSheetResults.add(musicSheet);
            });
            CourseScheduleStudentMusicSheetResult musicSheet = new CourseScheduleStudentMusicSheetResult();
            musicSheet.setMusicSheetAccompanimentId(accompanimentId);
            musicSheet.setSpeed(accompaniment.getSpeed());
            musicSheet.setCourseScheduleId(courseScheduleId);
            musicSheet.setUserId(userId);
            musicSheet.setUserType(1);
            scheduleStudentMusicSheetResults.add(musicSheet);
            courseScheduleStudentMusicSheetService.getDao().batchInsert(scheduleStudentMusicSheetResults);
        }
        ImNetworkMusicSheetDownloadMessage msg = new ImNetworkMusicSheetDownloadMessage(
                JSON.parseObject(JSON.toJSONString(accompaniment), ImNetworkMusicSheetDownloadMessageContent.class));
        imHelper.publishMessage(userId.toString(), courseScheduleId.toString(), msg, 0);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void display(ImNetworkDisplayDataDto displayData) throws Exception {
        log.info("display in data = {}", displayData);
        Long userId = sysUserService.getUserId();

        StringBuffer display = new StringBuffer("display://type=").append(displayData.getType().ordinal()).append("?userId=");
        switch (displayData.getType()) {
            case NONE:
                //清空当前 room 的 display
                display = new StringBuffer();
                break;
            case TEACHER:
                Long teacherId = Optional.ofNullable(courseScheduleService.getById(displayData.getRoomId())).
                        map(CourseSchedule::getTeacherId).
                        orElseThrow(()->new BizException("房间信息不存在"));
                display.append(teacherId).append("?uri=");
                break;
            case SCREEN:
                display.append(userId).append("?uri=");
                break;
            case STUDENT:
                display.append(displayData.getUserId()).append("?uri=").append(displayData.getUri());
                break;
            default:
                display.append(userId).append("?uri=").append(displayData.getUri());
                break;
        }
        ImNetworkRoom room = baseMapper.findByRoomId(displayData.getRoomId());
        room.setDisplay(display.toString());
        this.updateDisplay(userId,room);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
        ImNetworkDeviceTypeEnum deviceType = deviceControl.getDeviceType();
        if (deviceControl.getUserId() != null) {
            controlDevice(deviceControl);
        } else {
            if (deviceType == ImNetworkDeviceTypeEnum.EXAM_SONG ||
                    deviceType == ImNetworkDeviceTypeEnum.MUSIC_SHEET ||
                    deviceType == ImNetworkDeviceTypeEnum.ACCOMPANIMENT) {
                List<CourseScheduleStudentPayment> studentPayments = courseScheduleStudentPaymentService.getDao().queryByCourseId(Long.parseLong(deviceControl.getRoomId()));

                for (CourseScheduleStudentPayment studentPayment : studentPayments) {
                    deviceControl.setUserId(studentPayment.getUserId());
                    controlDevice(deviceControl);
                }
                return;
            }else {
                List<ImNetworkRoomMember> roomMembers = imNetworkRoomMemberService.getDao().findByRoomAndRole(deviceControl.getRoomId(), 0);
                if (!CollectionUtils.isEmpty(roomMembers)) {
                    for (ImNetworkRoomMember roomMember : roomMembers) {
                        deviceControl.setUserId(roomMember.getUserId());
                        controlDevice(deviceControl);
                    }
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void controlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
        SysUser sysUser = sysUserService.getUser();
        String roomId = deviceControl.getRoomId();
        Long userId = deviceControl.getUserId();
        Boolean enable = deviceControl.getEnable();
        log.info("controlDevice: roomId:{} ,deviceType:{} ,enable:{} ,userId:{}", roomId,deviceControl.getDeviceType(),enable,userId);
        if(enable){
            long scheduleId = Long.parseLong(roomId);
            ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceControl.getDeviceType().ordinal(),enable);
            deviceResourceMessage.setUserId(userId.toString());
            switch (deviceControl.getDeviceType()) {
                case EXAM_SONG:
                    ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, userId);
                    msg.setEnable(enable);
                    courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId,userId, JSON.toJSONString(msg));
                    imHelper.publishMessage(userId.toString(), roomId, deviceResourceMessage, 1);
                    break;
                case MUSIC_SHEET:
                    Integer musicSheetId = Optional.ofNullable(deviceControl.getMusicSheetAccompanimentId()).
                            orElseThrow(()-> new BizException("请选择曲目"));
                    //关闭所有曲目播放
                    courseScheduleStudentMusicSheetService.getDao().closePlayStatus(scheduleId,userId);
                    //打开原音
                    courseScheduleStudentMusicSheetService.getDao().openPlayStatus(scheduleId,musicSheetId,userId);
                    deviceResourceMessage.setMusicSheetAccompanimentId(musicSheetId);
                    deviceResourceMessage.setUserId(userId.toString());
                    deviceResourceMessage.setSoundVolume(deviceControl.getSoundVolume());
                    imHelper.publishMessage(sysUser.getId().toString(), roomId, deviceResourceMessage, 1);
                    break;
                case ACCOMPANIMENT:
                  Integer musicSheetAccompanimentId = Optional.ofNullable(deviceControl.getMusicSheetAccompanimentId()).
                            orElseThrow(()-> new BizException("请选择曲目"));
                    //关闭所有曲目播放
                    courseScheduleStudentMusicSheetService.getDao().closePlayStatus(scheduleId,userId);
                    //打开伴奏
                    courseScheduleStudentMusicSheetService.getDao().openAccompanimentPlayStatus(scheduleId,musicSheetAccompanimentId,userId);
                    deviceResourceMessage.setMusicSheetAccompanimentId(musicSheetAccompanimentId);
                    deviceResourceMessage.setUserId(userId.toString());
                    deviceResourceMessage.setSoundVolume(deviceControl.getSoundVolume());
                    imHelper.publishMessage(sysUser.getId().toString(), roomId, deviceResourceMessage, 1);
                    break;
                default:
                    //邀请打开指定设备权限
                    ImNetworkControlDeviceNotifyMessage message = new ImNetworkControlDeviceNotifyMessage(ImNetworkActionEnum.INVITE.ordinal());
                    message.setType(deviceControl.getDeviceType().ordinal());
                    message.setOpUserId(sysUser.getId().toString());
                    message.setOpUserName(sysUser.getUsername());
                    imHelper.publishMessage(sysUser.getId().toString(), userId.toString(), roomId, message);
                    break;
            }
        }else {
            ImNetworkRoomMember roomMember = Optional.ofNullable(imNetworkRoomMemberService.getDao().findByRidAndUid(roomId, userId))
                    .orElseThrow(()-> new BizException("用户不在房间内"));
            long scheduleId = Long.parseLong(roomId);
            switch (deviceControl.getDeviceType()) {
                case CAMERA:
                    roomMember.setCameraFlag(deviceControl.getEnable());
                    break;
                case MICROPHONE:
                    roomMember.setMicFlag(deviceControl.getEnable());
                    break;
                case HAND_UP:
                    roomMember.setHandFlag(deviceControl.getEnable());
                    break;
                case MUSIC_MODE:
                    roomMember.setMusicModeFlag(deviceControl.getEnable());
                    break;
                case EXAM_SONG:
                    ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, userId);
                    msg.setEnable(deviceControl.getEnable());
                    courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId,userId, JSON.toJSONString(msg));
                    break;
                case MUSIC_SHEET:
                case ACCOMPANIMENT:
                    //关闭所有曲目播放
                    courseScheduleStudentMusicSheetService.getDao().closePlayStatus(scheduleId,userId);
                    break;
            }
            if(deviceControl.getDeviceType() != ImNetworkDeviceTypeEnum.MUSIC_SHEET &&
                    deviceControl.getDeviceType() != ImNetworkDeviceTypeEnum.EXAM_SONG &&
                    deviceControl.getDeviceType() != ImNetworkDeviceTypeEnum.ACCOMPANIMENT){
                imNetworkRoomMemberService.getDao().updateById(roomMember);
            }
            ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceControl.getDeviceType().ordinal(),deviceControl.getEnable());
            deviceResourceMessage.setUserId(userId.toString());
            BasicUserInfo basicUserInfo = teacherDao.getBasicUserInfo(userId);
            if (Objects.nonNull(basicUserInfo)) {
                deviceResourceMessage.setUserName(basicUserInfo.getUsername());
            }
            imHelper.publishMessage(sysUser.getId().toString(), roomId, deviceResourceMessage, 1);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approveControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
        log.info("approveControlDevice: roomId:{} ,deviceType:{} ,enable:{}", deviceControl.getRoomId(),deviceControl.getDeviceType(),deviceControl.getEnable());
        SysUser sysUser = sysUserService.getUser();
        ImNetworkRoomMember roomMember = Optional.ofNullable(imNetworkRoomMemberService.getDao().findByRidAndUid(deviceControl.getRoomId(), sysUser.getId())).
                orElseThrow(()-> new BizException("用户不在房间内"));
        switch (deviceControl.getDeviceType()) {
            case CAMERA:
                roomMember.setCameraFlag(deviceControl.getEnable());
                break;
            case EXAM_SONG:
                long scheduleId = Long.parseLong(deviceControl.getRoomId());
                ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, sysUser.getId());
                msg.setEnable(deviceControl.getEnable());
                courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId, sysUser.getId(), JSON.toJSONString(msg));
                break;
            case MICROPHONE:
                roomMember.setMicFlag(deviceControl.getEnable());
                break;
        }
        if(deviceControl.getDeviceType() == ImNetworkDeviceTypeEnum.CAMERA ||
                deviceControl.getDeviceType() == ImNetworkDeviceTypeEnum.MICROPHONE){
            imNetworkRoomMemberService.getDao().updateById(roomMember);
        }
        ImNetworkControlDeviceNotifyMessage msg = new ImNetworkControlDeviceNotifyMessage(ImNetworkActionEnum.APPROVE.ordinal());
        msg.setType(deviceControl.getDeviceType().ordinal());
        msg.setOpUserId(sysUser.getId().toString());
        msg.setOpUserName(sysUser.getUsername());
        //获取老师编号
        Long teacherId = Optional.ofNullable(courseScheduleService.getById(deviceControl.getRoomId())).
                map(CourseSchedule::getTeacherId).
                orElseThrow(()->new BizException("房间信息不存在"));
        imHelper.publishMessage(sysUser.getId().toString(),teacherId.toString(), deviceControl.getRoomId(), msg);

        //发送设备状态变更消息
        this.sendDeviceStateChangedMessage(deviceControl, sysUser.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deviceStatusSync(ImNetworkDeviceControlDto deviceStatusSync) throws Exception {
        log.info("deviceStatusSync: enable:{} ,roomId:{} ,deviceType:{}", deviceStatusSync.getEnable(),deviceStatusSync.getRoomId(),deviceStatusSync.getDeviceType());
        Long userId = sysUserService.getUserId();
        ImNetworkDeviceTypeEnum deviceType = deviceStatusSync.getDeviceType();
        ImNetworkRoomMember roomMember = Optional.ofNullable(imNetworkRoomMemberService.getDao().
                        findByRidAndUid(deviceStatusSync.getRoomId(), userId))
                .orElseThrow(()-> new BizException("用户不在房间内"));
        switch (deviceType) {
            case CAMERA:
                roomMember.setCameraFlag(deviceStatusSync.getEnable());
                break;
            case MICROPHONE:
                roomMember.setMicFlag(deviceStatusSync.getEnable());
                break;
            case HAND_UP:
                roomMember.setHandFlag(deviceStatusSync.getEnable());
                break;
            case MUSIC_MODE:
                roomMember.setMusicModeFlag(deviceStatusSync.getEnable());
                break;
            case EXAM_SONG:
                long scheduleId = Long.parseLong(deviceStatusSync.getRoomId());
                ImNetworkRoomMusicSheetDownloadData msg = courseScheduleStudentPaymentService.getMemberExamSong(scheduleId, userId);
                msg.setEnable(deviceStatusSync.getEnable());
                courseScheduleStudentPaymentService.getDao().adjustExamSong(scheduleId, userId, JSON.toJSONString(msg));
                break;
        }
        if(deviceType == ImNetworkDeviceTypeEnum.CAMERA ||
                deviceType == ImNetworkDeviceTypeEnum.MICROPHONE ||
                deviceType == ImNetworkDeviceTypeEnum.HAND_UP ||
                deviceType == ImNetworkDeviceTypeEnum.MUSIC_MODE){
            imNetworkRoomMemberService.getDao().updateById(roomMember);
        }
        //发送设备状态同步消息
        this.sendDeviceStateChangedMessage(deviceStatusSync,userId);
    }

    @Override
    public List<BasicUserInfo> queryNoJoinStu(Long roomId) {
        return courseScheduleStudentPaymentService.getDao().queryNoJoinStu(roomId);
    }

    //发送设备状态同步消息
    private void sendDeviceStateChangedMessage(ImNetworkDeviceControlDto deviceStatusSync,Long userId) throws Exception {
        ImNetworkRoom room = baseMapper.findByRoomId(deviceStatusSync.getRoomId());
        ImNetworkDeviceStateChangedMessage deviceResourceMessage = new ImNetworkDeviceStateChangedMessage(deviceStatusSync.getDeviceType().ordinal(),deviceStatusSync.getEnable());
        deviceResourceMessage.setUserId(userId.toString());
        deviceResourceMessage.setSoundVolume(room.getSoundVolume());
        imHelper.publishMessage(userId.toString(), deviceStatusSync.getRoomId(), deviceResourceMessage, 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rejectControlDevice(ImNetworkDeviceControlDto deviceControl) throws Exception {
        log.info("rejectControlDevice: roomId:{} ,deviceType:{}", deviceControl.getRoomId(),deviceControl.getDeviceType());
        SysUser sysUser = sysUserService.getUser();
        ImNetworkControlDeviceNotifyMessage msg = new ImNetworkControlDeviceNotifyMessage(ImNetworkActionEnum.REJECT.ordinal());
        msg.setType(deviceControl.getDeviceType().ordinal());
        msg.setOpUserId(sysUser.getId().toString());
        msg.setOpUserName(sysUser.getUsername());
        //获取老师编号
        Long teacherId = Optional.ofNullable(courseScheduleService.getById(deviceControl.getRoomId())).
                map(CourseSchedule::getTeacherId).
                orElseThrow(()->new BizException("房间信息不存在"));
        imHelper.publishMessage(sysUser.getId().toString(),teacherId.toString(), deviceControl.getRoomId(), msg);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void musicSheetDownNotify(ImNetworkMusicSheetDto musicSheetDto) throws Exception {
        Long roomId = Optional.ofNullable(musicSheetDto).map(ImNetworkBaseDto::getRoomId).orElseThrow(() -> new BizException("房间编号不能为空"));
        Long accompanimentId = Optional.ofNullable(musicSheetDto).map(ImNetworkMusicSheetDto::getAccompanimentId).orElseThrow(() -> new BizException("伴奏编号不能为空"));
        Integer status = Optional.ofNullable(musicSheetDto).map(ImNetworkMusicSheetDto::getStatus).orElseThrow(() -> new BizException("伴奏下载状态不能为空"));
        log.info("musicSheetDownNotify: roomId:{} ,accompanimentId:{} ,status:{}", roomId,accompanimentId,status);
        Long userId = sysUserService.getUserId();
        List<CourseScheduleStudentMusicSheetResult> studentMusicSheetResults = courseScheduleStudentMusicSheetService.getDao().queryBySheetIdAndCourseId(accompanimentId, roomId,userId, null, null);
        if(CollectionUtils.isEmpty(studentMusicSheetResults)){
            return;
        }
        Optional.ofNullable(musicSheetAccompanimentService.getById(accompanimentId)).
                orElseThrow(()-> new BizException("曲目信息不存在"));
        //修改下载状态
        CourseScheduleStudentMusicSheetResult musicSheetResult = studentMusicSheetResults.get(0);
        musicSheetResult.setDownStatus(status);
        courseScheduleStudentMusicSheetService.updateById(musicSheetResult);
        //给老师发送学员曲目下载状态
        CourseSchedule courseSchedule = courseScheduleService.getById(roomId);
        ImNetworkMusicSheetDownloadStatusMessage statusMessage = new ImNetworkMusicSheetDownloadStatusMessage(status,studentMusicSheetResults);
        imHelper.publishMessage(userId.toString(), courseSchedule.getTeacherId().toString(), roomId.toString(), statusMessage);
    }

    //校验用户是否提前进入教室
    private boolean roomNotStart(CourseSchedule courseSchedule){
        //是否提前进入教室
        String courseBeforeBufferTime = sysConfigDao.findConfigValue(SysConfigConstant.PRE_CREATE_PRACTICE_ROOM_MINUTE);
        if (StringUtils.isEmpty(courseBeforeBufferTime)) {
            courseBeforeBufferTime = "5";
        }
        Date addMinutes = DateUtil.addMinutes(courseSchedule.getStartTime(), Integer.parseInt(courseBeforeBufferTime));
        return courseSchedule.getStartTime().compareTo(addMinutes) > 0;
    }

    public ImNetworkRoom initRoom(String roomId,Long courseId,UserRoleEnum userRole,Long userId,Date now) throws Exception {
        ImNetworkRoom room = baseMapper.findByRoomId(roomId);
        String display = "";
        if (userRole == UserRoleEnum.TEACHER) {
            display = "display://type=0?userId=" + userId + "?uri=";
        }
        if(Objects.isNull(room)){
            room = new ImNetworkRoom();
            //创建房间
            room.setCourseScheduleId(courseId);
            room.setRoomId(roomId);
            room.setCreateTime(now);
            room.setUpdateTime(now);
            room.setDisplay(display);
            baseMapper.insert(room);
            IMApiResultInfo resultInfo = imHelper.createGroup(new String[]{userId.toString()}, roomId, roomId);
            if(resultInfo.getCode() != 200){
                log.error("创建群聊失败 resultInfo:{}",resultInfo);
            }
        }else {
            if(userRole == UserRoleEnum.TEACHER){
                room.setDisplay(display);
                baseMapper.updateById(room);
            }
        }
        return room;
    }

    //修改节拍器
    public void updateDisplay(Long userId,ImNetworkRoom room) throws Exception {
        baseMapper.updateById(room);
        this.sendDisplay(userId,room);
    }

    public void sendDisplay(Long userId,ImNetworkRoom room) throws Exception {
        //发送display改动通知
        ImNetworkDisplayMessage displayMessage = new ImNetworkDisplayMessage(room.getDisplay());
        imHelper.publishMessage(userId.toString(), room.getRoomId(), displayMessage, 0);
    }

    public boolean isUserDisplay(String display, Long userId) {
        boolean result = false;
        if (!display.isEmpty() && display.contains("userId=" + userId)) {
            if (display.contains("type=0") || display.contains("type=2")) {
                result = true;
            }
        }
        return result;
    }
}