package old;

import com.google.common.collect.Comparators;
import old.core.Browser;
import old.core.BrowserArgumentProvider;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;

import old.page.AdminGroupPage;
import old.page.AdminUserPage;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * @author kote
 */
public class AdminGroupIT extends BaseComponentIT {

  private static final String GROUP_ACCESS_LEVEL = "user access level";
  private static final String ROLE = "BPMN User";
  private static final String ROLE_2 = "BPMN Admin";
  private static final String ROLE_3 = "BPMN Superuser";
  private static final String COL_ID = "group$name";
  private static final String COL_ID_CREATED = "group$created";
  private static final String COL_ID_UPDATED = "group$updated";
  private static final String BPMN_ADMIN_ROLE_ID = "aa14ba1d-0b61-4e33-8474-7c2d98944b12";
  private static final String BPMN_USER_ROLE_ID = "767ae8cf-af01-44d4-86ef-fcb143373407";
  private static final String BPMN_SUPERUSER_ROLE_ID = "2569ba58-1f8f-43ea-8b2c-0d373cf501fe";

  private AdminGroupPage adminGroupPage;
  private String oldName;
  private String groupId;
  private String roleId;

  public AdminGroupIT() {
    super();
  }

  @AfterEach
  public void afterEachTest(TestInfo testInfo) {
    String testName = testInfo.getTestMethod().toString();

    if (testName.contains("User")) {
      EXECUTION_MANAGER.deleteTestUser(name);
    }

    if (testName.contains("edit")) {
      EXECUTION_MANAGER.deleteTestGroup(oldName);
    }

    if (testName.contains("linked")) {
      EXECUTION_MANAGER.deleteUserGroupRole(name, groupId, roleId);
    }

    if (testName.contains("Sorting")) {
      String groupIdToDelete = EXECUTION_MANAGER.getGroupIdByName(name);
      EXECUTION_MANAGER.deleteLinkedRolesFromGroup(groupIdToDelete);
    }

    EXECUTION_MANAGER.deleteTestGroup(name);
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void createGroup(Browser browser) {
    openBrowserAndAdminPage(browser);
    adminGroupPage.clickCreateButton();

    adminGroupPage.waitForPageLoad();
    adminGroupPage.waitForVisibilityOf(adminGroupPage.nameField);
    adminGroupPage.typeText(adminGroupPage.nameField, name);
    adminGroupPage.typeAndSelectLevel(GROUP_ACCESS_LEVEL);
    adminGroupPage.addRole(ROLE, false);
    adminGroupPage.clickSaveButton();
    String dateOfCreation = adminGroupPage.getLocalDate();

    adminGroupPage.waitForPageLoad();
    adminGroupPage.searchGroup(name);
    assertEquals(1, adminGroupPage.getListOfGroupsNamesFromTable(name).size());
    assertTrue(adminGroupPage.getActionTime(COL_ID, name, COL_ID_CREATED).getText().contains(dateOfCreation));
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void searchGroup(Browser browser) {
    openBrowserAndAdminPage(browser);
    EXECUTION_MANAGER.createTestGroup(name, ACCESS_LEVEL_ID);
    adminGroupPage.searchGroup(name);

    adminGroupPage.waitForPageLoad();
    assertEquals(1, adminGroupPage.getListOfGroupsNamesFromTable(name).size());
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void editGroup(Browser browser) {
    openBrowserAndAdminPage(browser);
    oldName = "old" + name;
    EXECUTION_MANAGER.createTestGroup(oldName, ACCESS_LEVEL_ID);

    adminGroupPage.chooseGroup(oldName);
    adminGroupPage.clickEditButton();
    adminGroupPage.waitForVisibilityOf(adminGroupPage.nameField);
    adminGroupPage.typeText(adminGroupPage.nameField, name);
    adminGroupPage.addRole(ROLE, false);
    adminGroupPage.clickSaveButton();
    adminGroupPage.searchGroup(oldName);
    assertEquals(0, adminGroupPage.getListOfGroupsNamesFromTable(oldName).size());

    adminGroupPage.chooseGroup(name);
    assertEquals(1, adminGroupPage.getListOfGroupsNamesFromTable(name).size());
    String timeOfCreate = adminGroupPage.getActionTime(COL_ID, name, COL_ID_CREATED).getText();
    String timeOfUpdate = adminGroupPage.getActionTime(COL_ID, name, COL_ID_UPDATED).getText();
    assertNotEquals(timeOfCreate, timeOfUpdate);

    adminGroupPage.clickEditButton();
    assertTrue(adminGroupPage.hasRolesInTable(AdminGroupPage.GroupPageGrids.ADDED_ROLES_GRID, ROLE));
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void deleteGroup(Browser browser) {
    openBrowserAndAdminPage(browser);
    EXECUTION_MANAGER.createTestGroup(name, ACCESS_LEVEL_ID);

    adminGroupPage.chooseGroup(name);
    adminGroupPage.deleteGroup();
    assertTrue(adminGroupPage.isGridEmpty());
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void linkedRolesTable(Browser browser) {
    openBrowserAndAdminPage(browser);
    roleId = EXECUTION_MANAGER.generateId();
    groupId = EXECUTION_MANAGER.generateId();
    EXECUTION_MANAGER.createBindGroupRole(name, groupId, ACCESS_LEVEL_ID, roleId);

    adminGroupPage.chooseGroup(name);
    assertEquals(1, adminGroupPage.getListOfRolesFromLinkedTable().size());
    assertEquals(name, adminGroupPage.getListOfRolesFromLinkedTable().get(0).getText());
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void attachRemoveRoleToGroup(Browser browser) {
    openBrowserAndAdminPage(browser);
    EXECUTION_MANAGER.createTestGroup(name, ACCESS_LEVEL_ID);
    adminGroupPage.chooseGroup(name);
    assertTrue(adminGroupPage.getListOfRolesFromLinkedTable().isEmpty());

    adminGroupPage.clickEditButton();
    assertFalse(adminGroupPage.getListOfRolesToAdd().isEmpty());
    assertTrue(adminGroupPage.getListOfAddedRoles().isEmpty());

    adminGroupPage.addRole(ROLE, false);
    assertFalse(adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesToAdd()).contains(ROLE));
    assertTrue(adminGroupPage.getWebElementTexts(adminGroupPage.getListOfAddedRoles()).contains(ROLE));
    assertEquals(1, adminGroupPage.getListOfAddedRoles().size());

    adminGroupPage.clickSaveButton();
    adminGroupPage.chooseGroup(name);
    assertEquals(1, adminGroupPage.getListOfRolesFromLinkedTable().size());
    assertTrue(adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesFromLinkedTable()).contains(ROLE));

    adminGroupPage.clickEditButton();
    adminGroupPage.removeRole(ROLE);
    assertTrue(adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesToAdd()).contains(ROLE));
    assertTrue(adminGroupPage.getListOfAddedRoles().isEmpty());

    adminGroupPage.clickSaveButton();
    adminGroupPage.chooseGroup(name);
    assertTrue(adminGroupPage.getListOfRolesFromLinkedTable().isEmpty());
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void attachRemoveAllRolesToGroup(Browser browser) {
    openBrowserAndAdminPage(browser);
    EXECUTION_MANAGER.createTestGroup(name, ACCESS_LEVEL_ID);
    List<String> roleNames = EXECUTION_MANAGER.getRoleNamesFromUserRole();
    List<String> expectedRoles = Arrays.asList(ROLE, ROLE_2, ROLE_3);

    adminGroupPage.chooseGroup(name);
    adminGroupPage.clickEditButton();
    assertFalse(adminGroupPage.getListOfRolesToAdd().isEmpty());
    assertTrue(adminGroupPage.getListOfAddedRoles().isEmpty());

    adminGroupPage.addAllRoles();
    assertTrue(adminGroupPage.isAvailableGridEmpty(roleNames));
    assertFalse(adminGroupPage.getListOfAddedRoles().isEmpty());
    /*
    Нет возможности проверить сохранение привязки всех ролей к группе из-за создания/удаление ролей
    параллельными тестами.
     */

    adminGroupPage.removeAllRoles();
    assertFalse(adminGroupPage.getListOfRolesToAdd().isEmpty());
    assertTrue(adminGroupPage.getListOfAddedRoles().isEmpty());

    adminGroupPage.addRole(ROLE, false);
    adminGroupPage.addRole(ROLE_2, false);
    adminGroupPage.addRole(ROLE_3, false);
    adminGroupPage.clickSaveButton();
    adminGroupPage.chooseGroup(name);
    assertEquals(expectedRoles.size(), adminGroupPage.getListOfRolesFromLinkedTable().size());
    assertTrue(adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesFromLinkedTable())
        .containsAll(expectedRoles));

    adminGroupPage.clickEditButton();
    adminGroupPage.removeAllRoles();
    adminGroupPage.clickSaveButton();
    adminGroupPage.chooseGroup(name);
    assertTrue(adminGroupPage.getListOfRolesFromLinkedTable().isEmpty());
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void addNewGroupToUser(Browser browser) {
    openBrowserAndAdminPage(browser);
    String userName = name;
    EXECUTION_MANAGER.createUser(userName, ORGANIZATION_ID);
    adminGroupPage.clickCreateButton();

    adminGroupPage.waitForPageLoad();
    adminGroupPage.waitForVisibilityOf(adminGroupPage.nameField);
    adminGroupPage.typeText(adminGroupPage.nameField, name);
    adminGroupPage.typeAndSelectLevel(GROUP_ACCESS_LEVEL);
    adminGroupPage.clickSaveButton();

    AdminUserPage adminUserPage = inboxPage.startAdminUser();
    adminUserPage.searchUser(userName);
    adminUserPage.clickOnUserInTable(userName);
    adminUserPage.clickEditButton();
    adminUserPage.fillPassAndEmail(userName, userName + "@test.ru");
    adminUserPage.bindGroup(name);
    assertTrue(adminUserPage.getWebElementTexts(adminUserPage.getListOfAddedGroups()).contains(name));

    adminUserPage.clickSaveButton();
    adminUserPage.searchUser(userName);
    adminUserPage.clickOnUserInTable(userName);
    assertEquals(1, adminUserPage.getListOfGroupsFromTable().size());
    assertEquals(name, adminUserPage.getListOfGroupsFromTable().get(0).getText());
  }

  @Disabled("dev WEBBPMNEXT-7837")
  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void groupRolesGridsSorting(Browser browser) {
    openBrowserAndAdminPage(browser);
    EXECUTION_MANAGER.createGroupBindRoles(name, ACCESS_LEVEL_ID, BPMN_ADMIN_ROLE_ID,
        BPMN_USER_ROLE_ID, BPMN_SUPERUSER_ROLE_ID);

    //main group page sorting
    List<String> groupNamesNatural = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfGroupNames());
    assertTrue(Comparators.isInOrder(groupNamesNatural, String.CASE_INSENSITIVE_ORDER),
        "Grid wasn't sorted");

    adminGroupPage.changeGroupPageGridSort(AdminGroupPage.GroupPageGrids.GROUP_NAMES_GRID);
    List<String> groupNamesReverse = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfGroupNames());
    assertTrue(Comparators.isInOrder(groupNamesReverse, String.CASE_INSENSITIVE_ORDER.reversed()),
        "Grid wasn't sorted");

    adminGroupPage.chooseGroup(name);
    List<String> linkedRolesNatural = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesFromLinkedTable());
    assertTrue(Comparators.isInOrder(linkedRolesNatural, String.CASE_INSENSITIVE_ORDER),
        "Grid wasn't sorted");

    adminGroupPage.changeGroupPageGridSort(AdminGroupPage.GroupPageGrids.LINKED_ROLES_GRID);
    List<String> linkedRolesReverse = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesFromLinkedTable());
    assertTrue(Comparators.isInOrder(linkedRolesReverse, String.CASE_INSENSITIVE_ORDER.reversed()),
        "Grid wasn't sorted");

    //edit group page sorting
    adminGroupPage.clickEditButton();
    List<String> availableToAddRolesNatural = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesToAdd());
    assertTrue(Comparators.isInOrder(availableToAddRolesNatural, String.CASE_INSENSITIVE_ORDER),
        "Grid wasn't sorted");

    adminGroupPage.changeGroupPageGridSort(AdminGroupPage.GroupPageGrids.ROLES_TO_ADD_GRID);
    List<String> availableToAddRolesReverse = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesToAdd());
    assertTrue(Comparators.isInOrder(availableToAddRolesReverse,
        String.CASE_INSENSITIVE_ORDER.reversed()), "Grid wasn't sorted");

    adminGroupPage.removeAllRoles();
    List<String> addedRolesNatural = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfAddedRoles());
    assertTrue(Comparators.isInOrder(addedRolesNatural, String.CASE_INSENSITIVE_ORDER),
        "Grid wasn't sorted");

    adminGroupPage.changeGroupPageGridSort(AdminGroupPage.GroupPageGrids.ADDED_ROLES_GRID);
    List<String> addedRolesReverse = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfAddedRoles());
    assertTrue(Comparators.isInOrder(addedRolesReverse, String.CASE_INSENSITIVE_ORDER.reversed()),
        "Grid wasn't sorted");

    //create group page sorting
    adminGroupPage.cancelAction();
    adminGroupPage.clickCreateButton();
    List<String> rolesToAddNatural = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesToAdd());
    assertTrue(Comparators.isInOrder(rolesToAddNatural, String.CASE_INSENSITIVE_ORDER),
        "Grid wasn't sorted");

    adminGroupPage.changeGroupPageGridSort(AdminGroupPage.GroupPageGrids.ROLES_TO_ADD_GRID);
    List<String> rolesToAddReverse = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfRolesToAdd());
    assertTrue(Comparators.isInOrder(rolesToAddReverse, String.CASE_INSENSITIVE_ORDER.reversed()),
        "Grid wasn't sorted");

    adminGroupPage.removeAllRoles();
    List<String> addedRolesNaturalSort = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfAddedRoles());
    assertTrue(Comparators.isInOrder(addedRolesNaturalSort, String.CASE_INSENSITIVE_ORDER),
        "Grid wasn't sorted");

    adminGroupPage.changeGroupPageGridSort(AdminGroupPage.GroupPageGrids.ADDED_ROLES_GRID);
    List<String> addedRolesReverseSort = adminGroupPage.getWebElementTexts(adminGroupPage.getListOfAddedRoles());
    assertTrue(Comparators.isInOrder(addedRolesReverseSort, String.CASE_INSENSITIVE_ORDER.reversed()),
        "Grid wasn't sorted");
  }

  private void openBrowserAndAdminPage(Browser browser) {
    openBrowserAndLoginForAdmin(browser);
    initAdminName();
    adminGroupPage = inboxPage.startAdminGroup();
  }
}