package com.qmth.teachcloud.mark.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.teachcloud.common.bean.dto.mark.MarkUser;
import com.qmth.teachcloud.common.bean.params.mark.setting.MarkClassUserParams;
import com.qmth.teachcloud.common.bean.params.mark.setting.MarkGroupClassUserParams;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.mark.dto.mark.manage.MarkGroupClassProgressDto;
import com.qmth.teachcloud.mark.dto.mark.setting.MarkUserClassDetailDto;
import com.qmth.teachcloud.mark.dto.mark.setting.MarkUserClassDto;
import com.qmth.teachcloud.mark.entity.MarkGroup;
import com.qmth.teachcloud.mark.entity.MarkUserClass;
import com.qmth.teachcloud.mark.entity.MarkUserGroup;
import com.qmth.teachcloud.mark.mapper.MarkUserClassMapper;
import com.qmth.teachcloud.mark.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 评卷员班级 服务实现类
 * </p>
 *
 * @author xf
 * @since 2023-09-22
 */
@Service
public class MarkUserClassServiceImpl extends ServiceImpl<MarkUserClassMapper, MarkUserClass> implements MarkUserClassService {
    @Resource
    MarkUserGroupService markUserGroupService;

    @Resource
    MarkStudentService markStudentService;

    @Resource
    MarkGroupService markGroupService;

    @Resource
    MarkQuestionService markQuestionService;

    @Override
    public void deleteByExamIdAndPaperNumber(Long examId, String paperNumber) {
        UpdateWrapper<MarkUserClass> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(MarkUserClass::getExamId, examId)
                .eq(MarkUserClass::getPaperNumber, paperNumber);
        this.remove(updateWrapper);
    }

    @Override
    public MarkUserClassDto listMarkUserClassByExamIdAndPaperNumber(Long examId, String paperNumber) {
        // 课程下所有班级数据
        List<String> paperNumberClassList = markStudentService.listClassByExamIdAndCourseCode(examId, paperNumber);
        List<MarkUser> markUserList = markUserGroupService.listGroupUserByExamIdAndPaperNumberAndGroupNumberAndClassName(examId, paperNumber, null, null);

        MarkUserClassDto markUserClassDto = new MarkUserClassDto();
        markUserClassDto.setClassNames(paperNumberClassList);

        List<MarkUserClassDetailDto> markUserClassDetailDtos = new ArrayList<>();
        for (MarkUser marker : markUserList) {
            MarkUserClassDetailDto markUserClassDetailDto = new MarkUserClassDetailDto();
            markUserClassDetailDto.setMarker(marker);
            List<MarkUserClass> markUserClasses = this.baseMapper.listMarkerClassByExamIdAndPaperNumberAndUserId(examId, paperNumber, marker.getUserId());
            markUserClassDetailDto.setMarkerClassList(markUserClasses.stream().map(MarkUserClass::getClassName).collect(Collectors.toList()));
            markUserClassDetailDtos.add(markUserClassDetailDto);
        }
        markUserClassDto.setMarkerClass(markUserClassDetailDtos);
        return markUserClassDto;
    }

    @Override
    public List<MarkUser> listClassMarkerByExamIdAndPaperNumberAndGroupNumberAndClassName(Long examId, String paperNumber, Integer groupNumber, String className) {
        return this.baseMapper.listClassMarkerByExamIdAndPaperNumberAndGroupNumberAndClassName(examId, paperNumber, groupNumber, className);
    }

    @Transactional
    @Override
    public boolean saveMarkClassUser(MarkClassUserParams markClassUserParams) {
        Long examId = markClassUserParams.getExamId();
        String paperNumber = markClassUserParams.getPaperNumber();

        // 校验班级是否绑定完成
        List<String> listUserClass = markStudentService.listClassByExamIdAndCourseCode(examId, paperNumber);
        if (CollectionUtils.isNotEmpty(listUserClass)) {
            List<MarkGroup> markGroupList = markGroupService.listGroupByExamIdAndPaperNumber(examId, paperNumber);
            for (MarkGroup markGroup : markGroupList) {
                markGroup.setQuestionList(markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, markGroup.getNumber(), false));
                Set<String> groupBindClassSet = new HashSet<>();
                List<MarkUserGroup> markUserGroupList = markUserGroupService.listByExamIdAndPaperNumberAndGroupNumber(examId, paperNumber, markGroup.getNumber());
                for (MarkGroupClassUserParams groupUserClassInfo : markClassUserParams.getGroupMarkerClass()) {
                    if (markUserGroupList.stream().filter(m -> m.getUserId().equals(groupUserClassInfo.getMarker().getUserId())).count() > 0) {
                        groupBindClassSet.addAll(groupUserClassInfo.getMarkerClassList());
                    }
                }

                Collection<String> subtractList = CollectionUtils.subtract(listUserClass, groupBindClassSet);
                if (CollectionUtils.isNotEmpty(subtractList)) {
                    throw ExceptionResultEnum.ERROR.exception(String.format("班级[%s]在评阅题目[%s]中未被任何评卷员绑定", String.join(",", subtractList), markGroup.getGroupQuestions()));
                }
            }
        }

        List<MarkUserClass> markUserClasses = new ArrayList<>();
        for (MarkGroupClassUserParams groupUserClassInfo : markClassUserParams.getGroupMarkerClass()) {
            for (String className : groupUserClassInfo.getMarkerClassList()) {
                MarkUserClass markUserClass = new MarkUserClass();
                markUserClass.setId(SystemConstant.getDbUuid());
                markUserClass.setExamId(examId);
                markUserClass.setPaperNumber(paperNumber);
                markUserClass.setClassName(className);
                markUserClass.setUserId(groupUserClassInfo.getMarker().getUserId());
                markUserClasses.add(markUserClass);
            }
        }
        // 科目下所有数据同时提交
        this.deleteByExamIdAndPaperNumberAndClassName(examId, paperNumber, null);
        this.saveBatch(markUserClasses);
        return true;
    }

    @Override
    public boolean deleteByExamIdAndPaperNumberAndClassName(Long examId, String paperNumber, String className) {
        UpdateWrapper<MarkUserClass> updateWrapper = new UpdateWrapper<>();
        LambdaUpdateWrapper<MarkUserClass> lambdaUpdateWrapper = updateWrapper.lambda();
        lambdaUpdateWrapper.eq(MarkUserClass::getExamId, examId)
                .eq(MarkUserClass::getPaperNumber, paperNumber);
        if (StringUtils.isNotBlank(className)) {
            lambdaUpdateWrapper.eq(MarkUserClass::getClassName, className);
        }
        return this.remove(updateWrapper);
    }

    @Override
    public List<MarkUserClass> listByExamIdAndPaperNumber(Long examId, String paperNumber) {
        QueryWrapper<MarkUserClass> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkUserClass::getExamId, examId)
                .eq(MarkUserClass::getPaperNumber, paperNumber);
        return this.list(queryWrapper);
    }

    @Override
    public IPage<MarkGroupClassProgressDto> pageClassByExamIdAndPaperNumber(Page<MarkGroupClassProgressDto> page, Long examId, String paperNumber, String className) {
        return this.baseMapper.pageClassByExamIdAndPaperNumber(page, examId, paperNumber, className);
    }

    @Override
    public List<MarkUserClass> listByExamIdAndPaperNumberAndUserId(Long examId, String paperNumber, Long userId) {
        QueryWrapper<MarkUserClass> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkUserClass::getExamId, examId)
                .eq(MarkUserClass::getPaperNumber, paperNumber)
                .eq(MarkUserClass::getUserId, userId);
        return this.list(queryWrapper);
    }
}
