package com.atlassian.stash.internal.user;

import com.atlassian.bitbucket.user.DetailedUser;
import com.atlassian.event.api.EventListener;
import com.atlassian.bitbucket.event.auth.AuthenticationSuccessEvent;
import com.atlassian.bitbucket.EntityOutOfDateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Listens for {@link AuthenticationSuccessEvent AuthenticationSuccessEvent}s to track
 * a {@link DetailedUser#getLastAuthenticationTimestamp() last authentication timestamp}
 * for them.
 *
 * @since 3.7
 */
@Component
public class UserAuthenticationTracker {

    private static final Logger log = LoggerFactory.getLogger(UserAuthenticationTracker.class);

    private final InternalUserService userService;

    @Autowired
    public UserAuthenticationTracker(InternalUserService userService) {
        this.userService = userService;
    }

    @EventListener
    public void onAuthenticationSuccess(AuthenticationSuccessEvent event) {
        String username = event.getUsername();
        if (username != null) {
            try {
                userService.updateLastAuthentication(username);
            } catch (EntityOutOfDateException ignored) {
                //Concurrent logins for the same user may trigger concurrent updates for their authentication
                //timestamp. One update wins and the losers get this exception. Since it means the timestamp
                //was just updated, ignore it without logging
            } catch (RuntimeException e) {
                //Catch and log any other failure, rather than letting it bubble up to the event framework
                log.warn("{}: Failed to update last authentication timestamp", username, e);
            }
        }
    }
}
