package com.schoolinout.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.schoolinout.common.exception.ServiceException;
import com.schoolinout.common.utils.DateUtils;
import com.schoolinout.common.utils.SecurityUtils;
import com.schoolinout.common.utils.bean.BeanUtils;
import com.schoolinout.system.domain.Clazz;
import com.schoolinout.system.domain.TeacherClassRelation;
import com.schoolinout.system.domain.dto.AddClassDto;
import com.schoolinout.system.domain.dto.InsertTeacherClassRelationDto;
import com.schoolinout.system.domain.vo.OptionVo;
import com.schoolinout.system.mapper.ClazzMapper;
import com.schoolinout.system.mapper.TeacherClassRelationMapper;
import com.schoolinout.system.service.IClazzService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.rmi.ServerException;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 班级管理Service业务层处理
 *
 * @author sakura
 * @date 2024-01-03
 */
@Service
public class ClazzServiceImpl implements IClazzService {

    @Autowired
    private IClazzService curProxy;
    @Autowired
    private ClazzMapper clazzMapper;
    @Autowired
    private TeacherClassRelationMapper relationMapper;

    /**
     * 查询班级管理
     *
     * @param id 班级管理主键
     * @return 班级管理
     */
    @Override
    public Clazz selectClazzById(Long id) {
        return clazzMapper.selectClazzById(id);
    }

    @Override
    public List<OptionVo> selectClazzOptionList(Long schoolId) {
        return clazzMapper.selectClazzOptionBySchoolId(schoolId);
    }

    /**
     * 查询班级管理列表
     *
     * @param clazz 班级管理
     * @return 班级管理
     */
    @Override
    public List<Clazz> selectClazzList(Clazz clazz) {
        return clazzMapper.selectClazzList(clazz);
    }

    /**
     * 新增班级管理
     *
     * @param clazz 班级管理
     * @return 结果
     */
    @Override
    public int insertClazz(Clazz clazz) {
        clazz.setCreateTime(DateUtils.getNowDate());
        return clazzMapper.insertClazz(clazz);
    }

    /**
     * 修改班级管理
     *
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int updateClazz(AddClassDto form) {
        Long classId = form.getId();
        List<Long> newTeacherIds = form.getTeacherIds();

        // 处理班级与教师直接的关系
        curProxy.handlerClassTeacherRelation(form, classId, newTeacherIds);

        // 更新班级信息
        Clazz clazz = new Clazz();
        BeanUtils.copyBeanProp(clazz, form);
        return clazzMapper.updateClazz(clazz);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public void handlerClassTeacherRelation(AddClassDto form, Long classId, List<Long> newTeacherIds) {
        // 先查询原班级关系数据
        TeacherClassRelation queryRelation = new TeacherClassRelation();
        queryRelation.setClassId(classId);
        List<TeacherClassRelation> existingRelations = relationMapper.selectTeacherClassRelationList(queryRelation);

        // 将现有关系映射为教师ID集合
        Set<Long> existingTeacherIds = existingRelations.stream()
                .map(TeacherClassRelation::getTeacherId)
                .collect(Collectors.toSet());

        // 如果新的教师列表为空，或者需要移除所有现有教师
        if (newTeacherIds == null || newTeacherIds.isEmpty()) {
            // 删除所有现有关系
            relationMapper.deleteAllRelationsForClass(form.getSchoolId(), classId, null);
        } else {
            // 计算需要删除的教师ID
            List<Long> teacherIdsToRemove = existingTeacherIds.stream()
                    .filter(teacherId -> !newTeacherIds.contains(teacherId))
                    .collect(Collectors.toList());

            // 计算需要添加的教师ID
            List<Long> teacherIdsToAdd = newTeacherIds.stream()
                    .filter(teacherId -> !existingTeacherIds.contains(teacherId))
                    .collect(Collectors.toList());

            // 执行批量删除
            if (!teacherIdsToRemove.isEmpty()) {
                relationMapper.deleteRelationBatch(form.getSchoolId(), classId, teacherIdsToRemove);
            }

            // 执行批量插入
            if (!teacherIdsToAdd.isEmpty()) {
                relationMapper.insertRelationBatch(form.getSchoolId(), classId, teacherIdsToAdd);
            }
        }
    }

    /**
     * 批量删除班级管理
     *
     * @param ids 需要删除的班级管理主键
     * @return 结果
     */
    @Override
    public int deleteClazzByIds(Long[] ids) {
        return clazzMapper.deleteClazzByIds(ids);
    }

    /**
     * 删除班级管理信息
     *
     * @param id 班级管理主键
     * @return 结果
     */
    @Override
    public int deleteClazzById(Long id) {
        return clazzMapper.deleteClazzById(id);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, ServerException.class})
    public int saveClassAndRelation(AddClassDto form) {
        // step1：查询当前学校，是否出现同名的班级
        LambdaQueryWrapper<Clazz> wrapper = new LambdaQueryWrapper<Clazz>()
                .eq(Clazz::getSchoolId, form.getSchoolId())
                .eq(Clazz::getClassName, form.getClassName());
        Clazz clazz = clazzMapper.selectOne(wrapper);
        if (clazz != null) {
            throw new ServiceException("当前学校已有同名的班级");
        }
        // step2：新增对应的班级
        clazz = new Clazz();
        BeanUtils.copyBeanProp(clazz, form);
        // 插入数据
        clazz.setCreateTime(new Date());
        clazz.setCreateBy(SecurityUtils.getLoginUser().getUsername());
        clazzMapper.insertClazz(clazz);

        // step3：如果存在绑定老师，则新增关系的绑定
        List<Long> teacherIds = form.getTeacherIds();
        if (teacherIds != null && !teacherIds.isEmpty()) {
            // 插入数据
            Clazz finalClazz = clazz;
            List<InsertTeacherClassRelationDto> insertList = teacherIds.stream()
                    .map(item -> new InsertTeacherClassRelationDto(form.getSchoolId(), item, finalClazz.getId()))
                    .collect(Collectors.toList());
            return relationMapper.insertTeacherClassRelationBatch(insertList);
        }

        return 1;
    }
}
