package tests;

import core.BaseTest;
import core.Browser;
import core.BrowserArgumentProvider;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
import pages.GroupsPage;
import pages.InboxPage;

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.assertTrue;
import static org.openqa.selenium.support.PageFactory.initElements;

/**
 * @author kote
 */
public class GroupsIT extends BaseTest {

  private static final String ADMINISTRATION = "Администрирование";
  private static final String GROUPS = "Группы";
  private static final String CREATE = "Создать";
  private static final String EDIT = "Редактировать";
  private static final String SAVE = "Сохранить";
  private static final String ADD_ONE = ">";
  private static final String REMOVE_ONE = "<";
  private static final String TABLE_ADDED = "ADDED";
  private static final String TABLE_TO_ADD = "TO_ADD";
  private static final String CONFIRMATION_TITLE = "Подтверждение действия";
  private static final String YES = "Да";
  private static final String PART_FOR_NAME = "groupsTest";

  private GroupsPage groupsPage;

  @AfterAll
  public static void afterAll() {
    EXECUTION_MANAGER.deleteGroupByName(PART_FOR_NAME);
    EXECUTION_MANAGER.deleteRoleByName(PART_FOR_NAME);
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void crudGroups(Browser browser) {
    InboxPage inboxPage = loginInAppByAdmin(browser);
    assertTrue(inboxPage.pageLoadSuccessfully());

    inboxPage.clickOnMenu(ADMINISTRATION);
    inboxPage.clickOnSubMenu(GROUPS);
    groupsPage = initElements(driver, GroupsPage.class);
    assertTrue(groupsPage.pageLoadSuccessfully());
    assertTrue(groupsPage.isTitleVisible("Администрирование групп"));

    //check create and search group:
    groupsPage.clickOnButton(CREATE);
    assertTrue(groupsPage.pageLoadSuccessfully());

    String groupName = generateName(PART_FOR_NAME);
    groupsPage.editGroupName(groupName);
    groupsPage.selectAccessLevel("user access level");
    groupsPage.clickOnButton(SAVE);
    assertTrue(groupsPage.pageLoadSuccessfully());

    groupsPage.editSearchField(groupName);
    groupsPage.waitGridProgressBarNotVisible();
    assertTrue(groupsPage.isGroupVisible(groupName));
    assertEquals(1, groupsPage.getNumberOfGroupRows());

    //check edit group:
    groupsPage.clickOnGroup(groupName);
    groupsPage.clickOnButton(EDIT);
    assertTrue(groupsPage.pageLoadSuccessfully());

    String newGroupName = generateName(PART_FOR_NAME);
    groupsPage.editGroupName(newGroupName);
    groupsPage.clickOnButton(SAVE);
    assertTrue(groupsPage.pageLoadSuccessfully());

    groupsPage.editSearchField(groupName);
    groupsPage.waitGridProgressBarNotVisible();
    assertEquals(0, groupsPage.getNumberOfGroupRows());

    groupsPage.editSearchField(newGroupName);
    groupsPage.waitGridProgressBarNotVisible();
    assertTrue(groupsPage.isGroupVisible(newGroupName));
    assertEquals(1, groupsPage.getNumberOfGroupRows());

    //check delete group:
    groupsPage.clickOnGroup(newGroupName);
    groupsPage.clickOnButton("Удалить");
    assertTrue(groupsPage.isDialogOpened(CONFIRMATION_TITLE));

    groupsPage.clickOnButton(YES);
    assertTrue(groupsPage.pageLoadSuccessfully());
    assertEquals(0, groupsPage.getNumberOfGroupRows());
  }

  @ParameterizedTest
  @ArgumentsSource(BrowserArgumentProvider.class)
  public void addAndRemoveRoles(Browser browser) {
    InboxPage inboxPage = loginInAppByAdmin(browser);
    assertTrue(inboxPage.pageLoadSuccessfully());

    inboxPage.clickOnMenu(ADMINISTRATION);
    inboxPage.clickOnSubMenu(GROUPS);
    groupsPage = initElements(driver, GroupsPage.class);
    assertTrue(groupsPage.pageLoadSuccessfully());

    groupsPage.clickOnButton(CREATE);
    assertTrue(groupsPage.pageLoadSuccessfully());

    String roleName = generateName(PART_FOR_NAME);
    EXECUTION_MANAGER.insertRole(roleName);
    String groupName = generateName(PART_FOR_NAME);
    groupsPage.editGroupName(groupName);
    groupsPage.selectAccessLevel("user access level");

    //check > 1 element:
    List<String> listRoles = groupsPage.getListOfRolesNamesToAdd();
    groupsPage.clickOnRoleToAdd(listRoles.get(1));
    groupsPage.clickOnMoveButton(ADD_ONE);
    groupsPage.waitGridProgressBarNotVisible();
    checkRolesInTable(TABLE_ADDED, listRoles.subList(1, 2), true);
    checkRolesInTable(TABLE_TO_ADD, listRoles.subList(1, 2), false);

    //check < 1 element:
    groupsPage.clickOnRoleAdded(listRoles.get(1));
    groupsPage.clickOnMoveButton(REMOVE_ONE);
    groupsPage.waitGridProgressBarNotVisible();
    checkRolesInTable(TABLE_TO_ADD, listRoles.subList(1, 2), true);
    checkRolesInTable(TABLE_ADDED, listRoles.subList(1, 2), false);

    //check > 2 elements:
    //здесь не проверяем выбор двух ролей чекбоксом из-за бага Selenium получения списка
    //(он не в том порядке, в котором они отображаются), проверяем кликом по конкретной роли
    listRoles = groupsPage.getListOfRolesNamesToAdd(); //актуализируем список
    groupsPage.clickOnRoleToAdd(listRoles.get(1));
    groupsPage.clickOnMoveButton(ADD_ONE);
    groupsPage.clickOnRoleToAdd(listRoles.get(2));
    groupsPage.clickOnMoveButton(ADD_ONE);
    groupsPage.waitGridProgressBarNotVisible();
    checkRolesInTable(TABLE_ADDED, listRoles.subList(1, 3), true);
    checkRolesInTable(TABLE_TO_ADD, listRoles.subList(1, 3), false);

    //check < 2 elements:
    groupsPage.clickOnRoleAdded(listRoles.get(1));
    groupsPage.clickOnMoveButton(REMOVE_ONE);
    groupsPage.clickOnRoleAdded(listRoles.get(2));
    groupsPage.clickOnMoveButton(REMOVE_ONE);
    groupsPage.waitGridProgressBarNotVisible();
    checkRolesInTable(TABLE_TO_ADD, listRoles.subList(1, 3), true);
    checkRolesInTable(TABLE_ADDED, listRoles.subList(1, 3), false);

    //check >>:
    listRoles = groupsPage.getListOfRolesNamesToAdd(); //актуализируем список
    groupsPage.clickOnMoveButton(">>");
    groupsPage.waitGridProgressBarNotVisible();
    checkRolesInTable(TABLE_ADDED, listRoles, true);
    checkRolesInTable(TABLE_TO_ADD, listRoles, false);

    //check <<:
    groupsPage.clickOnMoveButton("<<");
    groupsPage.waitGridProgressBarNotVisible();
    checkRolesInTable(TABLE_TO_ADD, listRoles, true);
    checkRolesInTable(TABLE_ADDED, listRoles, false);

    //check Ok and linked roles grid:
    groupsPage.clickOnRoleDateColumnHeader();
    groupsPage.clickOnRoleToAdd(roleName);
    groupsPage.clickOnMoveButton(ADD_ONE);
    groupsPage.waitGridProgressBarNotVisible();
    groupsPage.clickOnButton(SAVE);
    assertTrue(groupsPage.pageLoadSuccessfully());

    groupsPage.editSearchField(groupName);
    groupsPage.waitGridProgressBarNotVisible();
    groupsPage.clickOnGroup(groupName);
    groupsPage.waitGridProgressBarNotVisible();
    assertTrue(groupsPage.isRoleVisible(roleName));
    assertEquals(1, groupsPage.getNumberOfRolesRows());

    //check Cancel:
    groupsPage.clickOnButton(EDIT);
    assertTrue(groupsPage.pageLoadSuccessfully());

    groupsPage.clickOnRoleAdded(roleName);
    groupsPage.clickOnMoveButton(REMOVE_ONE);
    groupsPage.clickOnButton("Отменить");
    assertTrue(groupsPage.isDialogOpened(CONFIRMATION_TITLE));

    groupsPage.clickOnButton(YES);
    assertTrue(groupsPage.pageLoadSuccessfully());

    groupsPage.editSearchField(groupName);
    groupsPage.waitGridProgressBarNotVisible();
    groupsPage.clickOnGroup(groupName);
    groupsPage.waitGridProgressBarNotVisible();
    assertTrue(groupsPage.isRoleVisible(roleName));
    assertEquals(1, groupsPage.getNumberOfRolesRows());
  }

  private void checkRolesInTable(String table, List<String> expectedValues, boolean shouldHaveValues) {
    if (shouldHaveValues) {
      assertTrue(groupsPage.hasRolesInTable(table, expectedValues));
    }
    else {
      assertFalse(groupsPage.hasRolesInTable(table, expectedValues));
    }
  }
}