package com.atlassian.stash.internal.crowd;

import com.atlassian.crowd.embedded.api.ApplicationFactory;
import com.atlassian.crowd.embedded.api.PasswordCredential;
import com.atlassian.crowd.event.EventStore;
import com.atlassian.crowd.exception.*;
import com.atlassian.crowd.manager.application.SearchStrategyFactory;
import com.atlassian.crowd.manager.avatar.AvatarProvider;
import com.atlassian.crowd.manager.directory.DirectoryManager;
import com.atlassian.crowd.manager.permission.PermissionManager;
import com.atlassian.crowd.manager.recovery.RecoveryModeAwareApplicationService;
import com.atlassian.crowd.manager.recovery.RecoveryModeService;
import com.atlassian.crowd.manager.webhook.WebhookRegistry;
import com.atlassian.crowd.model.application.Application;
import com.atlassian.crowd.model.user.User;
import com.atlassian.event.api.EventPublisher;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * Override of Crowd's {@link RecoveryModeAwareApplicationService} that does not create a transaction around user
 * authentication. Crowd authentication may involve a remote call which could keep a transaction open for up to
 * 2 minutes if there are network issues or the remote Crowd/LDAP instance is under heavy load or malfunctioning.
 * Instead of a single transaction at a high level, multiple small transactions will be created when interacting with
 * the database.
 *
 * @since 3.4
 */
public class CustomizedApplicationService extends RecoveryModeAwareApplicationService {

    public CustomizedApplicationService(DirectoryManager directoryManager,
                                        SearchStrategyFactory searchStrategyFactory,
                                        PermissionManager permissionManager,
                                        EventPublisher eventPublisher,
                                        EventStore eventStore,
                                        WebhookRegistry webhookRegistry,
                                        AvatarProvider avatarProvider,
                                        ApplicationFactory applicationFactory,
                                        RecoveryModeService recoveryModeService) {

        super(directoryManager, searchStrategyFactory, permissionManager, eventPublisher, eventStore,
                webhookRegistry, avatarProvider, applicationFactory, recoveryModeService);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public User authenticateUser(Application application, String username, PasswordCredential passwordCredential)
            throws OperationFailedException, InactiveAccountException, InvalidAuthenticationException,
            ExpiredCredentialException, UserNotFoundException {
        return super.authenticateUser(application, username, passwordCredential);
    }
}
