package it.com.atlassian.stash.admin;

import com.atlassian.bitbucket.permission.Permission;
import com.atlassian.webdriver.bitbucket.page.admin.UserEditPage;
import com.atlassian.webdriver.bitbucket.page.admin.UserListPage;
import it.com.atlassian.stash.BaseBrowserFuncTest;
import org.junit.BeforeClass;
import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
 * Verifies that an admin user can not update the password or profile of a sysadmin.
 *
 * <p>Syadmin can still reset their password using the password reset UI if needed.</p>
 */
public class UserUpdateRightsTest extends BaseBrowserFuncTest {

    private static final String ADMIN = "testadmin";

    private static final String ADMIN_PASSWORD = "password" + ADMIN;
    private static final String ADMIN2 = "testadmin2";
    private static final String ADMIN_PASSWORD2 = "password" + ADMIN2;
    private static final String SYSADMIN = "testsyadmin";
    private static final String SYSADMIN_PASSWORD = "password" + SYSADMIN;
    private static final String SYSADMIN2 = "testsyadmin2";
    private static final String SYSADMIN2_PASSWORD = "password" + SYSADMIN2;

    @BeforeClass
    public static void setUp() throws Exception {
        getClassTestContext()
                .user(ADMIN, ADMIN, ADMIN_PASSWORD, ADMIN + "@example.com")
                .user(ADMIN2, ADMIN2, ADMIN_PASSWORD2, ADMIN2 + "@example.com")
                .user(SYSADMIN, SYSADMIN, SYSADMIN_PASSWORD, SYSADMIN + "@example.com")
                .user(SYSADMIN2, SYSADMIN2, SYSADMIN2_PASSWORD, SYSADMIN2 + "@example.com");

        getClassTestContext()
                .globalPermission(ADMIN, Permission.ADMIN)
                .globalPermission(ADMIN2, Permission.ADMIN)
                .globalPermission(SYSADMIN, Permission.SYS_ADMIN)
                .globalPermission(SYSADMIN2, Permission.SYS_ADMIN);
    }

    /* --- admin updating sysadmin --- */

    @Test
    public void testAdminCanNotUpdateSysadminDetails() throws Exception {
        testCanNotUpdateDetails(ADMIN, ADMIN_PASSWORD, SYSADMIN);
    }

    @Test
    public void testAdminCanNotUpdateSysadminPassword() throws Exception {
        testCanNotUpdatePassword(ADMIN, ADMIN_PASSWORD, SYSADMIN);
    }

    /* --- sysadmin updating admin --- */

    @Test // verifies the opposite: a sysadmin can update an admin
    public void testSysadminCanUpdateAdminDetails() throws Exception {
        testCanUpdateDetails(SYSADMIN, SYSADMIN_PASSWORD, ADMIN2);
    }

    @Test
    public void testSysadminCanUpdateAdminPassword() throws Exception {
        testCanUpdatePassword(SYSADMIN, SYSADMIN_PASSWORD, ADMIN2);
    }

    /* --- sysadmin updating sysadmin --- */

    @Test
    public void testSysadminCanUpdateOtherSysadminDetails() throws Exception {
        testCanUpdateDetails(SYSADMIN, SYSADMIN_PASSWORD, SYSADMIN2);
    }

    @Test
    public void testSysadminCanUpdateOtherSysadminPassword() throws Exception {
        testCanUpdatePassword(SYSADMIN, SYSADMIN_PASSWORD, SYSADMIN2);
    }

    /* --- utils --- */

    private void testCanUpdateDetails(String user, String password, String userToEdit) {
        assertTrue("unexpected error message", logAsAndEdit(user, password, userToEdit)
                .clickEditDetails()
                .setFullname("change name for " + user)
                .setEmail("newemail@example.com")
                .clickSaveUserDetails().hasUpdateConfirmation("updated"));
    }

    private void testCanNotUpdateDetails(String user, String password, String userToEdit) {
        assertFalse("user is editable whereas it should not", logAsAndEdit(user, password, userToEdit).canUpdateUserDetails());
    }

    private void testCanUpdatePassword(String user, String password, String userToEdit) {
        assertTrue("unexpected error message", logAsAndEdit(user, password, userToEdit)
                .clickChangePassword()
                .setPassword("password")
                .setPasswordConfirm("password")
                .clickSavePassword().hasUpdateConfirmation("Password"));
    }

    private void testCanNotUpdatePassword(String user, String password, String userToEdit) {
        assertFalse("password is editable whereas it should not", logAsAndEdit(user, password, userToEdit).canUpdateUserPassword());
    }

    private UserEditPage logAsAndEdit(String user, String password, String userToEdit) {
        final UserListPage listPage = loginAs(user, password, UserListPage.class);
        return listPage.setFilter(userToEdit).getUser(userToEdit).clickView();
    }

}
