package com.atlassian.stash.internal.user;

import com.atlassian.bitbucket.user.*;
import com.atlassian.sal.api.user.UserKey;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Set;

/**
 * @since 2.12
 */
public interface InternalUserService extends UserService {

    String ATTR_LAST_AUTHENTICATION_TIMESTAMP = "lastAuthenticationTimestamp";

    /**
     * Retrieves a page of {@link UserType#SERVICE service} users, optionally
     * filtering the returned results to those containing the specified {@code displayName}.
     * If the provided {@code displayName} is {@code null} or empty then no filtering is done.
     *
     * @param displayName 0 or more characters to apply as a filter on returned service users
     * @param pageRequest defines the page of service users to retrieve
     * @return the requested page of service users, potentially filtered, which may be empty but never {@code null}
     * @since 2.12
     */
    @Nonnull
    Page<ServiceUser> findServiceUsersByName(@Nullable String displayName, @Nonnull PageRequest pageRequest);

    /**
     * Maps {@link ApplicationUser users} by their e-mail address. This is intended as a bulk version of
     * {@link UserService#findUserByNameOrEmail(String) findUserByNameOrEmail}, with the secondary
     * goal being that this can offer a single point of optimization for this type of request.
     * <p>
     * There is <i>no guarantee</i> that a given e-mail address will match a user. Addresses which
     * don't match a user will not be included in the returned map. As a result, the returned map
     * may be empty even though the provided set of e-mail addresses is not.
     *
     * @param emailAddresses a set containing one or more e-mail addresses to map users for
     * @return a map containing zero or more users mapped by their e-mail address
     */
    @Nonnull
    Map<String, ApplicationUser> mapUsersByEmail(@Nonnull Set<String> emailAddresses);

    /**
     * Retrieves a {@link ApplicationUser} by its {@link ApplicationUser#getId() ID}, or by its name depending
     * on the contents of the provided {@link UserKey}.
     * <p>
     * <b>Note</b>: This method will <i>not</i> return deleted or inactive users.
     *
     * @param key a user key containing information to identify the user.
     * @return the user with the specified ID/name, or {@code null} if no matching user exists
     * @since 3.2
     */
    @Nullable
    ApplicationUser getUserByKey(@Nullable UserKey key);

    /**
     * Retrieves a {@link ApplicationUser} by its {@link ApplicationUser#getId() ID}, or by its name depending
     * on the contents of the provided {@link UserKey}.
     * <p>
     * <b>Note</b>: This method will return deleted or inactive users depending on the value of {@code inactive}.
     *
     * @param key a user key containing information to identify the user.
     * @param inactive whether to return deleted and inactive users
     * @return the user with the specified ID/name, or {@code null} if no matching user exists
     * @since 3.9
     */
    @Nullable
    ApplicationUser getUserByKey(@Nullable UserKey key, boolean inactive);

    /**
     * Updates the {@link DetailedUser#getLastAuthenticationTimestamp() last authentication
     * timestamp} for the specified user.
     *
     * @param username the username to update the timestamp for
     * @since 3.7
     */
    void updateLastAuthentication(@Nonnull String username);
}
