package com.atlassian.stash.internal.auth;

import com.atlassian.bitbucket.auth.HttpAuthenticationSuccessContext;
import com.atlassian.bitbucket.auth.HttpAuthenticationSuccessHandler;
import com.atlassian.bitbucket.auth.HttpAuthenticationSuccessHandlerModuleDescriptor;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.bitbucket.event.auth.AuthenticationSuccessEvent;
import com.atlassian.bitbucket.util.ModuleDescriptorUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

/**
 * Delegates to plugin provided {@link HttpAuthenticationSuccessHandler} modules, sorted by
 * {@link HttpAuthenticationSuccessHandlerModuleDescriptor#weight}.
 *
 * @since 2.3
 */
@Component("pluginHttpAuthenticationSuccessHandler")
public class PluginHttpAuthenticationSuccessHandler implements HttpAuthenticationSuccessHandler {

    private static final Logger log = LoggerFactory.getLogger(PluginHttpAuthenticationSuccessHandler.class);
    private final EventPublisher eventPublisher;
    private final PluginAccessor pluginAccessor;

    @Autowired
    public PluginHttpAuthenticationSuccessHandler(EventPublisher eventPublisher, PluginAccessor pluginAccessor) {
        this.eventPublisher = eventPublisher;
        this.pluginAccessor = pluginAccessor;
    }

    @Override
    public boolean onAuthenticationSuccess(@Nonnull HttpAuthenticationSuccessContext context) throws ServletException, IOException {
        String username = context.getUsername() != null ? context.getUsername() : context.getUser().getName();

        eventPublisher.publish(new AuthenticationSuccessEvent(this, username, context.getMethod()));

        for (HttpAuthenticationSuccessHandler handler : getHandlers()) {
            String handlerName = handler.getClass().getName();
            log.trace("onAuthenticationSuccess - delegating to {}", handlerName);
            if (handler.onAuthenticationSuccess(context)) {
                log.trace("onAuthenticationSuccess - {} handled authentication success", handlerName);
                return true;
            }
        }

        log.trace("onAuthenticationSuccess - none of the plugins handled authentication success");
        return false;
    }

    private Iterable<HttpAuthenticationSuccessHandler> getHandlers() {
        return ModuleDescriptorUtils.toSortedModules(
                pluginAccessor.getEnabledModuleDescriptorsByClass(HttpAuthenticationSuccessHandlerModuleDescriptor.class))
                .collect(toList());
    }

}
