package it.com.atlassian.stash;

import com.atlassian.bitbucket.test.PermissionsTestHelper;
import com.atlassian.bitbucket.test.ProjectTestHelper;
import com.atlassian.bitbucket.permission.Permission;
import com.atlassian.webdriver.bitbucket.element.AuiMessage;
import com.atlassian.webdriver.bitbucket.page.ProjectCreatePage;
import com.atlassian.webdriver.bitbucket.page.ProjectListPage;
import com.atlassian.webdriver.bitbucket.page.ProjectOverviewPage;
import com.atlassian.webdriver.bitbucket.page.BitbucketLoginPage;
import com.google.common.collect.Iterables;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.Collection;
import java.util.List;

import static org.junit.Assert.*;

public class ProjectListTest extends BaseBrowserFuncTest {

    private static final String SEED_PROJECT_KEY_FORMAT = "FUNC_TEST_PROJECT_%s";
    private static final String SEED_PROJECT_NAME_FORMAT = "Func test Project_%s";
    private static final int NUM_PROJECTS_TO_SEED = 100;

    // Created project is the 101st project
    private static final int CREATED_PROJECT_ON_PAGE = (int) Math.ceil((NUM_PROJECTS_TO_SEED + 1) / 100.0);

    private static final String PROJECT_NAME_TO_CREATE = "Func test Project_999";
    private static final String PROJECT_KEY_TO_CREATE = "FUNC_TEST_PROJECT_999";

    private static final String USER_WITH_CREATE_PROJ = "can-create-proj";
    private static final String USER_WITHOUT_CREATE_PROJ = "no-create";

    @BeforeClass
    public static void createTestContext() {
        getClassTestContext().user(USER_WITH_CREATE_PROJ).globalPermission(USER_WITH_CREATE_PROJ, Permission.PROJECT_CREATE);
        getClassTestContext().user(USER_WITHOUT_CREATE_PROJ).globalPermission(USER_WITHOUT_CREATE_PROJ, Permission.LICENSED_USER);
        getClassTestContext().projects(SEED_PROJECT_KEY_FORMAT, SEED_PROJECT_NAME_FORMAT, NUM_PROJECTS_TO_SEED);
    }

    // In case tests set global permissions for users and don't clean up properly
    @Before
    public void setUpPermissions() {
        PermissionsTestHelper.setGlobalPermissionForUser(USER_WITH_CREATE_PROJ, Permission.PROJECT_CREATE.name());
        PermissionsTestHelper.setGlobalPermissionForUser(USER_WITHOUT_CREATE_PROJ, Permission.LICENSED_USER.name());
    }

    @After
    public void cleanupCreatedProject() {
        ProjectTestHelper.deleteProject(PROJECT_KEY_TO_CREATE);
    }

    @Test
    public void testCreateCancellation() {
        ProjectListPage projectList = loginAs(USER_WITH_CREATE_PROJ, USER_WITH_CREATE_PROJ, ProjectListPage.class);

        ProjectCreatePage errorPage = projectList.goToCreateProjectPage()
                .setDescription("Cancel me")
                .setKey("CANCELME")
                .setName("Cancel Me")
                .submitFail();

        // Verify that creation is canceled and that the cancellation message from the plugin is shown
        Collection<String> errorMessages = errorPage.getAuiErrorMessages();
        assertFalse(errorMessages.isEmpty());
        assertEquals(1, errorMessages.size());
        assertTrue(Iterables.getOnlyElement(errorMessages).endsWith("\nTesting project creation cancellation."));
    }

    @Test
    public void testCreateProjectAndNavigateToIt() {
        //Let him see all the projects
        PermissionsTestHelper.setGlobalPermissionForUser(USER_WITH_CREATE_PROJ, Permission.ADMIN.name());

        ProjectListPage projectList = loginAs(USER_WITH_CREATE_PROJ, USER_WITH_CREATE_PROJ, ProjectListPage.class);

        projectList.goToCreateProjectPage()
            .setKey(PROJECT_KEY_TO_CREATE)
            .setName(PROJECT_NAME_TO_CREATE)
            .submitSuccess();

        projectList = BITBUCKET.visit(ProjectListPage.class);

        // Created project should not in table until we load next page
        assertNull("Should not have '" + PROJECT_NAME_TO_CREATE + "' (on initial page) in the table contents.",
                projectList.findProjectByName(PROJECT_NAME_TO_CREATE));

        projectList.getProjectTable().loadNextPage(); // load page 2

        assertTrue("Should have '" + PROJECT_NAME_TO_CREATE + "' (on page " + CREATED_PROJECT_ON_PAGE + ") in the table contents.",
                  projectList.findProjectByName(PROJECT_NAME_TO_CREATE).isPresent());
        // Undo the admin permissions
        PermissionsTestHelper.setGlobalPermissionForUser(USER_WITH_CREATE_PROJ, Permission.PROJECT_CREATE.name());
    }

    @Test
    public void testCreateAndDeleteProjectAsNonAdmin() throws Exception {
        ProjectListPage projectList = loginAs(USER_WITH_CREATE_PROJ, USER_WITH_CREATE_PROJ, ProjectListPage.class);
        // Clear any existing messages
        List<AuiMessage> messages = projectList.getMessages();
        for (AuiMessage message : messages) {
            message.clear();
        }

        ProjectOverviewPage overviewPage = projectList.goToCreateProjectPage()
                .setKey(PROJECT_KEY_TO_CREATE)
                .setName(PROJECT_NAME_TO_CREATE)
                .submitSuccess();

        projectList = overviewPage.goToEditSettingsPage().clickDelete().clickConfirmSuccess();
        messages = projectList.getMessages();
        assertEquals("Should only be 1 message", 1, messages.size());
        assertTrue("Confirmation message should contain the text 'deleted'", messages.get(0).getMessage().contains("deleted"));
    }

    @Test
    public void testNoCreateProjectButtonForUnauthorisedUser() throws Exception {
        ProjectListPage projectList = loginAs(USER_WITHOUT_CREATE_PROJ, USER_WITHOUT_CREATE_PROJ, ProjectListPage.class);
        assertFalse("User should not see the create project button", projectList.canCreateProject());
    }

    @Test
    public void testHasCreateProjectButtonForAuthorisedUser() throws Exception {
        ProjectListPage projectList = loginAs(USER_WITH_CREATE_PROJ, USER_WITH_CREATE_PROJ, ProjectListPage.class);
        assertTrue("User should see the create project button", projectList.canCreateProject());
    }

    @Test(expected = AssertionError.class)
    public void testProjectListAnonymousUser() {
        // This should fail because it can never reach the ProjectListPageAnon
        anonymous(ProjectListPageAnon.class).isHere();
    }

    @Test
    public void testProjectListOneRepoAnonymousUser() throws Throwable {
        testContext.project("temp_project");
        testContext.repository("temp_project", "empty_repo", true);
        assertEquals(1, anonymous(ProjectListPage.class).getProjectTable().getProjects().size());
    }

    // We want to check that we redirect to the login page
    public static class ProjectListPageAnon extends ProjectListPage {

        @Override
        public void doWait() {
            pageBinder.bind(BitbucketLoginPage.class).doWait();
        }
    }

}
