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

import com.atlassian.bitbucket.repository.*;
import com.atlassian.bitbucket.rest.RestErrors;
import com.atlassian.bitbucket.rest.repository.RestMinimalRef;
import com.atlassian.bitbucket.rest.repository.RestTag;
import com.atlassian.bitbucket.rest.util.RestPage;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;
import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
import com.sun.jersey.spi.resource.Singleton;

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

import static com.atlassian.bitbucket.rest.util.ResourcePatterns.REPOSITORY_URI;

@Path(REPOSITORY_URI + "/tags")
@Singleton
@AnonymousAllowed
public class TagResource extends AbstractRepositoryRefResource {

    public TagResource(RefService refService) {
        super(refService);
    }

    /**
     * Retrieve the tags matching the supplied <strong>filterText</strong> param.
     * <p>
     * The authenticated user must have <strong>REPO_READ</strong> permission for the context repository to call this
     * resource.
     *
     * @param repository created by the ResourceContextInterceptor from the URL
     * @param filterText the text to match on
     * @param orderBy ordering of refs either ALPHABETICAL (by name) or MODIFICATION (last updated)
     *
     * @response.representation.200.mediaType application/json
     * @response.representation.200.qname page
     * @response.representation.200.example {@link RestTag#PAGE_EXAMPLE}
     * @response.representation.200.doc The tags matching the supplied <strong>filterText</strong>.
     *
     * @response.representation.401.mediaType application/json
     * @response.representation.401.qname errors
     * @response.representation.401.example {@link RestErrors#EXAMPLE}
     * @response.representation.401.doc The currently authenticated user has insufficient permissions to read the
     * repository.
     *
     * @response.representation.404.mediaType application/json
     * @response.representation.404.qname errors
     * @response.representation.404.example {@link RestErrors#EXAMPLE}
     * @response.representation.404.doc  The specified repository does not exist.
     */
    @GET
    public Response getTags(@Context Repository repository,
                            @Context final PageRequest pageRequest,
                            @QueryParam("filterText") final String filterText,
                            @QueryParam("orderBy") final String orderBy) {

        return process(repository, (repo, refService) -> {
            Page<Tag> tags = refService.getTags(new RepositoryTagsRequest.Builder(repository)
                    .filterText(filterText)
                    .order(RefOrder.fromValueOrNull(orderBy))
                    .build(), pageRequest);

            return new RestPage<>(tags, RestMinimalRef.REST_TRANSFORM);
        });
    }

    /**
     * Retrieve a tag in the specified repository.
     * <p>
     * The authenticated user must have <strong>REPO_READ</strong> permission for the context repository to call this
     * resource.
     *
     * @param repository created by the ResourceContextInterceptor from the URL
     * @param name the name of the tag to be retrieved
     *
     * @response.representation.200.mediaType application/json
     * @response.representation.200.qname tag
     * @response.representation.200.example {@link RestTag#EXAMPLE}
     * @response.representation.200.doc The tag which matches the supplied <strong>name</strong>.
     *
     * @response.representation.401.mediaType application/json
     * @response.representation.401.qname errors
     * @response.representation.401.example {@link RestErrors#EXAMPLE}
     * @response.representation.401.doc The currently authenticated user has insufficient permissions to read the
     * repository.
     *
     * @response.representation.404.mediaType application/json
     * @response.representation.404.qname errors
     * @response.representation.404.example {@link RestErrors#EXAMPLE}
     * @response.representation.404.doc  The specified tag does not exist.
     */
    @GET
    @Path("{name:.*}")
    public Response getTag(@Context Repository repository,
                           @PathParam("name") String name) {

        return process(repository, (repo, refService) -> {
            ResolveRefRequest request = new ResolveRefRequest.Builder(repository)
                    .refId(name)
                    .type(StandardRefType.TAG)
                    .build();

            return RestMinimalRef.REST_TRANSFORM.apply(refService.resolveRef(request));
        });
    }

    /**
     * Creates a tag using the information provided in the {@link RestCreateTagRequest request}
     * <p>
     * The authenticated user must have <strong>REPO_WRITE</strong> permission for the context repository to call this
     * resource.
     *
     * @param repository created by the ResourceContextInterceptor from the URL. The repository in which the tag will be
     *                   created
     * @param restRequest the request to create a tag containing a <strong>name</strong>, <strong>startPoint</strong>,
     *                    and optionally a <strong>message</strong>
     *
     * @request.representation.example {@link RestCreateTagRequest#EXAMPLE}
     *
     * @response.representation.200.mediaType application/json
     * @response.representation.200.qname tag
     * @response.representation.200.example {@link RestTag#EXAMPLE}
     * @response.representation.200.doc The created tag
     *
     * @response.representation.401.mediaType application/json
     * @response.representation.401.qname errors
     * @response.representation.401.example {@link RestErrors#EXAMPLE}
     * @response.representation.401.doc The currently authenticated user has insufficient permissions to write to the
     * repository.
     *
     * @response.representation.404.mediaType application/json
     * @response.representation.404.qname errors
     * @response.representation.404.example {@link RestErrors#EXAMPLE}
     * @response.representation.404.doc  The specified repository does not exist.
     */
    @POST
    public Response createTag(@Context Repository repository, final RestCreateTagRequest restRequest) {
        return process(repository, (repo, refService) ->
                new RestTag(refService.createTag(new CreateTagRequest.Builder(repo, restRequest.getName(), restRequest.getStartPoint())
                        .message(restRequest.getMessage())
                        .build())));
    }
}
