Newer
Older
teacher-diary / src / main / java / ru / mcs / diary / lesson / LessonService.java
package ru.mcs.diary.lesson;

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.group.GroupRepository;
import ru.mcs.diary.group.StudyGroup;
import ru.mcs.diary.lesson.dto.LessonCreateRequest;
import ru.mcs.diary.lesson.dto.LessonDto;
import ru.mcs.diary.teacher.Teacher;
import ru.mcs.diary.teacher.TeacherRepository;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class LessonService {

    private final LessonRepository lessonRepository;
    private final GroupRepository groupRepository;
    private final TeacherRepository teacherRepository;

    @Transactional(readOnly = true)
    public List<LessonDto> getLessonsByDate(Long teacherId, LocalDate date) {
        return lessonRepository.findByTeacherIdAndDate(teacherId, date)
                .stream()
                .map(this::toDto)
                .toList();
    }

    @Transactional(readOnly = true)
    public Map<LocalDate, List<LessonDto>> getWeekLessons(Long teacherId, LocalDate weekStart) {
        LocalDate weekEnd = weekStart.plusDays(6);
        List<Lesson> lessons = lessonRepository.findByTeacherIdAndDateBetween(teacherId, weekStart, weekEnd);

        Map<LocalDate, List<LessonDto>> weekMap = new LinkedHashMap<>();
        for (int i = 0; i < 7; i++) {
            LocalDate day = weekStart.plusDays(i);
            List<LessonDto> dayLessons = lessons.stream()
                    .filter(l -> l.getDate().equals(day))
                    .map(this::toDto)
                    .toList();
            weekMap.put(day, dayLessons);
        }
        return weekMap;
    }

    @Transactional(readOnly = true)
    public Lesson getLesson(Long id, Long teacherId) {
        return lessonRepository.findByIdAndTeacherId(id, teacherId)
                .orElseThrow(() -> new ResourceNotFoundException("Занятие", id));
    }

    @Transactional(readOnly = true)
    public Lesson getLessonWithDetails(Long id, Long teacherId) {
        return lessonRepository.findByIdWithDetails(id, teacherId)
                .orElseThrow(() -> new ResourceNotFoundException("Занятие", id));
    }

    @Transactional
    public Lesson createLesson(LessonCreateRequest request, Long teacherId) {
        log.info("Creating lesson for group {} on {}", request.getGroupId(), request.getDate());

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

        StudyGroup group = groupRepository.findByIdAndTeacherId(request.getGroupId(), teacherId)
                .orElseThrow(() -> new ResourceNotFoundException("Группа", request.getGroupId()));

        validateTime(request);

        Lesson lesson = Lesson.builder()
                .group(group)
                .date(request.getDate())
                .startTime(request.getStartTime())
                .endTime(request.getEndTime())
                .topic(request.getTopic())
                .homework(request.getHomework())
                .notes(request.getNotes())
                .status(LessonStatus.SCHEDULED)
                .teacher(teacher)
                .build();

        return lessonRepository.save(lesson);
    }

    @Transactional
    public Lesson updateLesson(Long id, LessonCreateRequest request, Long teacherId) {
        log.info("Updating lesson: {}", id);

        Lesson lesson = getLesson(id, teacherId);

        StudyGroup group = groupRepository.findByIdAndTeacherId(request.getGroupId(), teacherId)
                .orElseThrow(() -> new ResourceNotFoundException("Группа", request.getGroupId()));

        validateTime(request);

        lesson.setGroup(group);
        lesson.setDate(request.getDate());
        lesson.setStartTime(request.getStartTime());
        lesson.setEndTime(request.getEndTime());
        lesson.setTopic(request.getTopic());
        lesson.setHomework(request.getHomework());
        lesson.setNotes(request.getNotes());

        if (request.getStatus() != null) {
            lesson.setStatus(request.getStatus());
        }

        return lessonRepository.save(lesson);
    }

    @Transactional
    public void deleteLesson(Long id, Long teacherId) {
        log.info("Deleting lesson: {}", id);
        Lesson lesson = getLesson(id, teacherId);
        lessonRepository.delete(lesson);
    }

    @Transactional
    public void updateStatus(Long id, LessonStatus status, Long teacherId) {
        Lesson lesson = getLesson(id, teacherId);
        lesson.setStatus(status);
        lessonRepository.save(lesson);
        log.info("Lesson {} status changed to {}", id, status);
    }

    public long countTodayLessons(Long teacherId) {
        return lessonRepository.countByTeacherIdAndDate(teacherId, LocalDate.now());
    }

    public LocalDate getWeekStart(LocalDate date) {
        return date.with(DayOfWeek.MONDAY);
    }

    private void validateTime(LessonCreateRequest request) {
        if (request.getEndTime().isBefore(request.getStartTime()) ||
                request.getEndTime().equals(request.getStartTime())) {
            throw new IllegalArgumentException("Время окончания должно быть позже времени начала");
        }
    }

    private LessonDto toDto(Lesson lesson) {
        return LessonDto.builder()
                .id(lesson.getId())
                .groupId(lesson.getGroup().getId())
                .groupName(lesson.getGroup().getName())
                .subjectName(lesson.getGroup().getSubject() != null ?
                        lesson.getGroup().getSubject().getName() : "—")
                .date(lesson.getDate())
                .startTime(lesson.getStartTime())
                .endTime(lesson.getEndTime())
                .topic(lesson.getTopic())
                .status(lesson.getStatus())
                .studentCount(lesson.getGroup().getStudents().size())
                .build();
    }
}