package com.magistr.app.repository;

import com.magistr.app.model.TimeSlot;
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.time.LocalTime;

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

public interface TimeSlotRepository extends JpaRepository<TimeSlot, Long> {

    List<TimeSlot> findAllByOrderByTimeSlotScopeDisplayOrderAscOrderNumberAscStartTimeAsc();

    List<TimeSlot> findAllByTimeSlotScopeIdOrderByOrderNumberAsc(Long scopeId);

    Optional<TimeSlot> findByTimeSlotScopeIdAndOrderNumber(Long scopeId, Integer orderNumber);

    @Query("""
            select slot
            from TimeSlot slot
            join fetch slot.timeSlotScope
            order by slot.timeSlotScope.displayOrder, slot.orderNumber, slot.startTime
            """)
    List<TimeSlot> findAllForSchedule();

    boolean existsByTimeSlotScopeIdAndOrderNumber(Long scopeId, Integer orderNumber);

    boolean existsByTimeSlotScopeIdAndOrderNumberAndIdNot(Long scopeId, Integer orderNumber, Long id);

    boolean existsByTimeSlotScopeId(Long scopeId);

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

    @Query("""
            select case when count(slot) > 0 then true else false end
            from TimeSlot slot
            where slot.timeSlotScope.id = :scopeId
              and slot.startTime < :endTime
              and slot.endTime > :startTime
            """)
    boolean existsOverlapping(@Param("scopeId") Long scopeId,
                              @Param("startTime") LocalTime startTime,
                              @Param("endTime") LocalTime endTime);

    @Query("""
            select case when count(slot) > 0 then true else false end
            from TimeSlot slot
            where slot.timeSlotScope.id = :scopeId
              and slot.id <> :excludedId
              and slot.startTime < :endTime
              and slot.endTime > :startTime
            """)
    boolean existsOverlappingExcluding(@Param("scopeId") Long scopeId,
                                       @Param("excludedId") Long excludedId,
                                       @Param("startTime") LocalTime startTime,
                                       @Param("endTime") LocalTime endTime);
}
