package it.com.atlassian.stash.rest.commit;

import com.atlassian.bitbucket.content.DiffSegmentType;
import com.atlassian.bitbucket.test.CommitCommentLikeHelper;
import com.atlassian.bitbucket.test.CommitCommentTestHelper;
import com.atlassian.bitbucket.test.DefaultFuncTestData;
import com.atlassian.bitbucket.test.RepositoryTestHelper;
import com.atlassian.bitbucket.test.rest.comment.RestCommentLikeUtils;
import com.atlassian.bitbucket.test.rest.commit.RestCommitHelper;
import com.atlassian.bitbucket.permission.Permission;
import com.google.common.collect.ImmutableList;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import static javax.ws.rs.core.Response.Status.*;
import static org.hamcrest.Matchers.equalTo;

public class CommitCommentLikeResourceTest extends BaseCommitCommentTest {

    private static final String COMMENT_AUTHOR = "comment_author";
    private static final String LIKER = "liker";
    private static final String NON_REPO_READ = "non_repo_read";

    private int commentId;
    private CommitCommentLikeHelper likeHelper;
    private CommitCommentTestHelper commitHelper;

    @BeforeClass
    public static void resetRepo() {
        // the base class makes this public but we don't want that
        RepositoryTestHelper.setRepositoryPublicAccessEnabled(CS_COMMENT_TEST, CS_COMMENT_TEST, false);
    }

    @Before
    public void createComment() {
        testContext
                .user(NON_REPO_READ)
                .user(COMMENT_AUTHOR).repositoryPermission(CS_COMMENT_TEST, CS_COMMENT_TEST, COMMENT_AUTHOR, Permission.REPO_READ)
                .user(LIKER).repositoryPermission(CS_COMMENT_TEST, CS_COMMENT_TEST, LIKER, Permission.REPO_READ);

        likeHelper = new CommitCommentLikeHelper(CS_COMMENT_TEST, CS_COMMENT_TEST, CS_ID);
        commitHelper = new CommitCommentTestHelper(CS_COMMENT_TEST, CS_COMMENT_TEST, CS_ID);
        commentId = commitHelper.addCommitComment("Test Comment", CS_FILE, 1, DiffSegmentType.CONTEXT,
                COMMENT_AUTHOR, COMMENT_AUTHOR);
    }

    @After
    public void cleanupComment() throws Exception {
        commitHelper.deleteCommitCommentAndWait(commentId, 0);
    }

    @Test
    public void testLike() {
        requestAs(LIKER)
                .when()
                    .post(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(NO_CONTENT.getStatusCode());

        requestAs(LIKER)
                .when()
                    .get(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(OK.getStatusCode())
                    .body("size", equalTo(1))
                    .body("values[0].slug", equalTo(LIKER));
    }

    @Test
    public void testUnlike() {
        likeHelper.likeComment(commentId, LIKER);

        requestAs(LIKER)
                .when()
                    .delete(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(NO_CONTENT.getStatusCode());

        requestAs(LIKER)
                .when()
                    .get(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(OK.getStatusCode())
                    .body("size", equalTo(0));
    }

    @Test
    public void testCommitDiffHasLikedByProperty() {
        likeHelper.likeComment(commentId, LIKER);

        requestAs(LIKER)
                .when()
                    .get(RestCommitHelper.getDiffUrl(CS_COMMENT_TEST, CS_COMMENT_TEST, CS_ID, CS_FILE))
                .then()
                    .log().ifValidationFails()
                    .specification(RestCommentLikeUtils.expectLikedBy("diffs[0].lineComments[0]", ImmutableList.of(LIKER)))
                    .statusCode(OK.getStatusCode());
    }

    @Test
    public void testGetLikesAsAnonymous() {
        likeHelper.likeComment(commentId, LIKER);

        requestAsAnon()
                .when()
                    .get(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(UNAUTHORIZED.getStatusCode());
    }

    @Test
    public void testLikeAsAnonymous() {
        requestAsAnon()
                .when()
                    .post(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(UNAUTHORIZED.getStatusCode());
    }

    @Test
    public void testGetLikesOfDeletedComment() throws Exception {
        likeHelper.likeComment(commentId, LIKER);
        commitHelper.deleteCommitCommentAndWait(commentId, 0);

        requestAs(LIKER)
                .when()
                    .get(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(NOT_FOUND.getStatusCode());
    }

    @Test
    public void testLikingLikedComment() {
        likeHelper.likeComment(commentId, LIKER);

        requestAs(LIKER)
                .when()
                .post(getLikesEndpoint())
                .then()
                .log().ifValidationFails()
                .statusCode(NO_CONTENT.getStatusCode());
    }

    @Test
    public void testUnlikingUnlikedComment() {
        requestAs(LIKER)
                .when()
                    .delete(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(NO_CONTENT.getStatusCode());
    }

    @Test
    public void testLikeAsUserWithNoRepoRead() {
        requestAs(NON_REPO_READ)
                .when()
                     .post(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(UNAUTHORIZED.getStatusCode());
    }

    @Test
    public void testGetLikersAsUserWithNoRepoRead() {
        likeHelper.likeComment(commentId, LIKER);

        requestAs(NON_REPO_READ)
                .when()
                    .get(getLikesEndpoint())
                .then()
                    .log().ifValidationFails()
                    .statusCode(UNAUTHORIZED.getStatusCode());
    }

    public static RequestSpecification requestAs(String username) {
        return requestAs(username, username);
    }

    public static RequestSpecification requestAs(String username, String password) {
        return RestAssured.given().auth().preemptive().basic(username, password).contentType(ContentType.JSON);
    }

    public static RequestSpecification requestAsAnon() {
        return RestAssured.given().contentType(ContentType.JSON);
    }

    public String getLikesEndpoint() {
        return getLikesEndpoint(commentId);
    }

    public String getLikesEndpoint(long commentId) {
        return DefaultFuncTestData.getRestURL("comment-likes", "latest") +
                "/projects/" + CS_COMMENT_TEST + "/repos/" + CS_COMMENT_TEST +
                "/commits/" + CS_ID + "/comments/" + commentId + "/likes";
    }
}
