package com.atlassian.stash.internal.scm.git.rest;

import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.repository.Tag;
import com.atlassian.bitbucket.rest.RestErrors;
import com.atlassian.bitbucket.rest.RestResource;
import com.atlassian.bitbucket.rest.repository.RestTag;
import com.atlassian.bitbucket.rest.util.ResourcePatterns;
import com.atlassian.bitbucket.rest.util.ResponseFactory;
import com.atlassian.bitbucket.rest.util.RestUtils;
import com.atlassian.bitbucket.scm.git.command.tag.GitTagType;
import com.atlassian.bitbucket.scm.git.ref.GitCreateTagCommandParameters;
import com.atlassian.bitbucket.scm.git.ref.GitDeleteTagCommandParameters;
import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
import com.atlassian.stash.internal.scm.git.ref.GitRefService;
import com.sun.jersey.spi.resource.Singleton;
import org.apache.commons.lang3.StringUtils;

import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import static javax.ws.rs.core.Response.Status.BAD_REQUEST;

@AnonymousAllowed
@Consumes({MediaType.APPLICATION_JSON})
@Path(ResourcePatterns.REPOSITORY_URI + "/tags")
@Produces({RestUtils.APPLICATION_JSON_UTF8})
@Singleton
public class GitTagResource extends RestResource {

    private final GitRefService gitRefService;

    public GitTagResource(GitRefService gitRefService, I18nService i18nService) {
        super(i18nService);
        this.gitRefService = gitRefService;
    }

    /**
     * Creates a tag in the specified repository.
     * <p>
     * The authenticated user must have an effective <strong>REPO_WRITE</strong> permission to call this resource.
     * <p>
     * 'LIGHTWEIGHT' and 'ANNOTATED' are the two type of tags that can be created. The 'startPoint' can either be a ref
     *  or a 'commit'.
     *
     * @param repository the repository to create the tag in
     * @param request the {@link RestGitTagCreateRequest request} containing the details of the tag to create
     *
     * @request.representation.example {@link RestGitTagCreateRequest#ANNOTATED_EXAMPLE}
     *
     * @response.representation.201.doc a JSON representation of the newly created tag
     * @response.representation.201.mediaType application/json
     * @response.representation.201.example {@link RestTag#EXAMPLE}
     *
     * @response.representation.400.doc the tag was not created because the request was invalid, e.g. the provided
     *                                  ref name already existed in the repository, or was not a valid ref name in the
     *                                  repository, or the start point is invalid
     * @response.representation.400.mediaType application/json
     * @response.representation.400.qname errors
     * @response.representation.400.example {@link RestErrors#EXAMPLE}
     *
     * @response.representation.403.doc The currently authenticated user has insufficient permissions to create a
     *                                  tag. This could be due to insufficient repository permissions.
     *
     * @response.representation.403.mediaType application/json
     * @response.representation.403.qname errors
     * @response.representation.403.example {@link RestErrors#EXAMPLE}
     */
    @POST
    public Response createTag(@Context Repository repository, RestGitTagCreateRequest request) {
        if (StringUtils.isBlank(request.getName())) {
            return ResponseFactory
                    .errors(BAD_REQUEST, new RestErrors(i18nService.getMessage("bitbucket.git.rest.tag.emptyname")))
                    .build();
        }
        if (StringUtils.isBlank(request.getStartPoint())) {
            return ResponseFactory
                    .errors(BAD_REQUEST, new RestErrors(i18nService.getMessage("bitbucket.git.rest.tag.emptystartpoint")))
                    .build();
        }

       Tag tag = gitRefService.createTag(repository, createParameters(request));
       return ResponseFactory.status(Response.Status.CREATED)
               .entity(new RestTag(tag))
               .build();
    }

    /**
     * Deletes a tag in the specified repository.
     * <p>
     * The authenticated user must have an effective <strong>REPO_WRITE</strong> permission to call this resource.
     *
     * @param repository the repository to delete the tag in
     * @param name the name of the tag to be deleted
     *
     *
     * @response.representation.204.doc an empty response indicating that the tag no longer exists in the repository
     *
     * @response.representation.400.doc the tag was not deleted because repository is either empty,
     *                                  or is not a git repository
     *
     * @response.representation.400.mediaType application/json
     * @response.representation.400.qname errors
     * @response.representation.400.example {@link RestErrors#EXAMPLE}
     *
     * @response.representation.403.doc The currently authenticated user has insufficient permissions to delete a
     *                                  tag. This could be due to insufficient repository permissions.
     *
     * @response.representation.403.mediaType application/json
     * @response.representation.403.qname errors
     * @response.representation.403.example {@link RestErrors#EXAMPLE}
     *
     * @response.representation.404.doc  If the tag doesn't exist in the {@link Repository}
     *
     * @response.representation.404.mediaType application/json
     * @response.representation.404.qname errors
     * @response.representation.404.example {@link RestErrors#EXAMPLE}
     */
    @DELETE
    @Path("{name:.*}")
    public Response deleteTag(@Context Repository repository, @PathParam("name") String name) {
        GitDeleteTagCommandParameters parameters = new GitDeleteTagCommandParameters.Builder()
                .name(name)
                .build();

        gitRefService.deleteTag(repository, parameters);
        return ResponseFactory.noContent().build();
    }

    private GitCreateTagCommandParameters createParameters(RestGitTagCreateRequest request) {
        GitCreateTagCommandParameters.Builder builder = new GitCreateTagCommandParameters.Builder();

        GitTagType type = request.getType();
        if (type != null) {
            builder.type(type);
        }

        return builder.name(request.getName())
                .force(request.isForce())
                .startPoint(request.getStartPoint())
                .message(request.getMessage())
                .build();
    }
}
