package it.com.atlassian.stash.notification;

import com.atlassian.bitbucket.rest.RestMapEntity;
import com.atlassian.bitbucket.test.DefaultFuncTestData;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.http.ContentType;

import it.com.atlassian.stash.BaseRestTest;
import org.junit.Before;
import org.junit.Test;

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

public class UserNotificationSettingsResourceTest extends BaseRestTest {

    private static final String SEND_MODE_KEY = "sendMode";
    private static final String SEND_MODE_BATCHED = "BATCHED";
    private static final String SEND_MODE_IMMEDIATE = "IMMEDIATE";

    @Before
    public void setUp() throws Exception {
        // I know we actually test this below as well, so it would fail early, but settings persist when a user is deleted
        // so we need to set to a known value before each test
        setSendModeForUser(DefaultFuncTestData.getAdminUser(), SEND_MODE_IMMEDIATE);
        setSendModeForUser(DefaultFuncTestData.getRegularUser(), SEND_MODE_BATCHED);
    }

    @Test
    public void testGetSettingsForCurrentUser() throws Exception {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getRegularUser(), DefaultFuncTestData.getRegularUserPassword())
                .when()
                    .get(getResourceUrl())
                .then()
                    .log().ifValidationFails()
                    .body(SEND_MODE_KEY, equalTo(SEND_MODE_BATCHED))
                    .statusCode(OK.getStatusCode());
    }

    @Test
    public void testGetSettingsForDifferentUserAsNonAdmin() throws Exception {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getRegularUser(), DefaultFuncTestData.getRegularUserPassword())
                .when()
                    .get(getResourceUrl() + "/" + DefaultFuncTestData.getAdminUser())
                .then()
                    .log().ifValidationFails()
                    .body(SEND_MODE_KEY, equalTo(SEND_MODE_IMMEDIATE))
                    .statusCode(OK.getStatusCode());
    }

    @Test
    public void testGetSettingsForDifferentUserAsAdmin() throws Exception {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                .when()
                    .get(getResourceUrl() + "/" + DefaultFuncTestData.getRegularUser())
                .then()
                    .log().ifValidationFails()
                    .body(SEND_MODE_KEY, equalTo(SEND_MODE_BATCHED))
                    .statusCode(OK.getStatusCode());
    }

    @Test
    public void testUpdateSettingsForCurrentUser() throws Exception {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getRegularUser(), DefaultFuncTestData.getRegularUserPassword())
                    .contentType(ContentType.JSON)
                    .body(getUserNotificationSettings(SEND_MODE_IMMEDIATE))
                .when()
                    .put(getResourceUrl())
                .then()
                    .log().ifValidationFails()
                    .statusCode(NO_CONTENT.getStatusCode());
    }

    @Test
    public void testUpdateSettingsForDifferentUserAsAdmin() throws Exception {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                    .contentType(ContentType.JSON)
                    .body(getUserNotificationSettings(SEND_MODE_IMMEDIATE))
                .when()
                    .put(getResourceUrl())
                .then()
                    .log().ifValidationFails()
                    .statusCode(NO_CONTENT.getStatusCode());
    }

    @Test
    public void testUpdateSettingsForDifferentUserAsNonAdmin() throws Exception {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getRegularUser(), DefaultFuncTestData.getRegularUserPassword())
                    .contentType(ContentType.JSON)
                    .body(getUserNotificationSettings(SEND_MODE_IMMEDIATE))
                .when()
                    .put(getResourceUrl() + "/admin")
                .then()
                    .log().ifValidationFails()
                    .statusCode(FORBIDDEN.getStatusCode());
    }

    private void setSendModeForUser(String userSlug, String sendMode) {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                    .contentType(ContentType.JSON)
                    .body(getUserNotificationSettings(sendMode))
                .when()
                    .put(getResourceUrl() + "/" + userSlug)
                .then()
                    .log().ifValidationFails()
                    .statusCode(NO_CONTENT.getStatusCode());
    }

    private RestUserNotificationSettings getUserNotificationSettings(String sendMode) {
        return new RestUserNotificationSettings(sendMode);
    }

    private String getResourceUrl() {
        return DefaultFuncTestData.getRestURL("notification", "latest") + "/settings";
    }

    private class RestUserNotificationSettings extends RestMapEntity {
        public RestUserNotificationSettings(String sendMode) {
            put(SEND_MODE_KEY, sendMode);
        }
    }
}
