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

import com.atlassian.bitbucket.mail.MailHostConfiguration;
import com.atlassian.bitbucket.mail.MailProtocol;
import com.atlassian.bitbucket.rest.mail.RestMailConfiguration;
import com.atlassian.bitbucket.test.DefaultFuncTestData;
import com.atlassian.bitbucket.test.MailServerConfigHelper;
import com.jayway.restassured.RestAssured;
import it.com.atlassian.stash.BaseRestTest;
import org.junit.Before;
import org.junit.Test;

import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
import static javax.ws.rs.core.Response.Status.OK;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
import static com.atlassian.bitbucket.test.MailServerConfigHelper.*;

public class MailServerResourceTest extends BaseRestTest {

    private static final String HOSTNAME = "smtp.example.server.com";
    private static final String HOSTNAME2 = "smtp2.example.server.com";
    private static final String PASSWORD = "mail-password";
    private static final Integer PORT = 456;
    private static final MailProtocol PROTOCOL = MailProtocol.SMTP;
    private static final boolean REQUIRE_TLS = true;
    private static final String SENDER_ADDRESS = "sender@example.com";
    private static final boolean USE_TLS = true;
    private static final String USERNAME = "mail-user";

    private static final MailHostConfiguration CONFIGURATION = new MailHostConfiguration.Builder()
            .hostname(HOSTNAME)
            .port(PORT)
            .protocol(PROTOCOL)
            .requireStartTls(REQUIRE_TLS)
            .useStartTls(USE_TLS)
            .username(USERNAME)
            .password(PASSWORD)
            .build();

    private static final MailHostConfiguration CONFIGURATION2 = new MailHostConfiguration.Builder(CONFIGURATION)
            .hostname(HOSTNAME2)
            .build();

    @Before
    public void clearMailConfig() {
        delete(URL_MAIL_CONFIG);
    }

    @Test
    public void testGetEmptyMailConfigReturns404() {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                .expect()
                    .statusCode(NOT_FOUND.getStatusCode())
                .when().get(URL_MAIL_CONFIG);
    }

    @Test
    public void testGetMailConfig() {
        MailServerConfigHelper.setConfig(CONFIGURATION, SENDER_ADDRESS);

        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                .expect().log().ifError()
                    .statusCode(OK.getStatusCode())
                    .body("hostname", equalTo(HOSTNAME))
                    .body("port", equalTo(PORT))
                    .body("protocol", equalTo(PROTOCOL.name()))
                    .body("require-start-tls", equalTo(REQUIRE_TLS))
                    .body("use-start-tls", equalTo(USE_TLS))
                    .body("username", equalTo(USERNAME))
                    .body("password", nullValue()) // password should never be returned
                    .body("sender-address", equalTo(SENDER_ADDRESS))
                .when().get(URL_MAIL_CONFIG);
    }

    @Test
    public void testPutMailConfig() {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                    .body(new RestMailConfiguration(CONFIGURATION, SENDER_ADDRESS)).contentType("application/json")
                .expect().log().ifError()
                    .statusCode(OK.getStatusCode())
                    .body("hostname", equalTo(HOSTNAME))
                    .body("port", equalTo(PORT))
                    .body("protocol", equalTo(PROTOCOL.name()))
                    .body("require-start-tls", equalTo(REQUIRE_TLS))
                    .body("use-start-tls", equalTo(USE_TLS))
                    .body("username", equalTo(USERNAME))
                    .body("password", nullValue()) // password should never be returned
                    .body("sender-address", equalTo(SENDER_ADDRESS))
                .when().put(URL_MAIL_CONFIG);

        // override an existing configuration - leaving out the SENDER_ADDRESS
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                    .body(new RestMailConfiguration(CONFIGURATION2, null)).contentType("application/json")
                .expect().log().ifError()
                    .statusCode(OK.getStatusCode())
                    .body("hostname", equalTo(HOSTNAME2))
                    .body("port", equalTo(PORT))
                    .body("protocol", equalTo(PROTOCOL.name()))
                    .body("require-start-tls", equalTo(REQUIRE_TLS))
                    .body("use-start-tls", equalTo(USE_TLS))
                    .body("username", equalTo(USERNAME))
                    .body("password", nullValue()) // password should never be returned
                    .body("sender-address", equalTo(SENDER_ADDRESS)) // sender address should not change
                .when().put(URL_MAIL_CONFIG);

        // override only the sender address in an existing configuration
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                    .body(new RestMailConfiguration(null, "changed@email.com")).contentType("application/json")
                .expect().log().ifError()
                .statusCode(OK.getStatusCode())
                    .body("hostname", equalTo(HOSTNAME2))
                    .body("port", equalTo(PORT))
                    .body("protocol", equalTo(PROTOCOL.name()))
                    .body("require-start-tls", equalTo(REQUIRE_TLS))
                    .body("use-start-tls", equalTo(USE_TLS))
                    .body("username", equalTo(USERNAME))
                    .body("password", nullValue()) // password should never be returned
                    .body("sender-address", equalTo("changed@email.com"))
                .when().put(URL_MAIL_CONFIG);
    }

    @Test
    public void testPutMailConfigMissingPort() {
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                    .body(new RestMailConfiguration(new MailHostConfiguration.Builder()
                            .hostname(HOSTNAME)
                            .username(USERNAME)
                            .password(PASSWORD)
                            .build(),
                            SENDER_ADDRESS)).contentType("application/json")
                .expect()
                    .statusCode(BAD_REQUEST.getStatusCode())
                    .body("errors[0].context", equalTo("port"))
                .when().put(URL_MAIL_CONFIG);
    }

    @Test
    public void testDeleteMailConfig() {
        MailServerConfigHelper.setConfig(CONFIGURATION);

        delete(URL_MAIL_CONFIG);

        // Verify that the mail config is cleared
        assert404(URL_MAIL_CONFIG);
    }

    @Test
    public void testServerEmailAddress() {
        // 404 when not set
        assert404(URL_MAIL_SENDER_ADDRESS);

        // Set it
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                    .body("sender@git.server.com").contentType("application/json")
                .expect()
                    .statusCode(OK.getStatusCode())
                    .body(equalTo("sender@git.server.com"))
                .when().put(URL_MAIL_SENDER_ADDRESS);

        // Verify that it is set
        RestAssured
                .given()
                    .auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword())
                .expect()
                    .statusCode(OK.getStatusCode())
                    .body(equalTo("sender@git.server.com"))
                .when().get(URL_MAIL_SENDER_ADDRESS);

        // Clear it again
        delete(URL_MAIL_SENDER_ADDRESS);

        // Verify that it 404s again
        assert404(URL_MAIL_SENDER_ADDRESS);
    }
}
