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

import com.atlassian.bitbucket.pull.*;
import com.atlassian.bitbucket.rest.RestResource;
import com.atlassian.bitbucket.rest.BadRequestException;
import com.atlassian.bitbucket.rest.util.ResponseFactory;
import com.atlassian.bitbucket.rest.util.RestUtils;
import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.rest.util.RestPage;
import com.atlassian.bitbucket.rest.pull.RestPullRequest;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.bitbucket.permission.PermissionValidationService;
import com.atlassian.bitbucket.auth.AuthenticationContext;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;
import com.atlassian.bitbucket.util.PageRequestImpl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.sun.jersey.spi.resource.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Arrays;
import java.util.Map;

@AnonymousAllowed
@Consumes({MediaType.APPLICATION_JSON})
@Path("/inbox")
@Produces({RestUtils.APPLICATION_JSON_UTF8})
@Singleton
@SuppressWarnings("ConstantConditions")
public class InboxResource extends RestResource {

    private static final Logger log = LoggerFactory.getLogger(InboxResource.class);

    private final AuthenticationContext authenticationContext;
    private final PermissionValidationService permissionValidationService;
    private final PullRequestService pullRequestService;

    public InboxResource(I18nService i18nService, AuthenticationContext authenticationContext,
                         PermissionValidationService permissionValidationService,
                         PullRequestService pullRequestService) {
        super(i18nService);
        this.authenticationContext = authenticationContext;
        this.permissionValidationService = permissionValidationService;
        this.pullRequestService = pullRequestService;
    }

    @GET
    @Path(value = "pull-requests")
    public Response getPullRequests(@QueryParam("start") @DefaultValue(RestUtils.DEFAULT_START) int start,
                                    @QueryParam("limit") @DefaultValue(RestUtils.DEFAULT_LIMIT) int limit,
                                    @QueryParam("role") @DefaultValue("reviewer") String role) {
        permissionValidationService.validateAuthenticated();

        ApplicationUser currentUser = authenticationContext.getCurrentUser();
        log.debug("Retrieving pull requests for user {}", currentUser.getDisplayName());

        PageRequest pageRequest = new PageRequestImpl(start, limit);

        Page<PullRequest> pullRequestPage = pullRequestService.search(new PullRequestSearchRequest.Builder()
                .order(PullRequestOrder.PARTICIPANT_STATUS)
                .participant(new PullRequestParticipantRequest.Builder(currentUser.getName())
                        .role(parseRole(role))
                        .statuses(ImmutableList.of(PullRequestParticipantStatus.UNAPPROVED,
                                PullRequestParticipantStatus.NEEDS_WORK))
                        .build())
                .state(PullRequestState.OPEN).build(), pageRequest);

        return ResponseFactory.ok(
                new RestPage<>(pullRequestPage, RestPullRequest.REST_TRANSFORM)
        ).build();
    }

    @GET
    @Path(value = "pull-requests/count")
    public Response getPullRequestCount() {
        permissionValidationService.validateAuthenticated();

        ApplicationUser currentUser = authenticationContext.getCurrentUser();
        log.debug("Retrieving pull request count for user {}", currentUser.getDisplayName());

        long count = pullRequestService.count(new PullRequestSearchRequest.Builder()
                .participant(new PullRequestParticipantRequest.Builder(currentUser.getName())
                        .role(PullRequestRole.REVIEWER)
                        .status(PullRequestParticipantStatus.UNAPPROVED)
                        .build())
                .state(PullRequestState.OPEN).build());

        Map<String, Long> response = Maps.newHashMap();
        response.put("count", count);

        return ResponseFactory.ok(response).build();
    }

    private PullRequestRole parseRole(String role) {
        try {
            return PullRequestRole.valueOf(role.toUpperCase());
        } catch (IllegalArgumentException e) {
            throw new BadRequestException(
                    i18nService.getText("bitbucket.rest.inbox.role.invalid", null, role, Arrays.asList(PullRequestRole.values()))
            );
        }
    }
}
