package it.com.atlassian.stash.admin;

import com.atlassian.webdriver.bitbucket.element.TimeZoneSelector;
import com.atlassian.webdriver.bitbucket.page.admin.AdminHomePage;
import com.atlassian.webdriver.bitbucket.page.admin.ServerSettingsPage;
import it.com.atlassian.stash.BaseBrowserFuncTest;
import it.com.atlassian.stash.TimeZoneTestHelper;
import org.junit.Test;

import java.time.ZoneId;
import java.util.Arrays;
import java.util.Locale;
import java.util.Optional;

import static com.atlassian.bitbucket.hamcrest.OptionalMatcher.empty;
import static com.atlassian.bitbucket.hamcrest.OptionalMatcher.some;
import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.*;

public final class ServerSettingsTest extends BaseBrowserFuncTest {

    @Test
    public void testUpdateConfig() {
        ServerSettingsPage serverSettings = loginAsAdmin(AdminHomePage.class).gotoServerSettingsPage();

        final String[] valuesPriorToTest = saveValues(serverSettings);
        try {
            final ServerSettingsPage page = serverSettings.setApplicationTitle("Cav test")
                    .setBaseUrl("http://localhost/stash")
                    .clickSave();
            assertThat(page.getAuiSuccessMessages(), hasItem("The server settings were updated"));
        } finally {
            restoreValues(serverSettings, valuesPriorToTest);
        }
    }

    @Test
    public void testCancel() {
        ServerSettingsPage serverSettings = loginAsAdmin(AdminHomePage.class).gotoServerSettingsPage();

        assertNotNull(serverSettings.clickCancel());
    }

    @Test
    public void testValidationErrors() throws Exception {
        ServerSettingsPage serverSettings = loginAsAdmin(AdminHomePage.class).gotoServerSettingsPage();

        // blank hostname
        serverSettings.setApplicationTitle("   ").setBaseUrl("http://localhost/stash").clickSave();
        assertFieldsWithErrors(serverSettings, "appTitle");

        // invalid base URL (not a URL)
        serverSettings.setApplicationTitle("Stash").setBaseUrl("abc").clickSave();
        assertFieldsWithErrors(serverSettings, "baseUrl");

        // invalid base URL (with invalid characters)
        serverSettings.setBaseUrl("http://localhost/stash>?{}[]").clickSave();
        assertFieldsWithErrors(serverSettings, "baseUrl");
    }

    @Test
    public void testLocale() {
        ServerSettingsPage serverSettings = loginAsAdmin(AdminHomePage.class).gotoServerSettingsPage();
        assertEquals(Locale.US.toString(), serverSettings.getLocale().getLocale());
        serverSettings.getLocale().searchAndSelect("Zealand");
        serverSettings.clickSave();
        try {
            assertEquals("en_NZ", serverSettings.getLocale().getLocale());
        } finally {
            serverSettings.getLocale().searchAndSelect("United");
            serverSettings.clickSave();
        }
    }

    @Test
    public void testServerTimeZone() {
        ServerSettingsPage settingsPage = loginAsAdmin(ServerSettingsPage.class);
        TimeZoneSelector serverTimeZoneSelector = settingsPage.getTimeZoneSelector();
        ZoneId expectedTimeZone = ZoneId.of("Africa/Cairo");

        try {
            assertThat(serverTimeZoneSelector.getTimeZone(), empty());

            serverTimeZoneSelector.filter("Cairo");
            serverTimeZoneSelector.setTimeZone(expectedTimeZone);

            settingsPage = settingsPage.clickSave();
            serverTimeZoneSelector = settingsPage.getTimeZoneSelector();

            Optional<ZoneId> actualTimeZone = serverTimeZoneSelector.getTimeZone();
            assertThat(actualTimeZone, some(expectedTimeZone));

            serverTimeZoneSelector.clearTimeZone();
            settingsPage = settingsPage.clickSave();
            serverTimeZoneSelector = settingsPage.getTimeZoneSelector();

            actualTimeZone = serverTimeZoneSelector.getTimeZone();
            assertThat(actualTimeZone, empty());
        } finally {
            restoreTimeZone();
        }
    }

    private void assertFieldsWithErrors(ServerSettingsPage serverSettings, String... fields) {
        assertEquals(Arrays.asList(fields), serverSettings.getFieldsWithErrors());
    }


    private String[] saveValues(ServerSettingsPage page) {
        return new String[]{page.getApplicationTitle(), page.getBaseUrl()};
    }

    private void restoreTimeZone() {
        try {
            TimeZoneTestHelper.setServerTimeZone(Optional.empty());
        } catch (Exception e) {
            // do nothing, in case the test has already thrown an exception (to prevent masking the original error)
            // (here we assume that any exception in the parent test implies that the settings were not persisted)
        }
    }

    private void restoreValues(ServerSettingsPage page, String[] values) {
        try {
            page.setApplicationTitle(values[0]);
            page.setBaseUrl(values[1]);
            page.clickSave();
        } catch (Exception e) {
            // do nothing, in case the test has already thrown an exception (to prevent masking the original error)
            // (here we assume that any exception in the parent test implies that the settings were not persisted)
        }
    }

}
