package com.lesingle.edu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lesingle.edu.common.enums.ClassTeacherRole;
import com.lesingle.edu.common.enums.ErrorCode;
import com.lesingle.edu.common.enums.GenericStatus;
import com.lesingle.edu.common.enums.StudentClassStatus;
import com.lesingle.edu.common.exception.BusinessException;
import com.lesingle.edu.dto.request.ClassCreateRequest;
import com.lesingle.edu.dto.request.ClassUpdateRequest;
import com.lesingle.edu.dto.response.StudentTransferHistoryItemResponse;
import com.lesingle.edu.entity.ClassTeacher;
import com.lesingle.edu.entity.Clazz;
import com.lesingle.edu.entity.StudentClassHistory;
import com.lesingle.edu.mapper.ClassTeacherMapper;
import com.lesingle.edu.mapper.ClazzMapper;
import com.lesingle.edu.mapper.StudentClassHistoryMapper;
import com.lesingle.edu.service.ClassService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 班级服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ClassServiceImpl extends com.baomidou.mybatisplus.extension.service.impl.ServiceImpl<ClazzMapper, Clazz>
    implements ClassService {

    private final ClazzMapper clazzMapper;
    private final ClassTeacherMapper classTeacherMapper;
    private final StudentClassHistoryMapper studentClassHistoryMapper;

    @Override
    @Transactional
    public Clazz createClass(Long tenantId, ClassCreateRequest request) {
        log.info("开始创建班级，名称：{}", request.getName());

        // 检查班级名称是否唯一（MyBatis-Plus 会自动排除 deleted=1 的记录）
        LambdaQueryWrapper<Clazz> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Clazz::getTenantId, tenantId)
               .eq(Clazz::getName, request.getName());
        Long count = clazzMapper.selectCount(wrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.INVALID_PARAMETER, "该班级名称已存在");
        }

        Clazz clazz = new Clazz();
        clazz.setTenantId(tenantId);
        clazz.setName(request.getName());
        clazz.setGrade(request.getGrade());
        clazz.setDescription(request.getDescription());
        clazz.setCapacity(request.getCapacity() != null ? request.getCapacity() : 30);
        clazz.setStatus(GenericStatus.ACTIVE.getCode());

        clazzMapper.insert(clazz);

        // 如果指定了班主任，保存班级教师关系
        if (request.getTeacherId() != null) {
            ClassTeacher classTeacher = new ClassTeacher();
            classTeacher.setClassId(clazz.getId());
            classTeacher.setTeacherId(request.getTeacherId());
            classTeacher.setRole(ClassTeacherRole.MAIN.getCode());
            classTeacherMapper.insert(classTeacher);
            log.info("已为班级 {} 设置班主任，教师 ID: {}", clazz.getId(), request.getTeacherId());
        }

        log.info("班级创建成功，ID: {}", clazz.getId());
        return clazz;
    }

    @Override
    @Transactional
    public Clazz updateClass(Long id, ClassUpdateRequest request) {
        log.info("开始更新班级，ID: {}", id);

        Clazz clazz = getClassById(id);

        if (StringUtils.hasText(request.getName())) {
            // 检查班级名称是否唯一（排除当前班级和已删除）
            LambdaQueryWrapper<Clazz> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Clazz::getTenantId, clazz.getTenantId())
                   .eq(Clazz::getName, request.getName())
                   .ne(Clazz::getId, id);  // 排除当前班级
            Long count = clazzMapper.selectCount(wrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.INVALID_PARAMETER, "该班级名称已存在");
            }
            clazz.setName(request.getName());
        }
        if (request.getGrade() != null) {
            clazz.setGrade(request.getGrade());
        }
        if (request.getDescription() != null) {
            clazz.setDescription(request.getDescription());
        }
        if (request.getCapacity() != null) {
            clazz.setCapacity(request.getCapacity());
        }
        if (StringUtils.hasText(request.getStatus())) {
            clazz.setStatus(request.getStatus());
        }

        clazzMapper.updateById(clazz);

        // 处理班主任关系的更新
        if (request.getTeacherId() != null) {
            // 先删除该班级现有的所有教师关系
            classTeacherMapper.delete(
                    new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getClassId, id)
            );

            // 创建新的班主任关系
            ClassTeacher classTeacher = new ClassTeacher();
            classTeacher.setClassId(id);
            classTeacher.setTeacherId(request.getTeacherId());
            classTeacher.setRole(ClassTeacherRole.MAIN.getCode());
            classTeacherMapper.insert(classTeacher);
            log.info("已更新班级 {} 的班主任，教师 ID: {}", id, request.getTeacherId());
        }

        log.info("班级更新成功，ID: {}", id);
        return clazz;
    }

    @Override
    @Transactional
    public Clazz updateClassWithTenantCheck(Long id, Long tenantId, ClassUpdateRequest request) {
        log.info("开始更新班级（带租户验证），ID: {}, tenantId: {}", id, tenantId);
        // 先验证租户权限
        getClassByIdWithTenantCheck(id, tenantId);
        return updateClass(id, request);
    }

    @Override
    public Clazz getClassById(Long id) {
        log.debug("查询班级，ID: {}", id);

        Clazz clazz = clazzMapper.selectById(id);
        if (clazz == null) {
            log.warn("班级不存在，ID: {}", id);
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "班级不存在");
        }
        return clazz;
    }

    @Override
    public Clazz getClassByIdWithTenantCheck(Long id, Long tenantId) {
        log.debug("查询班级（带租户验证），ID: {}, tenantId: {}", id, tenantId);
        Clazz clazz = getClassById(id);
        if (!clazz.getTenantId().equals(tenantId)) {
            log.warn("租户无权访问班级，班级ID: {}, 租户ID: {}", id, tenantId);
            throw new BusinessException(ErrorCode.FORBIDDEN, "无权访问该班级");
        }
        return clazz;
    }

    @Override
    public Page<Clazz> getClassPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status) {
        log.debug("分页查询班级，页码：{}，每页数量：{}", pageNum, pageSize);

        Page<Clazz> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Clazz> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(Clazz::getTenantId, tenantId);

        if (StringUtils.hasText(keyword)) {
            wrapper.like(Clazz::getName, keyword);
        }
        if (StringUtils.hasText(grade)) {
            wrapper.eq(Clazz::getGrade, grade);
        }
        if (StringUtils.hasText(status)) {
            wrapper.eq(Clazz::getStatus, status);
        }
        wrapper.orderByDesc(Clazz::getCreatedAt);

        return clazzMapper.selectPage(page, wrapper);
    }

    @Override
    @Transactional
    public void deleteClass(Long id) {
        log.info("开始删除班级，ID: {}", id);

        getClassById(id);
        clazzMapper.deleteById(id);

        log.info("班级删除成功，ID: {}", id);
    }

    @Override
    @Transactional
    public void deleteClassWithTenantCheck(Long id, Long tenantId) {
        log.info("开始删除班级（带租户验证），ID: {}, tenantId: {}", id, tenantId);
        // 先验证租户权限
        getClassByIdWithTenantCheck(id, tenantId);
        deleteClass(id);
    }

    @Override
    @Transactional
    public void assignTeachers(Long classId, List<Long> teacherIds) {
        log.info("开始分配教师，班级 ID: {}，教师数量：{}", classId, teacherIds.size());

        // 验证班级是否存在
        getClassById(classId);

        // 删除现有的教师分配
        classTeacherMapper.delete(
                new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getClassId, classId)
        );

        // 创建新的分配
        for (Long teacherId : teacherIds) {
            ClassTeacher classTeacher = new ClassTeacher();
            classTeacher.setClassId(classId);
            classTeacher.setTeacherId(teacherId);
            classTeacher.setRole("teacher");
            classTeacherMapper.insert(classTeacher);
        }

        log.info("教师分配完成，班级 ID: {}，教师数量：{}", classId, teacherIds.size());
    }

    @Override
    @Transactional
    public void assignStudents(Long classId, List<Long> studentIds) {
        log.info("开始分配学生，班级 ID: {}，学生数量：{}", classId, studentIds.size());

        // 验证班级是否存在
        getClassById(classId);

        // 结束现有活跃的学生分配
        List<StudentClassHistory> existingHistories = studentClassHistoryMapper.selectList(
                new LambdaQueryWrapper<StudentClassHistory>()
                        .eq(StudentClassHistory::getClassId, classId)
                        .eq(StudentClassHistory::getStatus, StudentClassStatus.ACTIVE.getCode())
                        .isNull(StudentClassHistory::getEndDate)
        );

        for (StudentClassHistory history : existingHistories) {
            history.setEndDate(LocalDate.now());
            studentClassHistoryMapper.updateById(history);
        }

        // 创建新的分配
        for (Long studentId : studentIds) {
            StudentClassHistory history = new StudentClassHistory();
            history.setStudentId(studentId);
            history.setClassId(classId);
            history.setStartDate(LocalDate.now());
            history.setStatus(StudentClassStatus.ACTIVE.getCode());
            studentClassHistoryMapper.insert(history);
        }

        log.info("学生分配完成，班级 ID: {}，学生数量：{}", classId, studentIds.size());
    }

    @Override
    @Transactional
    public void assignTeachersWithTenantCheck(Long classId, Long tenantId, List<Long> teacherIds) {
        log.info("开始分配教师（带租户验证），班级 ID: {}, tenantId: {}", classId, tenantId);
        // 先验证班级属于当前租户
        getClassByIdWithTenantCheck(classId, tenantId);
        assignTeachers(classId, teacherIds);
    }

    @Override
    @Transactional
    public void assignStudentsWithTenantCheck(Long classId, Long tenantId, List<Long> studentIds) {
        log.info("开始分配学生（带租户验证），班级 ID: {}, tenantId: {}", classId, tenantId);
        // 先验证班级属于当前租户
        getClassByIdWithTenantCheck(classId, tenantId);
        assignStudents(classId, studentIds);
    }

    @Override
    @Transactional
    public void assignStudentToClass(Long studentId, Long classId, Long tenantId) {
        log.info("将学生调班，学生 ID: {}, 目标班级 ID: {}", studentId, classId);
        getClassByIdWithTenantCheck(classId, tenantId);
        // 结束该学生当前所有活跃的班级关联
        List<StudentClassHistory> existing = studentClassHistoryMapper.selectList(
                new LambdaQueryWrapper<StudentClassHistory>()
                        .eq(StudentClassHistory::getStudentId, studentId)
                        .in(StudentClassHistory::getStatus, StudentClassStatus.ACTIVE.getCode())
                        .and(w -> w.isNull(StudentClassHistory::getEndDate)
                                .or()
                                .ge(StudentClassHistory::getEndDate, LocalDate.now()))
        );
        for (StudentClassHistory h : existing) {
            h.setEndDate(LocalDate.now());
            studentClassHistoryMapper.updateById(h);
        }
        // 建立新班级关联
        StudentClassHistory history = new StudentClassHistory();
        history.setStudentId(studentId);
        history.setClassId(classId);
        history.setStartDate(LocalDate.now());
        history.setStatus(StudentClassStatus.ACTIVE.getCode());
        studentClassHistoryMapper.insert(history);
    }

    @Override
    public List<Long> getTeacherIdsByClassId(Long classId) {
        log.debug("获取班级教师 ID 列表，班级 ID: {}", classId);

        List<ClassTeacher> classTeachers = classTeacherMapper.selectList(
                new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getClassId, classId)
        );

        List<Long> teacherIds = new ArrayList<>();
        for (ClassTeacher ct : classTeachers) {
            teacherIds.add(ct.getTeacherId());
        }
        return teacherIds;
    }

    @Override
    @Transactional
    public void updateClassTeacherRole(Long classId, Long teacherId, String role, Boolean isPrimary) {
        log.info("更新班级教师角色，班级 ID: {}, 教师 ID: {}, 角色：{}, 是否班主任：{}", classId, teacherId, role, isPrimary);

        // 查询现有的关联记录
        ClassTeacher classTeacher = classTeacherMapper.selectOne(
                new LambdaQueryWrapper<ClassTeacher>()
                        .eq(ClassTeacher::getClassId, classId)
                        .eq(ClassTeacher::getTeacherId, teacherId)
        );

        if (classTeacher == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "该教师不在班级中");
        }

        // 如果设置为新主班，先将原主班降级为配班
        if (ClassTeacherRole.isPrimaryRole(role)) {
            List<ClassTeacher> allTeachers = classTeacherMapper.selectList(
                    new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getClassId, classId));
            for (ClassTeacher ct : allTeachers) {
                if (!ct.getId().equals(classTeacher.getId()) && ClassTeacherRole.isPrimaryRole(ct.getRole())) {
                    ct.setRole(ClassTeacherRole.ASSIST.getCode());
                    classTeacherMapper.updateById(ct);
                    log.info("班级 {} 的原主班教师 {} 已降级为配班", classId, ct.getTeacherId());
                }
            }
        }

        // 更新角色
        if (role != null) {
            classTeacher.setRole(role);
        }

        // 如果设置为班主任，需要确保角色为 MAIN
        if (Boolean.TRUE.equals(isPrimary)) {
            classTeacher.setRole(ClassTeacherRole.MAIN.getCode());
        }

        classTeacherMapper.updateById(classTeacher);
        log.info("班级教师角色更新成功，班级 ID: {}, 教师 ID: {}", classId, teacherId);
    }

    @Override
    public String getTeacherRoleInClass(Long classId, Long teacherId) {
        ClassTeacher ct = classTeacherMapper.selectOne(
                new LambdaQueryWrapper<ClassTeacher>()
                        .eq(ClassTeacher::getClassId, classId)
                        .eq(ClassTeacher::getTeacherId, teacherId)
        );
        return ct != null ? ct.getRole() : null;
    }

    @Override
    public List<Clazz> getActiveClassesByTenantId(Long tenantId) {
        log.debug("获取租户活跃班级列表，租户 ID: {}", tenantId);

        return clazzMapper.selectList(
                new LambdaQueryWrapper<Clazz>()
                        .eq(Clazz::getTenantId, tenantId)
                        .eq(Clazz::getStatus, GenericStatus.ACTIVE.getCode())
        );
    }

    @Override
    public List<Clazz> getClassesByTeacherId(Long teacherId, Long tenantId) {
        log.debug("获取教师教授的班级列表，教师 ID: {}, 租户 ID: {}", teacherId, tenantId);

        List<Clazz> allClasses = getActiveClassesByTenantId(tenantId);
        return allClasses.stream()
                .filter(clazz -> {
                    List<Long> teacherIds = getTeacherIdsByClassId(clazz.getId());
                    return teacherIds.contains(teacherId);
                })
                .toList();
    }

    @Override
    public Clazz getPrimaryClassByStudentId(Long studentId) {
        log.debug("获取学生当前所在班级，学生 ID: {}", studentId);

        // 查找学生当前活跃的班级关联记录
        StudentClassHistory history = studentClassHistoryMapper.selectOne(
                new LambdaQueryWrapper<StudentClassHistory>()
                        .eq(StudentClassHistory::getStudentId, studentId)
                        .in(StudentClassHistory::getStatus, StudentClassStatus.ACTIVE.getCode())
                        .and(w -> w.isNull(StudentClassHistory::getEndDate)
                                .or()
                                .ge(StudentClassHistory::getEndDate, LocalDate.now()))
                        .orderByDesc(StudentClassHistory::getStartDate)
                        .last("LIMIT 1")
        );

        if (history == null) {
            log.debug("学生当前没有活跃的班级关联，学生 ID: {}", studentId);
            return null;
        }

        return clazzMapper.selectById(history.getClassId());
    }

    @Override
    public List<StudentTransferHistoryItemResponse> getStudentClassHistory(Long studentId, Long tenantId) {
        log.debug("获取学生调班历史，学生 ID: {}, 租户 ID: {}", studentId, tenantId);

        List<StudentClassHistory> histories = studentClassHistoryMapper.selectList(
                new LambdaQueryWrapper<StudentClassHistory>()
                        .eq(StudentClassHistory::getStudentId, studentId)
                        .orderByAsc(StudentClassHistory::getStartDate)
        );

        List<StudentTransferHistoryItemResponse> result = new ArrayList<>();
        Clazz prevClass = null;

        for (StudentClassHistory h : histories) {
            Clazz toClazz = getClassById(h.getClassId());
            if (toClazz == null || !tenantId.equals(toClazz.getTenantId())) {
                log.warn("调班历史引用的班级不存在或无权访问，跳过。historyId: {}, classId: {}", h.getId(), h.getClassId());
                continue;
            }

            StudentTransferHistoryItemResponse.ClassBasicInfo fromClassInfo = prevClass == null ? null
                    : StudentTransferHistoryItemResponse.ClassBasicInfo.builder()
                            .id(prevClass.getId())
                            .name(prevClass.getName())
                            .grade(prevClass.getGrade() != null ? prevClass.getGrade() : "")
                            .build();

            StudentTransferHistoryItemResponse.ClassBasicInfo toClassInfo =
                    StudentTransferHistoryItemResponse.ClassBasicInfo.builder()
                            .id(toClazz.getId())
                            .name(toClazz.getName())
                            .grade(toClazz.getGrade() != null ? toClazz.getGrade() : "")
                            .build();

            result.add(StudentTransferHistoryItemResponse.builder()
                    .id(h.getId())
                    .fromClass(fromClassInfo)
                    .toClass(toClassInfo)
                    .reason(null)
                    .operatedBy(null)
                    .createdAt(h.getCreatedAt())
                    .build());

            prevClass = toClazz;
        }

        Collections.reverse(result);
        return result;
    }

}
