package com.magistr.app.repository;

import com.magistr.app.model.StudentGroupCalendarAssignment;
import jakarta.persistence.LockModeType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;
import java.util.Collection;

public interface StudentGroupCalendarAssignmentRepository extends JpaRepository<StudentGroupCalendarAssignment, Long> {

    @Query("""
            select assignment
            from StudentGroupCalendarAssignment assignment
            join fetch assignment.studentGroup
            join fetch assignment.academicYear
            join fetch assignment.academicCalendar calendar
            join fetch calendar.speciality
            join fetch calendar.specialtyProfile
            join fetch calendar.studyForm
            where assignment.studentGroup.id = :groupId
            order by assignment.academicYear.startDate desc
            """)
    List<StudentGroupCalendarAssignment> findByGroupIdWithDetails(@Param("groupId") Long groupId);

    @Query("""
            select assignment
            from StudentGroupCalendarAssignment assignment
            join fetch assignment.academicYear
            join fetch assignment.academicCalendar calendar
            join fetch calendar.speciality
            join fetch calendar.specialtyProfile
            join fetch calendar.studyForm
            where assignment.studentGroup.id = :groupId
              and assignment.academicYear.id = :academicYearId
            """)
    Optional<StudentGroupCalendarAssignment> findByGroupIdAndAcademicYearIdWithDetails(
            @Param("groupId") Long groupId,
            @Param("academicYearId") Long academicYearId
    );

    @Query("""
            select assignment
            from StudentGroupCalendarAssignment assignment
            join fetch assignment.academicCalendar
            where assignment.studentGroup.id = :groupId
              and assignment.academicYear.id = :academicYearId
            """)
    Optional<StudentGroupCalendarAssignment> findForSchedule(
            @Param("groupId") Long groupId,
            @Param("academicYearId") Long academicYearId
    );

    @Query("""
            select assignment
            from StudentGroupCalendarAssignment assignment
            join fetch assignment.studentGroup
            join fetch assignment.academicYear
            join fetch assignment.academicCalendar
            where assignment.studentGroup.id in :groupIds
              and assignment.academicYear.id in :academicYearIds
            """)
    List<StudentGroupCalendarAssignment> findForScheduleBatch(
            @Param("groupIds") Collection<Long> groupIds,
            @Param("academicYearIds") Collection<Long> academicYearIds
    );

    @Query("""
            select assignment
            from StudentGroupCalendarAssignment assignment
            join fetch assignment.studentGroup studentGroup
            join fetch studentGroup.educationForm
            join fetch studentGroup.speciality
            join fetch studentGroup.specialtyProfile
            join fetch assignment.academicYear
            join fetch assignment.academicCalendar calendar
            join fetch calendar.speciality
            join fetch calendar.specialtyProfile
            join fetch calendar.studyForm
            where calendar.id = :calendarId
            order by assignment.id
            """)
    List<StudentGroupCalendarAssignment> findByCalendarIdWithDetails(@Param("calendarId") Long calendarId);

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("""
            select assignment
            from StudentGroupCalendarAssignment assignment
            join fetch assignment.academicYear
            join fetch assignment.academicCalendar calendar
            join fetch calendar.speciality
            join fetch calendar.specialtyProfile
            join fetch calendar.studyForm
            where assignment.studentGroup.id = :groupId
              and assignment.academicYear.id = :academicYearId
            """)
    Optional<StudentGroupCalendarAssignment> findByGroupIdAndAcademicYearIdForUpdate(
            @Param("groupId") Long groupId,
            @Param("academicYearId") Long academicYearId
    );
}
