Newer
Older
teacher-diary / src / main / java / ru / mcs / diary / student / StudentService.java
package ru.mcs.diary.student;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.mcs.diary.common.exception.ResourceNotFoundException;
import ru.mcs.diary.parent.Parent;
import ru.mcs.diary.parent.ParentRepository;
import ru.mcs.diary.parent.ParentType;
import ru.mcs.diary.student.dto.StudentCreateRequest;
import ru.mcs.diary.student.dto.StudentListDto;
import ru.mcs.diary.teacher.Teacher;
import ru.mcs.diary.teacher.TeacherRepository;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class StudentService {

    private final StudentRepository studentRepository;
    private final StudentParentRepository studentParentRepository;
    private final ParentRepository parentRepository;
    private final TeacherRepository teacherRepository;

    @Transactional(readOnly = true)
    public List<StudentListDto> getAllStudents(Long teacherId) {
        return studentRepository.findAllByTeacherIdOrderByLastNameAscFirstNameAsc(teacherId)
                .stream()
                .map(this::toListDto)
                .toList();
    }

    @Transactional(readOnly = true)
    public Student getStudent(Long id, Long teacherId) {
        return studentRepository.findByIdAndTeacherId(id, teacherId)
                .orElseThrow(() -> new ResourceNotFoundException("Ученик", id));
    }

    @Transactional(readOnly = true)
    public Student getStudentWithParents(Long id, Long teacherId) {
        return studentRepository.findByIdWithParents(id, teacherId)
                .orElseThrow(() -> new ResourceNotFoundException("Ученик", id));
    }

    @Transactional
    public Student createStudent(StudentCreateRequest request, Long teacherId) {
        log.info("Creating student: {} {}", request.getLastName(), request.getFirstName());

        Teacher teacher = teacherRepository.findById(teacherId)
                .orElseThrow(() -> new ResourceNotFoundException("Преподаватель", teacherId));

        Student student = Student.builder()
                .firstName(request.getFirstName().trim())
                .lastName(request.getLastName().trim())
                .patronymic(request.getPatronymic() != null ? request.getPatronymic().trim() : null)
                .phone(request.getPhone())
                .birthDate(request.getBirthDate())
                .notes(request.getNotes())
                .teacher(teacher)
                .build();

        return studentRepository.save(student);
    }

    @Transactional
    public Student updateStudent(Long id, StudentCreateRequest request, Long teacherId) {
        log.info("Updating student: {}", id);

        Student student = getStudent(id, teacherId);

        student.setFirstName(request.getFirstName().trim());
        student.setLastName(request.getLastName().trim());
        student.setPatronymic(request.getPatronymic() != null ? request.getPatronymic().trim() : null);
        student.setPhone(request.getPhone());
        student.setBirthDate(request.getBirthDate());
        student.setNotes(request.getNotes());

        return studentRepository.save(student);
    }

    @Transactional
    public void deleteStudent(Long id, Long teacherId) {
        log.info("Deleting student: {}", id);
        Student student = getStudent(id, teacherId);
        studentRepository.delete(student);
    }

    @Transactional
    public void linkParent(Long studentId, Long parentId, ParentType parentType, Long teacherId) {
        Student student = getStudent(studentId, teacherId);
        Parent parent = parentRepository.findById(parentId)
                .orElseThrow(() -> new ResourceNotFoundException("Родитель", parentId));

        // Проверяем, что такой тип родителя ещё не привязан
        if (studentParentRepository.existsByStudentIdAndParentType(studentId, parentType)) {
            throw new IllegalArgumentException("У ученика уже есть " + getParentTypeName(parentType));
        }

        StudentParent studentParent = StudentParent.builder()
                .student(student)
                .parent(parent)
                .parentType(parentType)
                .build();

        studentParentRepository.save(studentParent);
        log.info("Linked parent {} to student {} as {}", parentId, studentId, parentType);
    }

    @Transactional
    public void unlinkParent(Long studentId, Long parentId, Long teacherId) {
        getStudent(studentId, teacherId); // Проверка доступа
        studentParentRepository.deleteByStudentIdAndParentId(studentId, parentId);
        log.info("Unlinked parent {} from student {}", parentId, studentId);
    }

    public long countByTeacher(Long teacherId) {
        return studentRepository.countByTeacherId(teacherId);
    }

    private StudentListDto toListDto(Student student) {
        return StudentListDto.builder()
                .id(student.getId())
                .fullName(student.getFullName())
                .phone(student.getPhone())
                .groupCount(student.getGroups().size())
                .parentCount(student.getStudentParents().size())
                .build();
    }

    private String getParentTypeName(ParentType type) {
        return switch (type) {
            case MOTHER -> "мама";
            case FATHER -> "папа";
            case GRANDMOTHER -> "бабушка";
            case GRANDFATHER -> "дедушка";
            case BROTHER -> "брат";
            case SISTER -> "сестра";
            case GUARDIAN -> "опекун";
        };
    }
}