package it.com.atlassian.stash;

import com.atlassian.bitbucket.test.DefaultFuncTestData;
import com.atlassian.bitbucket.test.PullRequestTestHelper;
import com.atlassian.webdriver.bitbucket.page.PullRequestOverviewPage;
import com.atlassian.webdriver.bitbucket.page.PullRequestRepositorySettingsPage;
import com.jayway.restassured.RestAssured;
import it.com.atlassian.stash.pull.BasePullRequestFuncTest;
import org.junit.Before;
import org.junit.Test;

import static com.jayway.restassured.http.ContentType.JSON;
import static javax.ws.rs.core.Response.Status.NO_CONTENT;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

/**
 * Tests for the AllApproversMergeCheck
 */
public class RequireAllApproversPullRequestMergeCheckTest extends BasePullRequestFuncTest {

    private PullRequestTestHelper pullRequest;
    private PullRequestOverviewPage pullRequestPage;

    @Before
    public void setup() throws Exception {
        pullRequest = createPullRequest(new PullRequestBuilder(
                BRANCH_THAT_DIFFER_BY_ONE_FILE_SRC, MASTER)
                .reviewer(DefaultFuncTestData.getAdminUser())
                .build());
    }

    @Test
    public void testShouldNotAllowMergingWithUnapprovedReviewers() {
        turnOnSettingAndVerifyVeto();
    }

    @Test
    public void testShouldAllowMergingWithUnapprovedReviewersWhenMergeCheckIsDisabled() {
        setRequireAllApprovals(false);
        goToPullRequest();
        assertThat(isMergeVetoPresent(), equalTo(false));
    }

    @Test
    public void testShouldAllowMergingWithNoUnapprovedReviewers() {
        turnOnSettingAndVerifyVeto();

        goToPullRequest();
        pullRequestPage.getApproveButton().clickButton();
        assertThat(isMergeVetoPresent(), equalTo(false));
    }

    @Test
    public void testShouldUpdateMergeStatusWhenReviewerChangesStatus() {
        turnOnSettingAndVerifyVeto();

        goToPullRequest();
        pullRequestPage.getApproveButton().clickButton();
        assertThat(isMergeVetoPresent(), equalTo(false));

        goToPullRequest();
        pullRequestPage.getNeedsWorkButton().clickButton();
        assertThat(isMergeVetoPresent(), equalTo(true));
    }

    @Test
    public void testShouldUpdateMergeStatusWhenReviewerIsAdded() {
        turnOnSettingAndVerifyVeto();

        pullRequestPage.getApproveButton().clickButton();
        assertThat(isMergeVetoPresent(), equalTo(false));

        pullRequest.addReviewers(REVIEWER_2);
        goToPullRequest();
        assertThat(isMergeVetoPresent(), equalTo(true));

        logInAndGoToPullRequest(REVIEWER_2);
        pullRequestPage.getApproveButton().clickButton();

        logInAndGoToPullRequest(DefaultFuncTestData.getAdminUser());
        assertThat(isMergeVetoPresent(), equalTo(false));
    }

    @Test
    public void testShouldUpdateMergeStatusWhenReviewerIsRemoved() {
        turnOnSettingAndVerifyVeto();

        pullRequestPage.getApproveButton().clickButton();
        assertThat(isMergeVetoPresent(), equalTo(false));

        pullRequest.addReviewers(REVIEWER_2);
        goToPullRequest();
        assertThat(isMergeVetoPresent(), equalTo(true));

        removeReviewer(REVIEWER_2);
        goToPullRequest();
        assertThat(isMergeVetoPresent(), equalTo(false));
    }

    private void goToPullRequest() {
        pullRequestPage = BITBUCKET.visit(PullRequestOverviewPage.class, PROJECT_KEY, REPO_SLUG, pullRequest.getId());
    }

    private void logInAndGoToPullRequest(String username) {
        pullRequestPage = loginAs(username, username, PullRequestOverviewPage.class, PROJECT_KEY, REPO_SLUG, pullRequest.getId());
    }

    private boolean isMergeVetoPresent() {
        return pullRequestPage.openMergeInlineWarnings()
                .map(dialog -> dialog.getWarnings()
                        .stream()
                        .filter(warning -> warning.equals("All reviewers must approve the pull request before it can be merged."))
                        .findFirst()
                        .isPresent())
                .orElse(false);
    }

    private void removeReviewer(String username) {
        RestAssured.given()
                .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                .expect().statusCode(NO_CONTENT.getStatusCode())
                .contentType(JSON)
                .when().delete(pullRequest.getDeleteParticipantsUrl(username))
                .getBody().jsonPath();
    }

    private void setRequireAllApprovals(boolean requireAllApprovals) {
        PullRequestRepositorySettingsPage settings = loginAsAdmin(PullRequestRepositorySettingsPage.class, PROJECT_KEY, REPO_SLUG);
        settings.setRequireAllApprovals(requireAllApprovals);
        settings.clickSave();
    }

    private void turnOnSettingAndVerifyVeto() {
        setRequireAllApprovals(true);
        goToPullRequest();
        assertThat(isMergeVetoPresent(), equalTo(true));
    }
}
