package com.reading.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.reading.platform.common.enums.ErrorCode;
import com.reading.platform.common.exception.BusinessException;
import com.reading.platform.common.util.PageUtils;
import com.reading.platform.dto.request.ClassCreateRequest;
import com.reading.platform.dto.request.ClassUpdateRequest;
import com.reading.platform.entity.ClassTeacher;
import com.reading.platform.entity.Clazz;
import com.reading.platform.entity.Student;
import com.reading.platform.entity.StudentClassHistory;
import com.reading.platform.mapper.ClassTeacherMapper;
import com.reading.platform.mapper.ClazzMapper;
import com.reading.platform.mapper.StudentClassHistoryMapper;
import com.reading.platform.mapper.StudentMapper;
import com.reading.platform.service.ClassService;
import lombok.RequiredArgsConstructor;
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.List;

@Service
@RequiredArgsConstructor
public class ClassServiceImpl implements ClassService {

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

    @Override
    @Transactional
    public Clazz createClass(String tenantId, ClassCreateRequest request) {
        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("active");

        clazzMapper.insert(clazz);
        return clazz;
    }

    @Override
    @Transactional
    public Clazz updateClass(String id, ClassUpdateRequest request) {
        Clazz clazz = getClassById(id);

        if (StringUtils.hasText(request.getName())) {
            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);
        return clazz;
    }

    @Override
    public Clazz getClassById(String id) {
        Clazz clazz = clazzMapper.selectById(id);
        if (clazz == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Class not found");
        }
        return clazz;
    }

    @Override
    public Page<Clazz> getClassPage(String tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status) {
        Page<Clazz> page = PageUtils.of(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(String id) {
        getClassById(id);
        clazzMapper.deleteById(id);
    }

    @Override
    @Transactional
    public void assignTeachers(String classId, List<String> teacherIds) {
        // Verify class exists
        getClassById(classId);

        // Delete existing teacher assignments
        classTeacherMapper.delete(
                new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getClassId, classId)
        );

        // Create new assignments
        for (String teacherId : teacherIds) {
            ClassTeacher classTeachers = new ClassTeacher();
            classTeachers.setClassId(classId);
            classTeachers.setTeacherId(teacherId);
            classTeachers.setRole("teacher");
            classTeacherMapper.insert(classTeachers);
        }
    }

    @Override
    @Transactional
    public void assignStudents(String classId, List<String> studentIds) {
        // Verify class exists
        getClassById(classId);

        // End existing active class assignments for students
        List<StudentClassHistory> existingHistories = studentClassHistoryMapper.selectList(
                new LambdaQueryWrapper<StudentClassHistory>()
                        .eq(StudentClassHistory::getClassId, classId)
                        .eq(StudentClassHistory::getStatus, "active")
                        .isNull(StudentClassHistory::getEndDate)
        );

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

        // Create new assignments
        for (String studentId : studentIds) {
            StudentClassHistory history = new StudentClassHistory();
            history.setStudentId(studentId);
            history.setClassId(classId);
            history.setStartDate(LocalDate.now());
            history.setStatus("active");
            studentClassHistoryMapper.insert(history);
        }
    }

    @Override
    public List<String> getTeacherIdsByClassId(String classId) {
        List<ClassTeacher> classTeachers = classTeacherMapper.selectList(
                new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getClassId, classId)
        );

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

    @Override
    @Transactional
    public void removeTeacher(String classId, String teacherId) {
        // Verify class exists
        getClassById(classId);

        // Delete teacher assignment
        classTeacherMapper.delete(
                new LambdaQueryWrapper<ClassTeacher>()
                        .eq(ClassTeacher::getClassId, classId)
                        .eq(ClassTeacher::getTeacherId, teacherId)
        );
    }

    @Override
    @Transactional
    public void removeStudent(String classId, String studentId) {
        // Verify class exists
        getClassById(classId);

        // End active class assignment for student
        List<StudentClassHistory> existingHistories = studentClassHistoryMapper.selectList(
                new LambdaQueryWrapper<StudentClassHistory>()
                        .eq(StudentClassHistory::getClassId, classId)
                        .eq(StudentClassHistory::getStudentId, studentId)
                        .eq(StudentClassHistory::getStatus, "active")
                        .isNull(StudentClassHistory::getEndDate)
        );

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

    @Override
    public List<Clazz> getClassList(String tenantId) {
        LambdaQueryWrapper<Clazz> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Clazz::getTenantId, tenantId)
                .eq(Clazz::getStatus, "active")
                .orderByDesc(Clazz::getCreatedAt);
        return clazzMapper.selectList(wrapper);
    }

    @Override
    public Page<Student> getClassStudents(String classId, Integer pageNum, Integer pageSize, String keyword) {
        Page<Student> page = PageUtils.of(pageNum, pageSize);

        // 获取班级 active 状态的学生
        List<StudentClassHistory> histories = studentClassHistoryMapper.selectList(
                new LambdaQueryWrapper<StudentClassHistory>()
                        .eq(StudentClassHistory::getClassId, classId)
                        .eq(StudentClassHistory::getStatus, "active")
                        .isNull(StudentClassHistory::getEndDate)
        );

        if (histories.isEmpty()) {
            return new Page<>(pageNum, pageSize, 0);
        }

        List<String> studentIds = new ArrayList<>();
        for (StudentClassHistory history : histories) {
            studentIds.add(history.getStudentId());
        }

        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Student::getId, studentIds);

        if (StringUtils.hasText(keyword)) {
            wrapper.like(Student::getName, keyword);
        }
        wrapper.orderByDesc(Student::getCreatedAt);

        return studentMapper.selectPage(page, wrapper);
    }

    @Override
    public List<ClassTeacher> getClassTeachers(String classId) {
        LambdaQueryWrapper<ClassTeacher> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassTeacher::getClassId, classId)
                .orderByAsc(ClassTeacher::getSortOrder);
        return classTeacherMapper.selectList(wrapper);
    }

    @Override
    @Transactional
    public ClassTeacher addClassTeacher(String tenantId, String classId, String teacherId, String role, Boolean isPrimary) {
        // 验证班级是否存在
        getClassById(classId);

        // 检查是否已存在
        ClassTeacher existing = classTeacherMapper.selectOne(
                new LambdaQueryWrapper<ClassTeacher>()
                        .eq(ClassTeacher::getClassId, classId)
                        .eq(ClassTeacher::getTeacherId, teacherId)
        );

        if (existing != null) {
            throw new BusinessException(ErrorCode.DATA_ALREADY_EXISTS, "该教师已在班级中");
        }

        ClassTeacher classTeachers = new ClassTeacher();
        classTeachers.setClassId(classId);
        classTeachers.setTeacherId(teacherId);
        classTeachers.setRole(role != null ? role : "ASSIST");
        classTeachers.setIsPrimary(isPrimary != null ? isPrimary : false);
        classTeacherMapper.insert(classTeachers);

        return classTeachers;
    }

    @Override
    @Transactional
    public ClassTeacher updateClassTeacher(String tenantId, String classId, String teacherId, String role, Boolean isPrimary) {
        // 验证班级是否存在
        getClassById(classId);

        ClassTeacher classTeachers = classTeacherMapper.selectOne(
                new LambdaQueryWrapper<ClassTeacher>()
                        .eq(ClassTeacher::getClassId, classId)
                        .eq(ClassTeacher::getTeacherId, teacherId)
        );

        if (classTeachers == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "班级教师关系不存在");
        }

        if (StringUtils.hasText(role)) {
            classTeachers.setRole(role);
        }
        if (isPrimary != null) {
            classTeachers.setIsPrimary(isPrimary);
        }

        classTeacherMapper.updateById(classTeachers);
        return classTeachers;
    }

    @Override
    @Transactional
    public void removeClassTeacher(String tenantId, String classId, String teacherId) {
        // 验证班级是否存在
        getClassById(classId);

        classTeacherMapper.delete(
                new LambdaQueryWrapper<ClassTeacher>()
                        .eq(ClassTeacher::getClassId, classId)
                        .eq(ClassTeacher::getTeacherId, teacherId)
        );
    }

}
