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.StudentClassHistory;
import com.reading.platform.mapper.ClassTeacherMapper;
import com.reading.platform.mapper.ClazzMapper;
import com.reading.platform.mapper.StudentClassHistoryMapper;
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;

    @Override
    @Transactional
    public Clazz createClass(Long 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(Long 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(Long 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(Long 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(Long id) {
        getClassById(id);
        clazzMapper.deleteById(id);
    }

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

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

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

    @Override
    @Transactional
    public void assignStudents(Long classId, List<Long> 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 (Long 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<Long> getTeacherIdsByClassId(Long 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;
    }

}
