package jnpf.cultivate.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jnpf.base.UserInfo;
import jnpf.base.entity.SuperBaseEntity;
import jnpf.cultivate.mapper.FtbCultivateOfflineTrainMapper;
import jnpf.cultivate.mapper.FtbCultivatePositionCourceLearningMapper;
import jnpf.cultivate.service.FtbCultivateOfflineCourseService;
import jnpf.cultivate.service.FtbCultivateOfflineTrainService;
import jnpf.cultivate.service.FtbCultivateOfflineUserService;
import jnpf.cultivate.utils.UserApiV2Util;
import jnpf.model.cultivate.dto.offline.*;
import jnpf.model.cultivate.event.JnpfApplicationEvent;
import jnpf.model.cultivate.event.dto.course.CourseEventDTO;
import jnpf.model.cultivate.event.dto.file.FileEventDTO;
import jnpf.model.cultivate.po.FtbCultivateFile;
import jnpf.model.cultivate.po.offline.FtbCultivateOfflineCourse;
import jnpf.model.cultivate.po.offline.FtbCultivateOfflineTrain;
import jnpf.model.cultivate.po.offline.FtbCultivateOfflineUser;
import jnpf.model.cultivate.po.position.FtbCultivatePositionCourceLearning;
import jnpf.model.cultivate.vo.offline.*;
import jnpf.permission.UserApi;
import jnpf.permission.entity.UserEntity;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.util.UserProvider;
import jnpf.util.context.SpringContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class FtbCultivateOfflineTrainServiceImpl extends ServiceImpl<FtbCultivateOfflineTrainMapper, FtbCultivateOfflineTrain> implements FtbCultivateOfflineTrainService {

    @Resource
    private FtbCultivateOfflineUserService ftbCultivateOfflineUserService;
    @Resource
    private FtbCultivateOfflineCourseService ftbCultivateOfflineCourseService;
    @Resource
    private FtbCultivateFileService ftbCultivateFileService;
    @Autowired
    private UserApi userApi;
    @Autowired
    private UserApiV2Util userApiV2Util;

    @Autowired
    private FtbCultivatePositionCourceLearningMapper ftbCultivatePositionCourceLearningMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(FtbCultivateOfflineTrainDTO ftbCultivateCourseDTO) {
        FtbCultivateOfflineTrain ftbCultivateOfflineTrain = ftbCultivateCourseDTO.convertFtbCultivateOfflineTrain(ftbCultivateCourseDTO);
        baseMapper.insert(ftbCultivateOfflineTrain);
        // 参与培训人员
        List<FtbCultivateOfflineUser> ftbCultivateOfflineUsers = ftbCultivateCourseDTO.getUserIds()
                .stream()
                .map(FtbCultivateOfflineTrainDTO::convertFtbCultivateOfflineUser)
                .peek(ftbCultivateOfflineUser -> {
                    ftbCultivateOfflineUser.setOffilneId(ftbCultivateOfflineTrain.getId());
                }).collect(Collectors.toList());
        ftbCultivateOfflineUserService.saveBatch(ftbCultivateOfflineUsers);
        if (CollUtil.isNotEmpty(ftbCultivateCourseDTO.getCourseIds())) {
            // 培训课程
            List<FtbCultivateOfflineCourse> ftbCultivateOfflineCourses = ftbCultivateCourseDTO.getCourseIds()
                    .stream()
                    .map(FtbCultivateOfflineTrainDTO::convertFtbCultivateOfflineCourse)
                    .peek(ftbCultivateOfflineCourse -> {
                        ftbCultivateOfflineCourse.setOffilneId(ftbCultivateOfflineTrain.getId());
                    }).collect(Collectors.toList());
            ftbCultivateOfflineCourseService.saveBatch(ftbCultivateOfflineCourses);
            // 课程进度，参与培训所有人员需要学习的课程,线下培训课程需要和岗位学习课程同步
            SpringContext.getApplicationContext().publishEvent(new JnpfApplicationEvent<>(
                    CourseEventDTO.builder()
                            .courseIds(ftbCultivateCourseDTO.getCourseIds())
                            .userIds(ftbCultivateCourseDTO.getUserIds()).whetherToChange(false).build()));
        }
        // 附件文件
        if (CollUtil.isNotEmpty(ftbCultivateCourseDTO.getFiles())) {
            SpringContext.getApplicationContext().publishEvent(new JnpfApplicationEvent<>(FileEventDTO.builder()
                    .files(ftbCultivateCourseDTO.getFiles())
                    .businessTypeID(ftbCultivateOfflineTrain.getId())
                    .type(FileEventDTO.FileType.OFFLINE_TRAINING)
                    .build()));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrainingResults(UserInfo userInfo, FtbCultivateOfflineTrainUpdateDTO ftbCultivateCourseDTO) {
        LambdaUpdateWrapper<FtbCultivateOfflineTrain> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(SuperBaseEntity.SuperIBaseEntity::getId, ftbCultivateCourseDTO.getId());
        updateWrapper.set(FtbCultivateOfflineTrain::getFeedHeadUserId, userInfo.getUserId());
        updateWrapper.set(FtbCultivateOfflineTrain::getHeadContent, ftbCultivateCourseDTO.getHeadContent());
        updateWrapper.set(FtbCultivateOfflineTrain::getFeedBackTime, new Date());
        baseMapper.update(new FtbCultivateOfflineTrain(), updateWrapper);
    }

    @Override
    public FtbCultivateOfflineTrainDetailsVO courseDetails(String id) {
        LambdaQueryWrapper<FtbCultivateOfflineTrain> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(SuperBaseEntity.SuperIBaseEntity::getId, id);
        FtbCultivateOfflineTrain ftbCultivateOfflineTrain = baseMapper.selectOne(queryWrapper);
        FtbCultivateOfflineTrainDetailsVO ftbCultivateOfflineTrainDetailsVO = FtbCultivateOfflineTrainDetailsVO
                .convertFtbCultivateOfflineTrainDetailsVO(ftbCultivateOfflineTrain);
        // 培训参与人员
        LambdaQueryWrapper<FtbCultivateOfflineUser> offlineUserQueryWrapper = Wrappers.lambdaQuery();
        offlineUserQueryWrapper.eq(FtbCultivateOfflineUser::getOffilneId, id);
        List<FtbCultivateOfflineUser> list = ftbCultivateOfflineUserService.list(offlineUserQueryWrapper);
        List<String> collect = list.stream().map(FtbCultivateOfflineUser::getUserId).collect(Collectors.toList());
        ftbCultivateOfflineTrainDetailsVO.setParticipantsInTheTraining(collect);
        // 参与培训人员姓名集合
//        List<PartUserInfoVo> userApiInfoByIds = userApi.getInfoByIds(collect);
        List<UserBoundVO> userPrimaryBoundBatch = userApiV2Util.getUserPrimaryBoundBatchReturnList(collect, null);
        List<String> userNames = userPrimaryBoundBatch.stream().map(UserBoundVO::getName).collect(Collectors.toList());
        ftbCultivateOfflineTrainDetailsVO.setParticipantsInTheTrainingName(userNames);
        // 课程信息
        ftbCultivateOfflineTrainDetailsVO.setCourseInfo(baseMapper.listOfflineWebCourseVO(id));
        // 上传附件信息
        LambdaQueryWrapper<FtbCultivateFile> fileQueryWrapper = Wrappers.lambdaQuery();
        fileQueryWrapper.eq(FtbCultivateFile::getBusinessId, ftbCultivateOfflineTrain.getId());
        fileQueryWrapper.eq(FtbCultivateFile::getType, 0);
        List<FtbCultivateFile> ftbCultivateFiles = ftbCultivateFileService.list(fileQueryWrapper);
        List<FtbCultivateOfflineFileVO> ftbCultivateOfflineFileVOS = ftbCultivateFiles.stream()
                .map(FtbCultivateOfflineFileVO::convertFtbCultivateOfflineFileVO).collect(Collectors.toList());
        ftbCultivateOfflineTrainDetailsVO.setFiles(ftbCultivateOfflineFileVOS);

        LambdaQueryWrapper<FtbCultivateFile> fileFeedbackWrapper = Wrappers.lambdaQuery();
        fileFeedbackWrapper.eq(FtbCultivateFile::getBusinessId, ftbCultivateOfflineTrain.getId());
        fileFeedbackWrapper.eq(FtbCultivateFile::getType,FileEventDTO.FileType.OFFLINE_TRAINING_FEEDBACK.getType());
        fileFeedbackWrapper.eq(FtbCultivateFile::getEnabledMark, 0);
        List<FtbCultivateFile> feedBackFiles = ftbCultivateFileService.list(fileFeedbackWrapper);
        if(CollUtil.isNotEmpty(feedBackFiles)) {
            List<FtbCultivateOfflineFileVO> feedBackFilesVo = feedBackFiles.stream()
                    .map(FtbCultivateOfflineFileVO::convertFtbCultivateOfflineFileVO).collect(Collectors.toList());
            ftbCultivateOfflineTrainDetailsVO.setFeedBackFiles(feedBackFilesVo);
        }
        // 反馈负责人姓名
        List<String> userIds = new ArrayList<>();
        if(StringUtils.isNotEmpty(ftbCultivateOfflineTrainDetailsVO.getFeedHeadUserId())){
            userIds.add(ftbCultivateOfflineTrainDetailsVO.getFeedHeadUserId());
        }
        if(StringUtils.isNotEmpty(ftbCultivateOfflineTrainDetailsVO.getUserId())){
            userIds.add(ftbCultivateOfflineTrainDetailsVO.getUserId());
        }
        if(StringUtils.isNotEmpty(ftbCultivateOfflineTrainDetailsVO.getHeadUserId())){
            userIds.add(ftbCultivateOfflineTrainDetailsVO.getHeadUserId());
        }
        if (CollUtil.isNotEmpty(userIds)) {
            Map<String, UserEntity> userNameAndCopyForUserIds = userApiV2Util.getUserNameAndCopyForUserIds(userIds);
            UserEntity feedUser = userNameAndCopyForUserIds.get(ftbCultivateOfflineTrainDetailsVO.getFeedHeadUserId());
            if (feedUser != null) {
                ftbCultivateOfflineTrainDetailsVO.setFeedHeadUserName(feedUser.getRealName());
            }

            UserEntity userEntity = userNameAndCopyForUserIds.get(ftbCultivateOfflineTrainDetailsVO.getUserId());
            if (userEntity != null) {
                ftbCultivateOfflineTrainDetailsVO.setUserName(userEntity.getRealName());
            }

            UserEntity headUser = userNameAndCopyForUserIds.get(ftbCultivateOfflineTrainDetailsVO.getHeadUserId());
            if (headUser != null) {
                ftbCultivateOfflineTrainDetailsVO.setHeadUserName(headUser.getRealName());
            }
        }
        return ftbCultivateOfflineTrainDetailsVO;
    }

    @Override
    public Page<FtbCultivateOfflineTrainPageVO> listPage(Page<FtbCultivateOfflineTrainPageVO> page, String keywords) {
        Page<FtbCultivateOfflineTrainPageVO> result = baseMapper.listPage(page, keywords);
        List<String> userIds = result.getRecords().stream()
                .map(FtbCultivateOfflineTrainPageVO::getUserId).collect(Collectors.toList());
        List<String> headUserIds = result.getRecords().stream()
                .map(FtbCultivateOfflineTrainPageVO::getHeadUserId).collect(Collectors.toList());
        userIds.addAll(headUserIds);
//        List<PartUserInfoVo> infoByIds = userApi.getInfoByIds(userIds);
        Map<String, UserEntity>  userInfoMap  = userApiV2Util.getUserNameAndCopyForUserIds(userIds);
        result.getRecords().forEach(ftbCultivateOfflineTrainPageVO -> {
            // 申请人姓名
            UserEntity userEntity = userInfoMap.get(ftbCultivateOfflineTrainPageVO.getUserId());
            if(userEntity!=null) {
                ftbCultivateOfflineTrainPageVO.setUserName(userEntity.getRealName());
            }
            // 负责人姓名
            UserEntity userEntity1 = userInfoMap.get(ftbCultivateOfflineTrainPageVO.getHeadUserId());
            if(userEntity1!=null) {
                ftbCultivateOfflineTrainPageVO.setHeadUserName(userEntity1.getRealName());
            }
            // 参与培训人员数量
            LambdaQueryWrapper<FtbCultivateOfflineUser> offlineUserQueryWrapper = Wrappers.lambdaQuery();
            offlineUserQueryWrapper.eq(FtbCultivateOfflineUser::getOffilneId, ftbCultivateOfflineTrainPageVO.getId());
            ftbCultivateOfflineTrainPageVO.setParticipateTrainingMembers(Math.toIntExact(
                    ftbCultivateOfflineUserService.count(offlineUserQueryWrapper)));
            // 培训课程数量
            LambdaQueryWrapper<FtbCultivateOfflineCourse> offlineCourseQueryWrapper = Wrappers.lambdaQuery();
            offlineCourseQueryWrapper.eq(FtbCultivateOfflineCourse::getOffilneId, ftbCultivateOfflineTrainPageVO.getId());
            ftbCultivateOfflineTrainPageVO.setTrainingCourses(Math.toIntExact(
                    ftbCultivateOfflineCourseService.count(offlineCourseQueryWrapper)));
            // 培训状态
            Integer state = doTrainingStatus(ftbCultivateOfflineTrainPageVO.getState(),
                    ftbCultivateOfflineTrainPageVO.getTrainStartTime(),
                    ftbCultivateOfflineTrainPageVO.getTrainEndTime());
            ftbCultivateOfflineTrainPageVO.setState(state);
        });
        return result;
    }

    @Override
    public FtbCultivateOfflineTrainDetailsAppVO offlineAppDetails(String id) {
        FtbCultivateOfflineTrainDetailsVO offlineTrainWeb = courseDetails(id);
        // 课程信息
        String loginUserId = UserProvider.getLoginUserId();
        List<OfflineCourseVO> offlineCourseVOS = baseMapper.listOfflineCourseVO(id, loginUserId);
        fillStudyState(offlineCourseVOS,loginUserId);
        offlineTrainWeb.setCourseInfo(offlineCourseVOS);
        FtbCultivateOfflineTrainDetailsAppVO result = FtbCultivateOfflineTrainDetailsAppVO.convertFtbCultivateOfflineTrainDetailsVO(offlineTrainWeb);
        // 参与培训人员姓名头像信息
        LambdaQueryWrapper<FtbCultivateOfflineUser> offlineUserQueryWrapper = Wrappers.lambdaQuery();
        offlineUserQueryWrapper.eq(FtbCultivateOfflineUser::getOffilneId, id);
        Map<String, FtbCultivateOfflineUser> cultivateOfflineUsers = ftbCultivateOfflineUserService.list(offlineUserQueryWrapper)
                .stream()
                .collect(Collectors.toMap(FtbCultivateOfflineUser::getUserId, a -> a, (k1, k2) -> k1));
        List<UserInfoVO> userInfoVOS = userApiV2Util.getUserPrimaryBoundBatchReturnList(result.getParticipantsInTheTraining(), null)
                .stream()
                .map(UserInfoVO::convertUserInfoVO)
                .peek(a -> {
                    FtbCultivateOfflineUser ftbCultivateOfflineUser = cultivateOfflineUsers.get(a.getUserId());
                    if (ftbCultivateOfflineUser != null) {
                        a.setCheckInOrNot(ftbCultivateOfflineUser.getSignWhether());
                    }
                })
                .collect(Collectors.toList());
        result.setUserInfos(userInfoVOS);
        // 反馈负责人姓名
        // 反馈负责人姓名
        List<String> userIds = new ArrayList<>();
        if(StringUtils.isNotEmpty(result.getFeedHeadUserId())){
            userIds.add(result.getFeedHeadUserId());
        }
        if(StringUtils.isNotEmpty(result.getUserId())){
            userIds.add(result.getUserId());
        }
        if(StringUtils.isNotEmpty(result.getHeadUserId())){
            userIds.add(result.getHeadUserId());
        }
        if (CollUtil.isNotEmpty(userIds)) {
            Map<String, UserEntity> userNameAndCopyForUserIds = userApiV2Util.getUserNameAndCopyForUserIds(userIds);
            UserEntity feedUser = userNameAndCopyForUserIds.get(result.getFeedHeadUserId());
            if (feedUser != null) {
                result.setFeedHeadUserName(feedUser.getRealName());
            }

            UserEntity userEntity = userNameAndCopyForUserIds.get(result.getUserId());
            if (userEntity != null) {
                result.setUserName(userEntity.getRealName());
            }

            UserEntity headUser = userNameAndCopyForUserIds.get(result.getHeadUserId());
            if (headUser != null) {
                result.setHeadUserName(headUser.getRealName());
            }
        }
        // 已学习课程数
        long count = result.getCourseInfo().stream()
                .filter(offlineCourseVO -> offlineCourseVO.getState() == 1).count();
        result.setNumberOfCoursesTaken(Math.toIntExact(count));
        // 总学习课程数
        result.setTotalNumberOfStudyCourses(result.getCourseInfo().size());
        // 培训状态
        // 当前时间小于开始时间，未开始
        Integer state = doTrainingStatus(result.getState(), result.getTrainStartTime(), result.getTrainEndTime());
        result.setState(state);
        List<FtbCultivateFile> ftbCultivateFiles = queryFilesLists(List.of(offlineTrainWeb.getId()), FileEventDTO.FileType.OFFLINE_TRAINING_FEEDBACK.getType());
        if(CollUtil.isNotEmpty(ftbCultivateFiles)) {
            result.setFeedBackFiles(ftbCultivateFiles.stream().map(ftbCultivateFile -> FtbCultivateOfflineFileVO.convertFtbCultivateOfflineFileVO(ftbCultivateFile)).collect(Collectors.toList()));
        }
        return result;
    }

    private void fillStudyState(List<OfflineCourseVO> offlineCourseVOS, String userId) {
        List<String> courseIds = offlineCourseVOS.stream().map(OfflineCourseVO::getCourseId).collect(Collectors.toList());
        if (CollUtil.isEmpty(courseIds)) {
            return;
        }

        // 构建查询条件，查询用户在指定课程中的学习情况
        LambdaQueryWrapper<FtbCultivatePositionCourceLearning> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(FtbCultivatePositionCourceLearning::getId, FtbCultivatePositionCourceLearning::getCourceId, FtbCultivatePositionCourceLearning::getState,
                FtbCultivatePositionCourceLearning::getLearnTime);
        queryWrapper.eq(FtbCultivatePositionCourceLearning::getUserId, userId);
        queryWrapper.in(FtbCultivatePositionCourceLearning::getCourceId, courseIds);
        queryWrapper.eq(FtbCultivatePositionCourceLearning::getEnabledMark, 0); // 有效标志为0表示有效

        List<FtbCultivatePositionCourceLearning> courseLearnings = ftbCultivatePositionCourceLearningMapper.selectList(queryWrapper);

        // 构建key为userId-courseId的映射
        Map<String, FtbCultivatePositionCourceLearning> resultMap = new HashMap<>();
        for (FtbCultivatePositionCourceLearning learning : courseLearnings) {
            resultMap.put(learning.getCourceId(), learning);
        }
        for (OfflineCourseVO offlineCourseVO : offlineCourseVOS) {
            FtbCultivatePositionCourceLearning ftbCultivatePositionCourceLearning = resultMap.get(offlineCourseVO.getCourseId());
            if (ftbCultivatePositionCourceLearning == null) {
                offlineCourseVO.setState(0);
                continue;
            }
            offlineCourseVO.setState(ftbCultivatePositionCourceLearning.getState());
        }
    }

    public List<FtbCultivateFile> queryFilesLists(List<String> businessIds, Integer type) {
        LambdaQueryWrapper<FtbCultivateFile> wrapperItemFile = Wrappers.lambdaQuery();
        wrapperItemFile.in(FtbCultivateFile::getBusinessId, businessIds);
        wrapperItemFile.eq(FtbCultivateFile::getType, type);
        wrapperItemFile.eq(FtbCultivateFile::getEnabledMark,0);
        wrapperItemFile.orderByAsc(FtbCultivateFile::getCreatorTime);
        List<FtbCultivateFile> list = ftbCultivateFileService.list(wrapperItemFile);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list;
    }

    @Override
    public Page<FtbOfflineTrainingAppPageVO> offlineTrainingApp(Page<FtbOfflineTrainingAppPageVO> page, Integer type) {
        String userId = UserProvider.getUser().getUserId();
        // 查询类型，null为全部培训，1为我发起的，2为我参与的，3为我负责的
        Page<FtbOfflineTrainingAppPageVO> result = baseMapper.listOfflineTrainingApp(page, type, userId);
        result.getRecords().forEach(ftbOfflineTrainingAppPageVO -> {
            // 负责人姓名
            UserEntity userEntity = userApi.getInfoById(ftbOfflineTrainingAppPageVO.getHeadUserId());
            if (Objects.nonNull(userEntity)) {
                ftbOfflineTrainingAppPageVO.setHeadUserName(userEntity.getRealName());
            }
            // 参与人员
            LambdaQueryWrapper<FtbCultivateOfflineUser> offlineUserQueryWrapper = Wrappers.lambdaQuery();
            offlineUserQueryWrapper.eq(FtbCultivateOfflineUser::getOffilneId, ftbOfflineTrainingAppPageVO.getId());
            List<FtbCultivateOfflineUser> ftbCultivateOfflineUsers = ftbCultivateOfflineUserService.list(offlineUserQueryWrapper);
            List<String> userIds = ftbCultivateOfflineUsers.stream()
                    .map(FtbCultivateOfflineUser::getUserId).collect(Collectors.toList());
//            List<PartUserInfoVo> infoByIds = userApi.getInfoByIds(userIds);
            List<UserBoundVO> userPrimaryBoundBatchReturnList = userApiV2Util.getUserPrimaryBoundBatchReturnList(userIds, null);
            List<String> userNames = userPrimaryBoundBatchReturnList.stream().map(UserBoundVO::getName).collect(Collectors.toList());
            ftbOfflineTrainingAppPageVO.setUserInfos(userNames);
            // 培训状态
            Integer state = doTrainingStatus(ftbOfflineTrainingAppPageVO.getState(),
                    ftbOfflineTrainingAppPageVO.getTrainStartTime(),
                    ftbOfflineTrainingAppPageVO.getTrainEndTime());
            ftbOfflineTrainingAppPageVO.setState(state);
            // 只有【进行中】，且参与人员包含登陆人，则显示【签到】按钮
            ftbOfflineTrainingAppPageVO.setShowSignInButton(1);
            if (state != null && state == 2) {
                ftbOfflineTrainingAppPageVO.setShowSignInButton(userIds.contains(userId) ? 0 : 1);
            }
        });
        return result;
    }

    @Override
    @Transactional
    public void deleteOfflineTrain(String id) {
        LambdaUpdateWrapper<FtbCultivateOfflineTrain> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(FtbCultivateOfflineTrain::getId, id);
        updateWrapper.set(FtbCultivateOfflineTrain::getEnableMark, 1);
        update(new FtbCultivateOfflineTrain(), updateWrapper);
    }

    @Override
    public List<String> queryExistingMembers(String id) {
        LambdaQueryWrapper<FtbCultivateOfflineUser> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(FtbCultivateOfflineUser::getUserId);
        queryWrapper.eq(FtbCultivateOfflineUser::getOffilneId, id);
        return ftbCultivateOfflineUserService.list(queryWrapper)
                .stream()
                .map(FtbCultivateOfflineUser::getUserId)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void modifyOfflineTrainingMembers(FtbModifyOfflineTrainingMembersDTO data) {
        LambdaQueryWrapper<FtbCultivateOfflineUser> removeWrapper = Wrappers.lambdaQuery();
        removeWrapper.eq(FtbCultivateOfflineUser::getOffilneId, data.getOfflineTrainId());
        // 原有用户
        List<FtbCultivateOfflineUser> oldOfflineUsers = ftbCultivateOfflineUserService.list(removeWrapper);
        removeWrapper.notIn(FtbCultivateOfflineUser::getUserId, data.getUserIds());
        List<String> oldUserIds = oldOfflineUsers.stream().map(FtbCultivateOfflineUser::getUserId).collect(Collectors.toList());
        List<FtbCultivateOfflineUser> ftbCultivateOfflineUsers = data.getUserIds()
                .stream()
                .filter(a -> !oldUserIds.contains(a))
                .map(a -> {
                    FtbCultivateOfflineUser ftbCultivateOfflineUser = new FtbCultivateOfflineUser();
                    ftbCultivateOfflineUser.setUserId(a);
                    ftbCultivateOfflineUser.setOffilneId(data.getOfflineTrainId());
                    ftbCultivateOfflineUser.setSignWhether(0);
                    return ftbCultivateOfflineUser;
                }).collect(Collectors.toList());
        // 删除不存在的用户
        ftbCultivateOfflineUserService.remove(removeWrapper);
        ftbCultivateOfflineUserService.saveBatch(ftbCultivateOfflineUsers);
        // 维护参与人员冗余字段
        LambdaUpdateWrapper<FtbCultivateOfflineTrain> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(FtbCultivateOfflineTrain::getId, data.getOfflineTrainId());
        updateWrapper.set(FtbCultivateOfflineTrain::getParticipants, String.join(",", data.getUserIds()));
        update(new FtbCultivateOfflineTrain(), updateWrapper);
        // 课程绑定
        List<String> courseIds = this.getBaseMapper().queryCourseIdsByOfflineId(data.getOfflineTrainId());
        // 课程进度，参与培训所有人员需要学习的课程,线下培训课程需要和岗位学习课程同步
        SpringContext.getApplicationContext().publishEvent(new JnpfApplicationEvent<>(
                CourseEventDTO.builder()
                        .courseIds(courseIds)
                        .userIds(data.getUserIds())
                        .whetherToChange(false)
                        .build()));
    }

    @Override
    @Transactional
    public void withdraw(String id) {
        LambdaUpdateWrapper<FtbCultivateOfflineTrain> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(SuperBaseEntity.SuperIBaseEntity::getId, id);
        updateWrapper.set(FtbCultivateOfflineTrain::getState, 3);
        update(new FtbCultivateOfflineTrain(), updateWrapper);
    }

    @Override
    public Page<FtbCultivateOfflineTrainPeopleSigningInVO> numberOfflineTraining(Page<FtbCultivateOfflineTrainPeopleSigningInVO> page, FtbCultivateOfflineTrainPeopleSigningInDTO data) {
        return this.getBaseMapper().numberOfflineTraining(page, data);
    }

    @Override
    @Transactional
    public void editOfflineTraining(FtbCultivateOfflineTrainChangeDTO ftbCultivateOfflineTrainDTO) {
        LambdaUpdateWrapper<FtbCultivateOfflineTrain> updateWrapper = FtbCultivateOfflineTrainChangeDTO.convert(ftbCultivateOfflineTrainDTO);
        update(new FtbCultivateOfflineTrain(), updateWrapper);
        // 线下培训课程
        LambdaQueryWrapper<FtbCultivateOfflineCourse> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbCultivateOfflineCourse::getOffilneId, ftbCultivateOfflineTrainDTO.getId());
        ftbCultivateOfflineCourseService.remove(queryWrapper);
        List<FtbCultivateOfflineCourse> ftbCultivateOfflineCourses = ftbCultivateOfflineTrainDTO.getCourseIds()
                .stream()
                .map(a -> {
                    FtbCultivateOfflineCourse ftbCultivateOfflineCourse = new FtbCultivateOfflineCourse();
                    ftbCultivateOfflineCourse.setCourseId(a);
                    ftbCultivateOfflineCourse.setOffilneId(ftbCultivateOfflineTrainDTO.getId());
                    return ftbCultivateOfflineCourse;
                }).collect(Collectors.toList());
        ftbCultivateOfflineCourseService.saveBatch(ftbCultivateOfflineCourses);
        // 附件
        this.getBaseMapper().deleteOfflineTrainFileById(ftbCultivateOfflineTrainDTO.getId());
        if (CollUtil.isNotEmpty(ftbCultivateOfflineTrainDTO.getFiles())) {
            SpringContext.getApplicationContext().publishEvent(new JnpfApplicationEvent<>(FileEventDTO.builder()
                    .files(ftbCultivateOfflineTrainDTO.getFiles())
                    .businessTypeID(ftbCultivateOfflineTrainDTO.getId())
                    .type(FileEventDTO.FileType.OFFLINE_TRAINING)
                    .build()));
        }
        // 线下培训参与人员
        FtbModifyOfflineTrainingMembersDTO modifyOfflineTrainingMembersDTO = new FtbModifyOfflineTrainingMembersDTO();
        modifyOfflineTrainingMembersDTO.setOfflineTrainId(ftbCultivateOfflineTrainDTO.getId());
        modifyOfflineTrainingMembersDTO.setUserIds(ftbCultivateOfflineTrainDTO.getUserIds());
        modifyOfflineTrainingMembers(modifyOfflineTrainingMembersDTO);
    }

    @Override
    @Transactional
    public void signIn(FtbCultivateOfflineTrainSignInDTO freightTrainSignInDTO) {
        if (freightTrainSignInDTO.getSignWay() == 1 && StrUtil.isBlank(freightTrainSignInDTO.getSignPhoto())) {
            throw new RuntimeException("请上传拍照签到的照片");
        }
        LambdaUpdateWrapper<FtbCultivateOfflineUser> offlineUserLambdaUpdateWrapper = Wrappers.lambdaUpdate();
        offlineUserLambdaUpdateWrapper.eq(FtbCultivateOfflineUser::getOffilneId, freightTrainSignInDTO.getOfflineTrainId());
        offlineUserLambdaUpdateWrapper.eq(FtbCultivateOfflineUser::getUserId, UserProvider.getLoginUserId());
        offlineUserLambdaUpdateWrapper.set(FtbCultivateOfflineUser::getSignWhether, 1);
        offlineUserLambdaUpdateWrapper.set(FtbCultivateOfflineUser::getSignTime, new Date());
        offlineUserLambdaUpdateWrapper.set(FtbCultivateOfflineUser::getSignPhoto, freightTrainSignInDTO.getSignPhoto());
        ftbCultivateOfflineUserService.update(new FtbCultivateOfflineUser(), offlineUserLambdaUpdateWrapper);
    }


    /**
     * 培训状态
     *
     * @param state          培训状态，0未开始，1已结束，2进行中,3已撤回
     * @param trainStartTime 培训开始时间
     * @param trainEndTime   培训结束时间
     * @return {@link Integer}
     */
    private Integer doTrainingStatus(Integer state, Date trainStartTime, Date trainEndTime) {
        if (state == 3) {
            return state;
        }
        Date now = new Date();
        if (DateUtil.compare(now, trainStartTime) < 0) {
            return 0;
        } else if (DateUtil.compare(now, trainStartTime) >= 0 &&
                DateUtil.compare(now, trainEndTime) <= 0) {
            // 当前时间大于开始时间，小于结束时间，进行中
            return 2;
        } else if (DateUtil.compare(now, trainEndTime) > 0) {
            // 当前时间大于结束时间，已结束
            return 1;
        }
        return null;
    }
}
