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

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.qmth.teachcloud.common.bean.dto.excel.BasicClazzImportDto;
import com.qmth.teachcloud.common.bean.dto.excel.DescribeImportDto;
import com.qmth.teachcloud.common.bean.params.BasicClazzParams;
import com.qmth.teachcloud.common.bean.result.BasicClazzResult;
import com.qmth.teachcloud.common.bean.result.ClazzDatasourceResult;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.*;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.mapper.BasicClazzMapper;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;

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


/**
 * @Description: 基础课程服务实现类
 * @Author: CaoZixuan
 * @Date: 2021-08-28
 */
@Service
public class BasicClazzServiceImpl extends ServiceImpl<BasicClazzMapper, BasicClazz> implements BasicClazzService {
    @Resource
    private BasicClazzMapper basicClazzMapper;
    @Resource
    private BasicStudentService basicStudentService;
    @Resource
    private BasicUserCourseService basicUserCourseService;
    @Resource
    private BasicCampusService basicCampusService;
    @Resource
    private BasicMajorService basicMajorService;

    @Override
    public IPage<BasicClazzResult> basicClazzPage(String queryParams, int pageNumber, int pageSize) {
        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
//        Set<Long> orgIds = teachcloudCommonService.listSubOrgIds(null);
        Set<Long> orgIds = null;
        queryParams = SystemConstant.translateSpecificSign(queryParams);
        return basicClazzMapper.findBasicClazzPage(new Page<>(pageNumber, pageSize), queryParams, schoolId, orgIds);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long saveBasicClazz(BasicClazzParams basicClazzParams, SysUser sysUser) throws IllegalAccessException {
        List<BasicClazzParams> basicClazzParamsList = new ArrayList<>();
        basicClazzParamsList.add(basicClazzParams);
        BasicClazz basicClazz = this.editEntityHelp(basicClazzParamsList, sysUser).get(0);
        this.saveOrUpdate(basicClazz);
        return basicClazz.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean removeBasicClazzBatch(List<Long> idList) {
        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
        if (idList.size() == 0) {
            throw ExceptionResultEnum.ERROR.exception("请选择要删除的目标");
        }
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        // 业务处理 - 判断'exam_task_print'表中是否已经选中该班级
        List<Map<Object, Object>> mapList = basicClazzMapper.findExamTaskPrintByClazzIdSet(schoolId, idList);
        if (mapList.size() > 0) {
            StringBuilder clazzNames = new StringBuilder();
            for (Map<Object, Object> map : mapList) {
                clazzNames.append(map.get("clazzName")).append(",");
            }
            throw ExceptionResultEnum.ERROR.exception("【班级】 ： " + clazzNames.substring(0, clazzNames.length() - 1) + "生成了未结束的印刷任务，无法删除");
        }

        // 异常处理
        String errorStudent = "";
        String errorCourse = "";
        List<BasicStudent> basicStudentCheck = basicStudentService.list(new QueryWrapper<BasicStudent>().lambda().eq(BasicStudent::getEnable, true).in(BasicStudent::getClazzId, idList));
        if (basicStudentCheck.size() > 0) {
            Set<Long> ids = basicStudentCheck.stream().map(BasicStudent::getClazzId).collect(Collectors.toSet());
            List<String> exStudentClazz = this.list(new QueryWrapper<BasicClazz>().lambda()
                    .in(BasicClazz::getId, ids)).stream().map(BasicClazz::getClazzName).collect(Collectors.toList());
            errorStudent = StringUtils.join(exStudentClazz, ',');
        }

        List<BasicUserCourse> basicUserCourseCheck = basicUserCourseService.list(new QueryWrapper<BasicUserCourse>().lambda()
                .in(BasicUserCourse::getClazzId, idList)
                .eq(BasicUserCourse::getEnable, true));
        if (basicUserCourseCheck.size() > 0) {
            Set<Long> ids = basicUserCourseCheck.stream().map(BasicUserCourse::getClazzId).collect(Collectors.toSet());
            List<String> exUserCourseClazz = this.list(new QueryWrapper<BasicClazz>().lambda().in(BasicClazz::getId, ids)).stream().map(BasicClazz::getClazzName).collect(Collectors.toList());
            errorCourse = StringUtils.join(exUserCourseClazz, ',');
        }

        if (SystemConstant.strNotNull(errorStudent) && SystemConstant.strNotNull(errorCourse)) {
            throw ExceptionResultEnum.ERROR.exception("学生已绑定了要删除的【班级】 ： " + errorStudent + "，课程已绑定了要删除的【班级】 ： " + errorCourse);
        } else if (SystemConstant.strNotNull(errorStudent) && !SystemConstant.strNotNull(errorCourse)) {
            throw ExceptionResultEnum.ERROR.exception("学生已绑定了要删除的【班级】 ： " + errorStudent);
        } else if (SystemConstant.strNotNull(errorCourse) && !SystemConstant.strNotNull(errorCourse)) {
            throw ExceptionResultEnum.ERROR.exception("课程已绑定了要删除的【班级】 ： " + errorCourse);
        }

        // 物理删除
        // 删除课程班级绑定关系
        basicUserCourseService.remove(new QueryWrapper<BasicUserCourse>().lambda()
                .eq(BasicUserCourse::getEnable, false)
                .in(BasicUserCourse::getClazzId, idList));
        return this.removeByIds(idList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    @Deprecated
    public Map<String, Object> executeBasicClazzImportLogic(List<LinkedMultiValueMap<Integer, Object>> finalList, Map<String, Object> map) throws IllegalAccessException {
        SysUser sysUser = (SysUser) map.get(SystemConstant.SYS_USER);
        Long schoolId = sysUser.getSchoolId();

        List<BasicClazzParams> addBasicClazzParamsList = new ArrayList<>();
        for (int i = 0; i < finalList.size(); i++) {
            LinkedMultiValueMap<Integer, Object> excelMap = finalList.get(i);
            List<Object> basicClazzImportDtoList = excelMap.get(i);

            assert basicClazzImportDtoList != null;
            if (basicClazzImportDtoList.get(0) instanceof DescribeImportDto) {
                continue;
            }
            List<BasicClazzImportDto> datasource = basicClazzImportDtoList.stream().map(e -> {
                BasicClazzImportDto basicClazzImportDto = new BasicClazzImportDto();
                BeanUtils.copyProperties(e, basicClazzImportDto);
                return basicClazzImportDto;
            }).collect(Collectors.toList());
            map.put("dataCount", datasource.size());


            // 新校区名称集合
            Set<String> newCampusNameSet = datasource.stream().map(BasicClazzImportDto::getCampusName).collect(Collectors.toSet());
            // 旧校区集合
            List<BasicCampus> basicCampusList = basicCampusService.list(new QueryWrapper<BasicCampus>().lambda().eq(BasicCampus::getEnable, true).eq(BasicCampus::getSchoolId, schoolId));
            Set<String> oldCampusNameSet = basicCampusList.stream().map(BasicCampus::getCampusName).collect(Collectors.toSet());

            // 需要新增的校区集合
            Set<String> addCampusNameSet = newCampusNameSet.stream().filter(e -> !oldCampusNameSet.contains(e)).collect(Collectors.toSet());
            List<BasicCampus> addBasicCampusList = new ArrayList<>();
            for (String campusName : addCampusNameSet) {
                BasicCampus basicCampus = new BasicCampus();
                Long id = SystemConstant.getDbUuid();
                basicCampus.setSchoolId(schoolId);
                basicCampus.setCampusName(campusName);
                basicCampus.setId(id);
                basicCampus.setCampusCode(String.valueOf(id));
                basicCampus.setEnable(true);
                basicCampus.setCreateId(sysUser.getId());
                addBasicCampusList.add(basicCampus);
            }
            // 批量新增校区
            basicCampusService.saveBatch(addBasicCampusList);

            for (int y = 0; y < Objects.requireNonNull(basicClazzImportDtoList).size(); y++) {
                BasicClazzImportDto basicClazzImportDto = (BasicClazzImportDto) basicClazzImportDtoList.get(y);

                // 取值
                String clazzName = basicClazzImportDto.getClazzName();
                String campusName = basicClazzImportDto.getCampusName();


                BasicClazzParams basicClazzParams = new BasicClazzParams();
                basicClazzParams.setCampusId(basicCampusService.getOne(new QueryWrapper<BasicCampus>().lambda()
                                .eq(BasicCampus::getSchoolId, schoolId)
                                .eq(BasicCampus::getCampusName, campusName)
                                .eq(BasicCampus::getEnable, true))
                        .getId());
                basicClazzParams.setClazzName(clazzName);

                BasicClazz tmp = this.getOne(new QueryWrapper<BasicClazz>().lambda()
                        .eq(BasicClazz::getSchoolId, sysUser.getSchoolId())
                        .eq(BasicClazz::getEnable, true)
                        .eq(BasicClazz::getClazzName, clazzName));
                if (Objects.nonNull(tmp)) {
                    basicClazzParams.setId(tmp.getId());
                }
                addBasicClazzParamsList.add(basicClazzParams);
            }

            List<BasicClazz> basicClazzList = this.editEntityHelp(addBasicClazzParamsList, sysUser);
            this.saveOrUpdateBatch(basicClazzList);
        }
        return map;
    }

    @Override
    public List<ClazzDatasourceResult> findClazzDatasource(Long campusId) {
        Long schoolId = SystemConstant.convertIdToLong(ServletUtil.getRequestHeaderSchoolId().toString());
        QueryWrapper<BasicClazz> basicClazzQueryWrapper = new QueryWrapper<>();

        basicClazzQueryWrapper.lambda().eq(BasicClazz::getEnable, true)
                .eq(BasicClazz::getSchoolId, schoolId);
        if (SystemConstant.longNotNull(campusId)) {
            basicClazzQueryWrapper.lambda().eq(BasicClazz::getCampusId, campusId);
        }

        return this.list(basicClazzQueryWrapper).stream()
                .map(e -> {
                    ClazzDatasourceResult clazzDatasourceResult = new ClazzDatasourceResult();
                    clazzDatasourceResult.setId(e.getId());
                    clazzDatasourceResult.setName(e.getClazzName());
                    clazzDatasourceResult.setCode(e.getClazzCode());
                    return clazzDatasourceResult;
                }).collect(Collectors.toList());
    }

    /**
     * 基础班级保存助手方法
     *
     * @param basicClazzParamsList 基础班级参数
     * @param sysUser              操作人
     * @return 结果
     */
    private List<BasicClazz> editEntityHelp(List<BasicClazzParams> basicClazzParamsList, SysUser sysUser) throws IllegalAccessException {
        Long schoolId = sysUser.getSchoolId();
        List<BasicClazz> editEntityList = new ArrayList<>();
        for (BasicClazzParams basicClazzParams : basicClazzParamsList) {
            SystemConstant.verifyDBFields(basicClazzParams, basicClazzParams.getClass());
            // 普通参数
            Long id = basicClazzParams.getId();
            Long campusId = basicClazzParams.getCampusId();
            String clazzCode = basicClazzParams.getClazzCode();
            String clazzName = basicClazzParams.getClazzName();
            Long majorId = basicClazzParams.getMajorId();

            // 校验校区不存在
            if (Objects.isNull(basicCampusService.getById(campusId))) {
                throw ExceptionResultEnum.ERROR.exception("所选校区不存在");
            }
            if (Objects.isNull(basicMajorService.getById(majorId))) {
                throw ExceptionResultEnum.ERROR.exception("所选专业不存在");
            }

            // 检验班级名称在学校的唯一性（字典班级在全校唯一）
            BasicClazz checkName = this.getOne(new QueryWrapper<BasicClazz>().lambda()
                    .eq(BasicClazz::getSchoolId, schoolId)
                    .eq(BasicClazz::getClazzName, clazzName));
            if (Objects.nonNull(checkName)) {
                if (!checkName.getId().equals(id)) {
                    throw ExceptionResultEnum.ERROR.exception("班级名称【" + clazzName + "】重复");
                }
            }

            // 组装基础参数
            Long orgId;
            BasicClazz basicClazz = new BasicClazz();
            basicClazz.setCampusId(campusId);
            basicClazz.setSchoolId(schoolId);
            basicClazz.setMajorId(majorId);
            if (SystemConstant.strNotNull(clazzCode)) {
                basicClazz.setClazzCode(clazzCode);
            }
            basicClazz.setClazzName(clazzName);

            if (!SystemConstant.longNotNull(id)) {
                // id为空 -> 新增
                // 获取分布式id
                orgId = sysUser.getOrgId();
                id = SystemConstant.getDbUuid();
                basicClazz.setId(id);
                basicClazz.setEnable(true);
                basicClazz.setCreateId(sysUser.getId());
            } else {
                // id不为空 -> 编辑
                BasicClazz old = this.getById(id);
                if (Objects.isNull(old) || old.getEnable().equals(false)) {
                    throw ExceptionResultEnum.ERROR.exception("基础班级主键不存在或被禁用");
                }
                orgId = old.getOrgId();
                basicClazz.setId(id);
                basicClazz.setUpdateId(sysUser.getId());
                // 如果更新了班级所属的专业或校区则更新学生级联关系
                if (!majorId.equals(old.getMajorId()) || !campusId.equals(old.getCampusId())) {
                    List<BasicStudent> basicStudentList = basicStudentService.list(new QueryWrapper<BasicStudent>().lambda()
                            .eq(BasicStudent::getClazzId, id));
                    basicStudentList.forEach(e -> {
                        e.setBelongOrgId(basicMajorService.getById(majorId).getBelongOrgId());
                        e.setMajorId(majorId);
                        e.setCampusId(campusId);
                    });
                    basicStudentService.updateBatchById(basicStudentList);
                }
            }
            basicClazz.setOrgId(orgId);
            editEntityList.add(basicClazz);
        }
        return editEntityList;
    }
}
