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 -> "опекун";
};
}
}