package com.magistr.app.service;

import com.magistr.app.model.StudentGroup;
import com.magistr.app.model.StudentGroupCalendarAssignment;
import com.magistr.app.model.StudentGroupStudyState;
import com.magistr.app.repository.StudentGroupCalendarAssignmentRepository;
import com.magistr.app.utils.CourseAndSemesterCalculator;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.Comparator;
import java.util.Optional;

@Service
public class StudentGroupLifecycleService {

    private final StudentGroupCalendarAssignmentRepository assignmentRepository;

    public StudentGroupLifecycleService(StudentGroupCalendarAssignmentRepository assignmentRepository) {
        this.assignmentRepository = assignmentRepository;
    }

    public boolean isAvailableForSelection(StudentGroup group, LocalDate date) {
        return group != null
                && group.isActiveRecord()
                && group.isActiveOn(date)
                && !isGraduatedOn(group, date);
    }

    public boolean mayHaveScheduleInRange(StudentGroup group, LocalDate startDate, LocalDate endDate) {
        if (group == null || startDate == null || endDate == null || endDate.isBefore(startDate)) {
            return false;
        }
        Optional<Integer> courseLimit = resolveCourseLimit(group);
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            if (group.isActiveOn(date) && hasStarted(group, date) && !isGraduatedOn(group, date, courseLimit)) {
                return true;
            }
        }
        return false;
    }

    public StudentGroupStudyState getStudyState(StudentGroup group, LocalDate date) {
        if (group == null || group.isArchivedRecord()) {
            return StudentGroupStudyState.ARCHIVED;
        }
        if (!group.isActiveOn(date)) {
            return StudentGroupStudyState.INACTIVE;
        }
        if (isGraduatedOn(group, date)) {
            return StudentGroupStudyState.GRADUATED;
        }
        if (!hasStarted(group, date)) {
            return StudentGroupStudyState.NOT_STARTED;
        }
        return StudentGroupStudyState.ACTIVE;
    }

    private boolean hasStarted(StudentGroup group, LocalDate date) {
        return CourseAndSemesterCalculator.getActualCourse(group.getYearStartStudy(), date) > 0;
    }

    private boolean isGraduatedOn(StudentGroup group, LocalDate date) {
        return isGraduatedOn(group, date, resolveCourseLimit(group));
    }

    private boolean isGraduatedOn(StudentGroup group, LocalDate date, Optional<Integer> courseLimit) {
        int course = CourseAndSemesterCalculator.getActualCourse(group.getYearStartStudy(), date);
        return course > 0 && courseLimit.map(limit -> course > limit).orElse(false);
    }

    private Optional<Integer> resolveCourseLimit(StudentGroup group) {
        if (group.getId() == null) {
            return Optional.empty();
        }
        return assignmentRepository.findByGroupIdWithDetails(group.getId()).stream()
                .map(StudentGroupCalendarAssignment::getAcademicCalendar)
                .filter(calendar -> calendar.getCourseCount() != null)
                .map(calendar -> calendar.getCourseCount())
                .max(Comparator.naturalOrder());
    }
}
