package com.atlassian.stash.internal.auth;

import com.atlassian.bitbucket.env.SystemProperties;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.WebAttributes;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Component("authenticationHelper")
public class DefaultAuthenticationHelper implements AuthenticationHelper {

    /**
     * Attribute set on a {@code HttpSession} containing the username cached between requests,
     * captured during signup or failed login, which allows pre-population of the username in
     * login forms.
     */
    static final String ATTR_CACHED_USERNAME = SystemProperties.PROP_PREFIX + ".cached-username";

    @Override
    public AuthenticationException getAuthenticationException(@Nonnull HttpServletRequest request) {
        return (AuthenticationException) getAttribute(request, WebAttributes.AUTHENTICATION_EXCEPTION);
    }

    @Override
    public String getCachedUsername(@Nonnull HttpServletRequest request) {
        return (String) getAttribute(request, ATTR_CACHED_USERNAME);
    }

    @Override
    public boolean isAuthenticationFailed(@Nonnull HttpServletRequest request) {
        Object attribute = getAttribute(request, WebAttributes.AUTHENTICATION_EXCEPTION);

        return attribute != null;
    }

    @Override
    public void setAuthenticationException(@Nonnull HttpServletRequest request, AuthenticationException e) {
        setAttribute(request, WebAttributes.AUTHENTICATION_EXCEPTION, e);
    }

    @Override
    public void setCachedUsername(@Nonnull HttpServletRequest request, String username) {
        //isBlank(username) is used over, say, trimToNull(username) to not damage usernames with whitespace
        setAttribute(request, ATTR_CACHED_USERNAME, StringUtils.isBlank(username) ? null : username);
    }

    private static Object getAttribute(HttpServletRequest request, String name) {
        HttpSession session = request.getSession(false);

        //Prefer to load the attribute from the session, if one exists
        Object value = session == null ? null : session.getAttribute(name);
        if (value == null) {
            //If there is no session, or the attribute is not set, load it from the request
            value = request.getAttribute(name);
        }
        return value;
    }

    private static void setAttribute(HttpServletRequest request, String name, Object value) {
        HttpSession session = request.getSession(false);
        if (value == null) {
            if (session != null) {
                session.removeAttribute(name);
            }
            request.removeAttribute(name);
        } else {
            if (session != null) {
                session.setAttribute(name, value);
            }
            //Always set the attribute on the request so it will be available even if the session is
            //invalidated before the request ends
            request.setAttribute(name, value);
        }
    }
}
