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.StudentCreateRequest;
import com.reading.platform.dto.request.StudentUpdateRequest;
import com.reading.platform.entity.ParentStudent;
import com.reading.platform.entity.Student;
import com.reading.platform.entity.StudentClassHistory;
import com.reading.platform.mapper.ParentStudentMapper;
import com.reading.platform.mapper.StudentClassHistoryMapper;
import com.reading.platform.mapper.StudentMapper;
import com.reading.platform.service.StudentService;
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 StudentServiceImpl implements StudentService {

    private final StudentMapper studentMapper;
    private final ParentStudentMapper parentStudentMapper;
    private final StudentClassHistoryMapper studentClassHistoryMapper;

    @Override
    @Transactional
    public Student createStudent(Long tenantId, StudentCreateRequest request) {
        Student student = new Student();
        student.setTenantId(tenantId);
        student.setName(request.getName());
        student.setGender(request.getGender());
        student.setBirthDate(request.getBirthDate());
        student.setGrade(request.getGrade());
        student.setStudentNo(request.getStudentNo());
        student.setReadingLevel(request.getReadingLevel());
        student.setInterests(request.getInterests());
        student.setNotes(request.getNotes());
        student.setStatus("active");

        studentMapper.insert(student);
        return student;
    }

    @Override
    @Transactional
    public Student updateStudent(Long id, StudentUpdateRequest request) {
        Student student = getStudentById(id);

        if (StringUtils.hasText(request.getName())) {
            student.setName(request.getName());
        }
        if (request.getGender() != null) {
            student.setGender(request.getGender());
        }
        if (request.getBirthDate() != null) {
            student.setBirthDate(request.getBirthDate());
        }
        if (request.getAvatarUrl() != null) {
            student.setAvatarUrl(request.getAvatarUrl());
        }
        if (request.getGrade() != null) {
            student.setGrade(request.getGrade());
        }
        if (request.getStudentNo() != null) {
            student.setStudentNo(request.getStudentNo());
        }
        if (request.getReadingLevel() != null) {
            student.setReadingLevel(request.getReadingLevel());
        }
        if (request.getInterests() != null) {
            student.setInterests(request.getInterests());
        }
        if (request.getNotes() != null) {
            student.setNotes(request.getNotes());
        }
        if (StringUtils.hasText(request.getStatus())) {
            student.setStatus(request.getStatus());
        }

        studentMapper.updateById(student);
        return student;
    }

    @Override
    public Student getStudentById(Long id) {
        Student student = studentMapper.selectById(id);
        if (student == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Student not found");
        }
        return student;
    }

    @Override
    public Page<Student> getStudentPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String grade, String status) {
        Page<Student> page = PageUtils.of(pageNum, pageSize);
        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();

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

        if (StringUtils.hasText(keyword)) {
            wrapper.and(w -> w
                    .like(Student::getName, keyword)
                    .or()
                    .like(Student::getStudentNo, keyword)
            );
        }
        if (StringUtils.hasText(grade)) {
            wrapper.eq(Student::getGrade, grade);
        }
        if (StringUtils.hasText(status)) {
            wrapper.eq(Student::getStatus, status);
        }
        wrapper.orderByDesc(Student::getCreatedAt);

        return studentMapper.selectPage(page, wrapper);
    }

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

        // Get active student IDs from class history
        List<StudentClassHistory> histories = studentClassHistoryMapper.selectList(
                new LambdaQueryWrapper<StudentClassHistory>()
                        .eq(StudentClassHistory::getClassId, classId)
                        .eq(StudentClassHistory::getStatus, "active")
                        .isNull(StudentClassHistory::getEndDate)
                        .or()
                        .ge(StudentClassHistory::getEndDate, LocalDate.now())
        );

        if (histories.isEmpty()) {
            return page;
        }

        List<Long> studentIds = histories.stream()
                .map(StudentClassHistory::getStudentId)
                .toList();

        if (studentIds.isEmpty()) {
            return page;
        }

        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Student::getId, studentIds)
                .eq(Student::getStatus, "active")
                .orderByAsc(Student::getName);

        return studentMapper.selectPage(page, wrapper);
    }

    @Override
    @Transactional
    public void deleteStudent(Long id) {
        getStudentById(id);
        studentMapper.deleteById(id);
    }

    @Override
    public List<Student> getStudentsByParentId(Long parentId) {
        List<ParentStudent> parentStudents = parentStudentMapper.selectList(
                new LambdaQueryWrapper<ParentStudent>()
                        .eq(ParentStudent::getParentId, parentId)
        );

        if (parentStudents.isEmpty()) {
            return new ArrayList<>();
        }

        List<Long> studentIds = parentStudents.stream()
                .map(ParentStudent::getStudentId)
                .toList();

        return studentMapper.selectList(
                new LambdaQueryWrapper<Student>()
                        .in(Student::getId, studentIds)
                        .eq(Student::getStatus, "active")
        );
    }

}
