package com.magistr.app.repository;

import com.magistr.app.model.ScheduleRule;
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 ScheduleRuleRepository extends JpaRepository<ScheduleRule, Long> {

    @Query("""
            select distinct r
            from ScheduleRule r
            join r.groups g
            left join fetch r.subject
            left join fetch r.semester sem
            left join fetch sem.academicYear
            left join fetch r.groups groups
            left join fetch r.slots slots
            left join fetch slots.timeSlot
            left join fetch slots.subgroups slotSubgroups
            left join fetch slotSubgroups.studentGroup
            left join fetch slots.teacher
            left join fetch slots.classroom
            left join fetch slots.lessonType
            where g.id = :groupId
              and sem.id = :semesterId
              and r.status <> 'ARCHIVED'
            """)
    List<ScheduleRule> findByGroupIdAndSemesterId(
            @Param("groupId") Long groupId,
            @Param("semesterId") Long semesterId
    );

    @Query("""
            select distinct r
            from ScheduleRule r
            join r.slots teacherSlot
            left join fetch r.subject
            left join fetch r.semester sem
            left join fetch sem.academicYear
            left join fetch r.groups groups
            left join fetch r.slots slots
            left join fetch slots.timeSlot
            left join fetch slots.subgroups slotSubgroups
            left join fetch slotSubgroups.studentGroup
            left join fetch slots.teacher
            left join fetch slots.classroom
            left join fetch slots.lessonType
            where teacherSlot.teacher.id = :teacherId
              and sem.id = :semesterId
              and r.status <> 'ARCHIVED'
            """)
    List<ScheduleRule> findByTeacherIdAndSemesterId(
            @Param("teacherId") Long teacherId,
            @Param("semesterId") Long semesterId
    );

    @Query("""
            select distinct r
            from ScheduleRule r
            join r.groups matchingGroup
            left join fetch r.subject
            left join fetch r.semester sem
            left join fetch sem.academicYear
            left join fetch r.groups groups
            left join fetch r.slots slots
            left join fetch slots.timeSlot
            left join fetch slots.subgroups slotSubgroups
            left join fetch slotSubgroups.studentGroup
            left join fetch slots.teacher
            left join fetch slots.classroom
            left join fetch slots.lessonType
            where matchingGroup.id in :groupIds
              and sem.id in :semesterIds
              and r.status <> 'ARCHIVED'
            """)
    List<ScheduleRule> findByGroupIdsAndSemesterIds(
            @Param("groupIds") Collection<Long> groupIds,
            @Param("semesterIds") Collection<Long> semesterIds
    );

    @Query("""
            select distinct r
            from ScheduleRule r
            join r.slots teacherSlot
            left join fetch r.subject
            left join fetch r.semester sem
            left join fetch sem.academicYear
            left join fetch r.groups groups
            left join fetch r.slots slots
            left join fetch slots.timeSlot
            left join fetch slots.subgroups slotSubgroups
            left join fetch slotSubgroups.studentGroup
            left join fetch slots.teacher
            left join fetch slots.classroom
            left join fetch slots.lessonType
            where teacherSlot.teacher.id = :teacherId
              and sem.id in :semesterIds
              and r.status <> 'ARCHIVED'
            """)
    List<ScheduleRule> findByTeacherIdAndSemesterIds(
            @Param("teacherId") Long teacherId,
            @Param("semesterIds") Collection<Long> semesterIds
    );

    @Query("""
            select distinct r
            from ScheduleRule r
            left join fetch r.subject
            left join fetch r.semester sem
            left join fetch sem.academicYear
            left join fetch r.groups groups
            left join fetch r.slots slots
            left join fetch slots.timeSlot
            left join fetch slots.subgroups slotSubgroups
            left join fetch slotSubgroups.studentGroup
            left join fetch slots.teacher
            left join fetch slots.classroom
            left join fetch slots.lessonType
            where r.status <> 'ARCHIVED'
            order by r.id desc
            """)
    List<ScheduleRule> findAllWithDetails();

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("select rule from ScheduleRule rule where rule.id = :id")
    Optional<ScheduleRule> findByIdForUpdate(@Param("id") Long id);

    @Query("""
            select distinct rule
            from ScheduleRule rule
            left join fetch rule.subject
            left join fetch rule.semester semester
            left join fetch semester.academicYear
            left join fetch rule.groups groups
            left join fetch rule.slots slots
            left join fetch slots.timeSlot
            left join fetch slots.subgroups slotSubgroups
            left join fetch slotSubgroups.studentGroup
            left join fetch slots.teacher
            left join fetch slots.classroom
            left join fetch slots.lessonType
            where semester.id = :semesterId
              and rule.status <> 'ARCHIVED'
              and (:excludeRuleId is null or rule.id <> :excludeRuleId)
            order by rule.id
            """)
    List<ScheduleRule> findActiveBySemesterIdWithDetails(
            @Param("semesterId") Long semesterId,
            @Param("excludeRuleId") Long excludeRuleId
    );

    @Query("""
            select distinct r
            from ScheduleRule r
            left join fetch r.subject
            left join fetch r.semester sem
            left join fetch sem.academicYear
            left join fetch r.groups groups
            left join fetch r.slots slots
            left join fetch slots.timeSlot
            left join fetch slots.subgroups slotSubgroups
            left join fetch slotSubgroups.studentGroup
            left join fetch slots.teacher
            left join fetch slots.classroom
            left join fetch slots.lessonType
            where r.id = :id
            """)
    Optional<ScheduleRule> findByIdWithDetails(@Param("id") Long id);
}
