package com.atlassian.stash.internal.rest.auth;

import com.atlassian.bitbucket.Product;
import com.atlassian.bitbucket.auth.HttpAuthenticationContext;
import com.atlassian.bitbucket.auth.HttpAuthenticationFailureContext;
import com.atlassian.bitbucket.auth.HttpAuthenticationFailureHandler;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.json.JsonRenderer;
import com.atlassian.bitbucket.nav.NavBuilder;
import com.atlassian.bitbucket.rest.RestErrorMessage;
import com.atlassian.bitbucket.rest.RestErrors;
import com.atlassian.bitbucket.rest.util.RestUtils;
import com.atlassian.bitbucket.server.ApplicationMode;
import com.atlassian.bitbucket.server.ApplicationModeSupplier;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;

import static com.atlassian.bitbucket.scm.http.HttpScmRequest.BITBUCKET_REALM;

public class RestAuthenticationFailureHandler implements HttpAuthenticationFailureHandler {

    public static final String REST_PATH_PREFIX = "/rest/";

    private final I18nService i18nService;
    private final NavBuilder navBuilder;
    private final JsonRenderer jsonRenderer;
    private final ApplicationModeSupplier modeSupplier;

    public RestAuthenticationFailureHandler(ApplicationModeSupplier modeSupplier,
                                            I18nService i18nService, NavBuilder navBuilder, JsonRenderer jsonRenderer) {
        this.modeSupplier = modeSupplier;
        this.i18nService = i18nService;
        this.navBuilder = navBuilder;
        this.jsonRenderer = jsonRenderer;
    }

    @Override
    public boolean onAuthenticationFailure(@Nonnull HttpAuthenticationFailureContext context) throws IOException {
        HttpServletRequest request = context.getRequest();

        if (!request.getServletPath().startsWith(REST_PATH_PREFIX)) {
            return false;
        }

        String message;

        switch (context.getAuthenticationState()) {
            case CAPTCHA_REQUIRED:
                if (modeSupplier.getMode() == ApplicationMode.MIRROR) {
                    message = i18nService.getMessage("bitbucket.rest.auth.captcha.required.upstream", Product.NAME);
                } else {
                    message = i18nService.getMessage("bitbucket.rest.auth.captcha.required", Product.NAME, navBuilder.buildAbsolute());
                }
                break;

            case UNLICENSED:
                message = i18nService.getMessage("bitbucket.rest.auth.unlicensed", Product.NAME);
                break;

            default:
                message = i18nService.getMessage("bitbucket.rest.auth.failed");
                break;
        }

        HttpServletResponse response = context.getResponse();

        response.setStatus(401);
        if (HttpAuthenticationContext.METHOD_BASIC.equals(context.getMethod())) {
            response.setHeader("WWW-Authenticate", "Basic realm=\"" + BITBUCKET_REALM + "\"");
        }
        response.setContentType(RestUtils.APPLICATION_JSON_UTF8);

        RestErrors errors = new RestErrors(new RestErrorMessage(
                null, message, context.getAuthenticationException().getClass().getName()));
        response.getWriter().write(jsonRenderer.render(errors, Collections.<String, Object>emptyMap()));

        return true;
    }
}
