package de.tum.in.www1.artemis.repository;

import static org.springframework.data.jpa.repository.EntityGraph.EntityGraphType.LOAD;

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

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import de.tum.in.www1.artemis.domain.User;

/** Spring Data JPA repository for the User entity. */
@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    String USERS_CACHE = "users";

    Optional<User> findOneByActivationKey(String activationKey);

    List<User> findAllByRegistrationNumberIsNull();

    Optional<User> findOneByResetKey(String resetKey);

    Optional<User> findOneByEmailIgnoreCase(String email);

    Optional<User> findOneByLogin(String login);

    @EntityGraph(type = LOAD, attributePaths = { "groups" })
    Optional<User> findOneWithGroupsByLogin(String login);

    @EntityGraph(type = LOAD, attributePaths = { "authorities" })
    Optional<User> findOneWithAuthoritiesByLogin(String login);

    @EntityGraph(type = LOAD, attributePaths = { "groups", "authorities" })
    Optional<User> findOneWithGroupsAndAuthoritiesByLogin(String login);

    @EntityGraph(type = LOAD, attributePaths = { "groups", "authorities", "guidedTourSettings" })
    Optional<User> findOneWithGroupsAuthoritiesAndGuidedTourSettingsByLogin(String login);

    @Query("select count(*) from User user where :#{#groupName} member of user.groups")
    Long countByGroupsIsContaining(@Param("groupName") String groupName);

    @EntityGraph(type = LOAD, attributePaths = { "groups" })
    @Query("select user from User user where :#{#groupName} member of user.groups")
    List<User> findAllInGroup(@Param("groupName") String groupName);

    /**
     * Searches for users in a group by their login or full name.
     * @param groupName Name of group in which to search for users
     * @param loginOrName Either a login (e.g. ga12abc) or name (e.g. Max Mustermann) by which to search
     * @return list of found users that match the search criteria
     */
    @EntityGraph(type = LOAD, attributePaths = { "groups" })
    @Query("select user from User user where :#{#groupName} member of user.groups and "
            + "(user.login like :#{#loginOrName}% or concat_ws(' ', user.firstName, user.lastName) like %:#{#loginOrName}%)")
    List<User> searchByLoginOrNameInGroup(@Param("groupName") String groupName, @Param("loginOrName") String loginOrName);

    /**
     * Searches for users by their login or full name.
     * @param page Pageable related info (e.g. for page size)
     * @param loginOrName Either a login (e.g. ga12abc) or name (e.g. Max Mustermann) by which to search
     * @return list of found users that match the search criteria
     */
    @EntityGraph(type = LOAD, attributePaths = { "groups" })
    @Query("select user from User user where user.login like :#{#loginOrName}% or concat_ws(' ', user.firstName, user.lastName) like %:#{#loginOrName}%")
    Page<User> searchAllByLoginOrName(Pageable page, @Param("loginOrName") String loginOrName);

    @EntityGraph(type = LOAD, attributePaths = { "groups" })
    @Query("select user from User user")
    Page<User> findAllWithGroups(Pageable pageable);

    @EntityGraph(attributePaths = { "groups" })
    @Query("select user from User user where user.login like %:searchTerm% or user.email like %:searchTerm% "
            + "or user.lastName like %:searchTerm% or user.firstName like %:searchTerm%")
    Page<User> searchByLoginOrNameWithGroups(String searchTerm, Pageable pageable);

    @Modifying
    @Query("Update User user set user.lastNotificationRead = current_timestamp() where user.id = :#{#userId}")
    void updateUserNotificationReadDate(@Param("userId") Long userId);

    @EntityGraph(type = LOAD, attributePaths = { "groups" })
    @Query("select user from User user where :#{#groupName} member of user.groups and user not in :#{#ignoredUsers}")
    List<User> findAllInGroupContainingAndNotIn(@Param("groupName") String groupName, @Param("ignoredUsers") Set<User> ignoredUsers);
}

@@ -3612,16 +3612,29 @@
 tyGraph(
+type = LOAD, 
 attribut
@@ -3711,32 +3711,35 @@
 er.login like %25:
+#%7B#
 searchTerm%25 or u
@@ -3724,32 +3724,33 @@
  %25:#%7B#searchTerm
+%7D
 %25 or user.email 
@@ -3748,32 +3748,35 @@
 er.email like %25:
+#%7B#
 searchTerm%25 %22%0A  
@@ -3769,16 +3769,17 @@
 archTerm
+%7D
 %25 %22%0A    
@@ -3805,32 +3805,35 @@
 lastName like %25:
+#%7B#
 searchTerm%25 or u
@@ -3826,16 +3826,17 @@
 archTerm
+%7D
 %25 or use
@@ -3854,16 +3854,19 @@
  like %25:
+#%7B#
 searchTe
@@ -3867,16 +3867,17 @@
 archTerm
+%7D
 %25%22)%0A    
@@ -3917,16 +3917,37 @@
 hGroups(
+@Param(%22searchTerm%22) 
 String s

fix query in UserRepository