package com.atlassian.bitbucket.internal.mirroring.upstream.rest.auth;

import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.internal.mirroring.rest.auth.RestApplicationUserWithPermissions;
import com.atlassian.bitbucket.internal.mirroring.rest.auth.RestAuthenticationRequest;
import com.atlassian.bitbucket.internal.mirroring.upstream.auth.AuthenticationService;
import com.atlassian.bitbucket.internal.mirroring.user.ApplicationUserWithPermissions;
import com.atlassian.bitbucket.permission.EffectivePermission;
import com.atlassian.bitbucket.rest.util.ResponseFactory;
import com.atlassian.bitbucket.rest.util.RestUtils;
import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
import com.sun.jersey.spi.resource.Singleton;

import javax.validation.Validator;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import static com.atlassian.bitbucket.util.ValidationUtils.validate;

@Consumes({MediaType.APPLICATION_JSON})
@Produces({RestUtils.APPLICATION_JSON_UTF8})
@Singleton
@AnonymousAllowed
@Path("authenticate")
public class AuthenticationResource {
    private final AuthenticationService authenticationService;
    private final I18nService i18nService;
    private final Validator validator;

    public AuthenticationResource(AuthenticationService authenticationService, I18nService i18nService, Validator validator) {
        this.authenticationService = authenticationService;
        this.i18nService = i18nService;
        this.validator = validator;
    }

    /**
     * Authenticates on behalf of a user. Used by mirrors to check the credentials supplied to them by users.
     * If successful a user and their {@link EffectivePermission effective permissions} are
     * returned. Currently only username/password and SSH credentials are supported.
     *
     * @param authRequest the authentication request which supplies the credentials
     *
     * @request.representation.mediaType application/json
     * @request.representation.example {@link RestAuthenticationRequest#EXAMPLE_USERNAME_AND_PASSWORD_REQUEST}
     * @request.representation.example {@link RestAuthenticationRequest#EXAMPLE_SSH_REQUEST}
     *
     * @response.representation.200.mediaType application/json
     * @response.representation.200.qname user
     * @response.representation.200.example {@link RestApplicationUserWithPermissions#RESPONSE_EXAMPLE}
     * @response.representation.200.doc The user for the supplied credentials and their {@link EffectivePermission effective permissions}.
     *
     * @response.representation.401.mediaType application/json
     * @response.representation.401.qname errors
     * @response.representation.401.example {@link com.atlassian.bitbucket.rest.RestErrors#EXAMPLE}
     * @response.representation.401.doc The currently authenticated user is not permitted
     *                                  to authenticate on behalf of users or authentication with the
     *                                  supplied user credentials failed for some reason
     *
     * @response.representation.400.mediaType application/json
     * @response.representation.400.qname errors
     * @response.representation.400.example {@link com.atlassian.bitbucket.rest.RestErrors#EXAMPLE}
     * @response.representation.400.doc If the supplied credentials are incomplete or not understood.
     */
    @POST
    public Response authenticate(RestAuthenticationRequest authRequest) {
        ApplicationUserWithPermissions user = authenticationService.authenticateForUser(validate(validator, authRequest).getCredentials());

        if (user == null) {
            return ResponseFactory.error(Response.Status.UNAUTHORIZED, "credentials", i18nService.getMessage("bitbucket.mirroring.authentication.delegation.failed")).build();
        }

        return ResponseFactory.ok(RestApplicationUserWithPermissions.REST_TRANSFORM.apply(user)).build();
    }

}