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();
}
}