package com.qmth.distributed.print.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.google.common.collect.Lists;
import com.qmth.distributed.print.business.bean.dto.excel.TeachCourseDto;
import com.qmth.distributed.print.business.bean.dto.excel.TeacherTeamDto;
import com.qmth.distributed.print.business.bean.params.TeachCourseParams;
import com.qmth.distributed.print.business.bean.params.TeacherTeamParam;
import com.qmth.distributed.print.business.bean.result.DictionaryResult;
import com.qmth.distributed.print.business.bean.result.TeachCourseResult;
import com.qmth.distributed.print.business.entity.TeachCourse;
import com.qmth.distributed.print.business.mapper.TeachCourseMapper;
import com.qmth.distributed.print.business.service.TeachCourseService;
import com.qmth.teachcloud.common.base.BaseEntity;
import com.qmth.teachcloud.common.bean.params.BasicCourseParams;
import com.qmth.teachcloud.common.bean.params.UserSaveParams;
import com.qmth.teachcloud.common.bean.result.TeacherSelectResult;
import com.qmth.teachcloud.common.bean.result.TeacherTeamResult;
import com.qmth.teachcloud.common.bean.result.UserRoleNameResult;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicCourse;
import com.qmth.teachcloud.common.entity.SysRole;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.RoleTypeEnum;
import com.qmth.teachcloud.common.service.BasicCourseService;
import com.qmth.teachcloud.common.service.SysOrgService;
import com.qmth.teachcloud.common.service.SysRoleService;
import com.qmth.teachcloud.common.service.SysUserService;
import com.qmth.teachcloud.common.util.ExcelUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description: 教学课程服务实现类
 * @Author: CaoZixuan
 * @Date: 2022-02-07
 */
@Service
public class TeachCourseServiceImpl extends ServiceImpl<TeachCourseMapper, TeachCourse> implements TeachCourseService {
    @Resource
    private BasicCourseService basicCourseService;
    @Resource
    private SysOrgService sysOrgService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysRoleService sysRoleService;

    @Override
    public IPage<TeachCourseResult> teachCoursePage(String courseName, int pageNumber, int pageSize, Long userId) {
        if (!SystemConstant.longNotNull(userId)) {
            throw ExceptionResultEnum.ERROR.exception("请先登录");
        }
        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
        courseName = SystemConstant.translateSpecificSign(courseName);
        return this.baseMapper.findTeachCoursePage(new Page<>(pageNumber, pageSize), courseName, userId, schoolId);
    }

    @Transactional
    @Override
    public Boolean manualCreate(TeachCourseParams teachCourseParams, SysUser requestUser) {
        String courseCode = teachCourseParams.getCourseCode();
        String courseName = teachCourseParams.getCourseName();
        Long schoolId = requestUser.getSchoolId();
        Long userId = requestUser.getId();
        Long basicCourseId;

        // 校验
        BasicCourse basicCourse = basicCourseService.getOne(new QueryWrapper<BasicCourse>()
                .lambda()
                .eq(BasicCourse::getSchoolId, schoolId)
                .eq(BasicCourse::getCode, courseCode));
        if (Objects.nonNull(basicCourse)) {
            // 根据课程编号查询存在课程判断名称是否一致
            if (!courseName.equals(basicCourse.getName())) {
                throw ExceptionResultEnum.ERROR.exception("课程编号为【" + courseCode + "】的课程名称错误");
            } else {
                basicCourseId = basicCourse.getId();
                // 判断重复教学课程
                if (this.count(new QueryWrapper<TeachCourse>()
                        .lambda()
                        .eq(TeachCourse::getSchoolId, schoolId)
                        .eq(TeachCourse::getUserId, userId)
                        .eq(TeachCourse::getBasicCourseId, basicCourseId)) > 0) {
                    throw ExceptionResultEnum.ERROR.exception("课程【" + courseName + "】已经创建");
                }
            }
        } else {
            // 不存在课程,直接新增一个课程！
            BasicCourseParams basicCourseParams = new BasicCourseParams();
            basicCourseParams.setCourseCode(courseCode);
            basicCourseParams.setCourseName(courseName);
            basicCourseParams.setTeachingRoomId(requestUser.getOrgId());
            basicCourseId = basicCourseService.saveBasicCourse(basicCourseParams, requestUser);
        }
        TeachCourse teachCourse = new TeachCourse();
        teachCourse.setSchoolId(schoolId);
        teachCourse.setBasicCourseId(basicCourseId);
        teachCourse.setUserId(userId);
        teachCourse.setEnable(true);
        teachCourse.insertInfo(userId);
        return this.save(teachCourse);
    }

    @Transactional
    @Override
    public void selectCreate(List<Long> basicCourseIdList, SysUser requestUser) {
        Long schoolId = requestUser.getSchoolId();
        Long userId = requestUser.getId();
        if (CollectionUtils.isNotEmpty(basicCourseIdList)) {
            basicCourseIdList = basicCourseService.listByIds(basicCourseIdList)
                    .stream()
                    .filter(BasicCourse::getEnable)
                    .map(BaseEntity::getId)
                    .distinct()
                    .collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(basicCourseIdList)) {
                List<Long> alreadyCreated = this.list(new QueryWrapper<TeachCourse>().lambda()
                                .eq(TeachCourse::getUserId, userId)
                                .in(TeachCourse::getBasicCourseId, basicCourseIdList))
                        .stream()
                        .map(TeachCourse::getBasicCourseId)
                        .distinct()
                        .collect(Collectors.toList());

                // 去掉已经创建的教学课程
                basicCourseIdList.removeAll(alreadyCreated);
                // 创建教学课程
                List<TeachCourse> teachCourseList = basicCourseIdList.stream().flatMap(e -> {
                    TeachCourse teachCourse = new TeachCourse();
                    teachCourse.setSchoolId(schoolId);
                    teachCourse.setBasicCourseId(e);
                    teachCourse.setUserId(userId);
                    teachCourse.setEnable(true);
                    teachCourse.insertInfo(userId);
                    return Stream.of(teachCourse);
                }).collect(Collectors.toList());

                // 新增课程
                this.saveBatch(teachCourseList);
            }
        }
    }

    @Transactional
    @Override
    public void importTeachCourse(MultipartFile file, SysUser requestUser) throws IOException, NoSuchFieldException {
        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(TeachCourseDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });

        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> teachCourseImportDtoList = map.get(i);
                for (int y = 0; y < Objects.requireNonNull(teachCourseImportDtoList).size(); y++) {
                    if (teachCourseImportDtoList.get(y) instanceof TeachCourseDto) {
                        TeachCourseDto teachCourseDto = (TeachCourseDto) teachCourseImportDtoList.get(y);
                        String courseCode = teachCourseDto.getCourseCode();
                        String courseName = teachCourseDto.getCourseName();
                        TeachCourseParams teachCourseParams = new TeachCourseParams();
                        teachCourseParams.setCourseCode(courseCode);
                        teachCourseParams.setCourseName(courseName);
                        this.manualCreate(teachCourseParams, requestUser);
                    }
                }
            }
        }
    }

    @Override
    public List<DictionaryResult> findBasicCourseByUser(SysUser requestUser) {
        Long userId = requestUser.getId();
        Set<Long> orgIdSet = sysOrgService.findDeepOrgIdListByUserId(userId);
        QueryWrapper<BasicCourse> basicCourseQueryWrapper = new QueryWrapper<>();
        basicCourseQueryWrapper.lambda().eq(BasicCourse::getEnable, true);
        if (orgIdSet.size() > 0) {
            basicCourseQueryWrapper.lambda().in(BasicCourse::getTeachingRoomId, orgIdSet);
        }
        List<BasicCourse> basicCourseList = basicCourseService.list(basicCourseQueryWrapper);

        List<DictionaryResult> resultList = new ArrayList<>();
        for (BasicCourse basicCourse : basicCourseList) {
            DictionaryResult dictionaryResult = new DictionaryResult();
            BeanUtils.copyProperties(basicCourse, dictionaryResult);
            resultList.add(dictionaryResult);
        }
        return resultList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteTeachCourseBatch(List<Long> idList) {
        this.removeByIds(idList);
    }

    @Transactional
    @Override
    public void manualCreateTeacher(TeacherTeamParam teacherTeamParam, SysUser requestUser) throws IllegalAccessException {
        String name = teacherTeamParam.getTeacherName();
        String code = teacherTeamParam.getTeacherCode();
        Long basicCourseId = teacherTeamParam.getBasicCourseId();
        Long requestUserId = requestUser.getId();
        Long schoolId = requestUser.getSchoolId();
        Long teacherId;

        SysUser dbUser = sysUserService.getOne(new QueryWrapper<SysUser>().lambda()
                .eq(SysUser::getSchoolId, schoolId)
                .eq(SysUser::getCode, code));
        if (Objects.nonNull(dbUser)) {
            if (!name.equals(dbUser.getRealName())) {
                // 用户名称不一致
                throw ExceptionResultEnum.ERROR.exception("工号为【" + code + "】的教师用户名称错误");
            } else {
                teacherId = dbUser.getId();
                // 判断在该教师团队下已经存在该教师
                if (this.count(new QueryWrapper<TeachCourse>()
                        .lambda()
                        .eq(TeachCourse::getSchoolId, schoolId)
                        .eq(TeachCourse::getBasicCourseId, basicCourseId)
                        .eq(TeachCourse::getUserId, teacherId)) > 0) {
                    throw ExceptionResultEnum.ERROR.exception("教师【" + name + "】已经在教师团队中");
                }
            }
        } else {
            // 不存在用户，直接创建一个学校老师用户
            SysRole schoolTeacher = sysRoleService.getOne(new QueryWrapper<SysRole>()
                    .lambda()
                    .eq(SysRole::getType, RoleTypeEnum.SCHOOL_TEACHER));
            if (Objects.isNull(schoolTeacher)) {
                throw ExceptionResultEnum.ERROR.exception("缺少学校教师角色");
            }
            // 创建用户
            UserSaveParams userSaveParams = new UserSaveParams();
            userSaveParams.setSchoolId(schoolId);
            userSaveParams.setLoginName(code);
            userSaveParams.setRealName(name);
            userSaveParams.setCode(code);
            userSaveParams.setPassword(SystemConstant.DEFAULT_PASSWORD);
            userSaveParams.setOrgId(requestUser.getOrgId());
            userSaveParams.setEnable(true);
            userSaveParams.setRoleIds(new Long[]{schoolTeacher.getId()});
            teacherId = sysUserService.saveUser(userSaveParams);
        }
        // 添加教师团队
        TeachCourse teachCourse = new TeachCourse();
        teachCourse.setSchoolId(schoolId);
        teachCourse.setBasicCourseId(basicCourseId);
        teachCourse.setUserId(teacherId);
        teachCourse.setEnable(true);
        teachCourse.insertInfo(requestUserId);
        this.save(teachCourse);
    }

    @Transactional
    @Override
    public void selectCreateTeacher(Long basicCourseId, List<Long> userIdList, SysUser requestUser) {
        Long schoolId = requestUser.getSchoolId();
        Long requestUserId = requestUser.getId();
        if (CollectionUtils.isNotEmpty(userIdList)) {
            // 过滤userIdList
            userIdList = sysUserService.listByIds(userIdList).stream()
                    .filter(SysUser::getEnable)
                    .map(BaseEntity::getId)
                    .distinct()
                    .collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(userIdList)) {
                List<Long> alreadyCreated = this.list(new QueryWrapper<TeachCourse>().lambda()
                                .in(TeachCourse::getUserId, userIdList)
                                .eq(TeachCourse::getBasicCourseId, basicCourseId))
                        .stream()
                        .map(TeachCourse::getUserId)
                        .distinct()
                        .collect(Collectors.toList());

                // 去掉已经在该课程教师团队的老师
                userIdList.removeAll(alreadyCreated);

                // 创建教学课程
                List<TeachCourse> teachCourseList = userIdList.stream().flatMap(e -> {
                    TeachCourse teachCourse = new TeachCourse();
                    teachCourse.setSchoolId(schoolId);
                    teachCourse.setBasicCourseId(basicCourseId);
                    teachCourse.setUserId(e);
                    teachCourse.setEnable(true);
                    teachCourse.insertInfo(requestUserId);
                    return Stream.of(teachCourse);
                }).collect(Collectors.toList());

                // 新增课程
                this.saveBatch(teachCourseList);
            }
        }
    }

    @Transactional
    @Override
    public void importTeacherTeam(MultipartFile file, Long basicCourseId, SysUser requestUser) throws IOException, NoSuchFieldException, IllegalAccessException {
        List<LinkedMultiValueMap<Integer, Object>> finalList = ExcelUtil.excelReader(file.getInputStream(), Lists.newArrayList(TeacherTeamDto.class), (finalExcelList, finalColumnNameList, finalExcelErrorList) -> {
            if (finalExcelErrorList.size() > 0) {
                throw ExceptionResultEnum.ERROR.exception(JSONObject.toJSONString(finalExcelErrorList));
            }
            return finalExcelList;
        });

        if (Objects.nonNull(finalList) && finalList.size() > 0) {
            for (int i = 0; i < finalList.size(); i++) {
                LinkedMultiValueMap<Integer, Object> map = finalList.get(i);
                List<Object> teacherTeamImportList = map.get(i);
                for (int y = 0; y < Objects.requireNonNull(teacherTeamImportList).size(); y++) {
                    if (teacherTeamImportList.get(y) instanceof TeacherTeamDto) {
                        TeacherTeamDto teacherTeamDto = (TeacherTeamDto) teacherTeamImportList.get(y);
                        TeacherTeamParam teacherTeamParam = new TeacherTeamParam();
                        teacherTeamParam.setTeacherCode(teacherTeamDto.getCode());
                        teacherTeamParam.setTeacherName(teacherTeamDto.getName());
                        teacherTeamParam.setBasicCourseId(basicCourseId);
                        this.manualCreateTeacher(teacherTeamParam, requestUser);
                    }
                }
            }
        }
    }

    @Override
    public IPage<TeacherTeamResult> findTeacherTeamPage(String userInfo, Long basicCourseId, int pageNumber, int pageSize) {
        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
        if (SystemConstant.strNotNull(userInfo)) {
            userInfo = SystemConstant.translateSpecificSign(userInfo);
        }
        IPage<TeacherTeamResult> page = this.baseMapper.findTeacherTeamPage(new Page<>(pageNumber, pageSize), userInfo, basicCourseId, schoolId);
        page.getRecords().forEach(e -> {
            Long userId = e.getUserId();
            List<Long> userIdList = new ArrayList<>();
            userIdList.add(userId);
            List<UserRoleNameResult> roleNameList = sysUserService.selectRoleNames(userIdList);
            if (roleNameList.size() == 1) {
                e.setRoleName(roleNameList.get(0).getRoleNames());
            }
        });
        return page;
    }

    @Override
    public List<TeacherSelectResult> findUserByOrgId(Long orgId) {
        List<Long> temp = new ArrayList<>();
        temp.add(orgId);
        Set<Long> orgIdSet = sysOrgService.findDeepOrgIdListByOrgIdList(temp);
        return this.baseMapper.findTeacherByOrgIds(new ArrayList<>(orgIdSet));
    }

    @Override
    public List<BasicCourse> findTeachCourseByUserId(Long userId) {
        return this.baseMapper.findTeachCourseByUserId(userId);
    }
}
