package old.page;

import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author kote
 */
public class AdminUserPage extends BaseComponentPage {

  private static final String TABLE_TO_ADD = "//*[@object-name='AvailableRecordsGrid']";
  private static final String TABLE_ADDED = "//*[@object-name='LinkFieldDialog for save']";
  private static final String USER_TABLE = "//*[@object-name='Grid']";
  private static final String LINK_GROUP_TABLE = "//*[@object-name='DependentGrid']";
  private static final String ROW_BY_NAME = "//div[@role='row']//div[contains(.,'%s')]";

  private static final By CELL_WITH_LAST_NAME = By.xpath(USER_TABLE + "//div[@col-id='user$lastName']" + EXCLUDE_HEADER);
  private static final By CELL_WITH_FIRST_NAME = By.xpath(USER_TABLE + "//div[@col-id='user$firstName']" + EXCLUDE_HEADER);
  private static final By CELL_WITH_MIDDLE_NAME = By.xpath(USER_TABLE + "//div[@col-id='user$middleName']" + EXCLUDE_HEADER);
  private static final By GROUP_IN_TABLE = By.xpath(LINK_GROUP_TABLE + "//div[@col-id='group$name']" + EXCLUDE_HEADER);
  private static final By CELL_WITH_LAST_NAME_HEADER = By.xpath(USER_TABLE + "//div[@col-id='user$lastName']" + AG_HEADER);
  private static final By GROUP_IN_TABLE_HEADER = By.xpath(LINK_GROUP_TABLE + "//div[@col-id='group$name']" + AG_HEADER);
  private static final By GROUP_TO_ADD_HEADER = By.xpath(TABLE_TO_ADD + "//div[@col-id='group$name']" + AG_HEADER);
  private static final By ADDED_GROUPS_HEADER = By.xpath(TABLE_ADDED + "//div[@col-id='group$name']" + AG_HEADER);
  private static final By GROUP_TO_ADD = By.xpath(TABLE_TO_ADD + "//div[@col-id='group$name']" + EXCLUDE_HEADER);
  private static final By ADDED_GROUPS = By.xpath(TABLE_ADDED + "//div[@role='gridcell']" + EXCLUDE_HEADER + "[@col-id='group$name']");
  private static final By LOGOUT_BUTTON = By.xpath("//div[@class ='fa fa-power-off']");


  //User Administration Page
  @FindBy(xpath = "//*[contains(text(),'Фильтр по пользователям')]")
  public WebElement filterPanel;

  //User Editing Page
  @FindBy(xpath = "//*[@object-name='last-name']//input")
  public WebElement lastNameField;
  @FindBy(xpath = "//div[@class='logout']//button[contains(@class,'nav-link')]")
  public WebElement userMenuButton;
  @FindBy(xpath = "//button[contains(.,'Выход')]")
  public WebElement exitButton;

  @FindBy(xpath = "//*[@object-name='first-name']//input")
  private WebElement firstNameField;
  @FindBy(xpath = "//*[@object-name='middleName']//input")
  private WebElement middleNameField;
  @FindBy(xpath = "//*[@object-name='login']//input")
  private WebElement loginField;
  @FindBy(xpath = "//*[@object-name='last-name']//input")
  private WebElement surNameField;
  @FindBy(xpath = "//*[@object-name='password']//input")
  private WebElement passwordField;
  @FindBy(xpath = "//*[@object-name='password-repeat']//input")
  private WebElement passwordRepeatField;
  @FindBy(xpath = "//*[@object-name='email']//input")
  private WebElement emailField;
  @FindBy(xpath = "//div[@row-index='0']//div[@col-id='checkbox_uid']")
  private List<WebElement> listGroupsToAdd;

  public AdminUserPage(WebDriver browser) {
    super(browser, "/#/");
  }

  public void fillUserFullName(String userName) {
    typeText(lastNameField, userName);
    typeText(firstNameField, userName);
    typeText(middleNameField, userName);
  }

  public void fillUserCredentials(String userName, String userPassword, String userEmail,
                                  String userOrganization, String fullOrganizationName) {
    typeText(loginField, userName);
    fillPassAndEmail(userPassword, userEmail);
    chooseUserOrganization(userOrganization, fullOrganizationName);
  }

  public void chooseUserOrganization(String userOrganization, String fullOrganizationName) {
    typeTextAndSelectOption("org_unit_id", userOrganization, fullOrganizationName);
  }

  public void chooseUserOrganization(String userOrganization) {
    typeTextAndSelectOption("org_unit_id", userOrganization, userOrganization);
  }

  public void fillPassAndEmail(String userPassword, String userEmail) {
    fillPass(userPassword);
    typeText(emailField, userEmail);
  }

  public void fillPass(String userPassword) {
    typeText(passwordField, userPassword);
    typeText(passwordRepeatField, userPassword);
  }

  public void searchUser(String userSurName) {
    filterPanel.click();
    waitForPageLoad();
    typeTextOnAdminFilter(surNameField, userSurName);
    waitForInvisibilityGridDownloader();
  }

  public void deleteUser() {
    waitProgressBarNotVisible();
    clickDeleteButton();
    clickConfirmButton();
    waitProgressBarNotVisible();
  }

  public List<WebElement> getListOfLastNamesFromTable() {
    return driver.findElements(CELL_WITH_LAST_NAME);
  }

  public List<WebElement> getListOfFirstNamesFromTable() {
    return driver.findElements(CELL_WITH_FIRST_NAME);
  }

  public List<WebElement> getListOfMiddleNamesFromTable() {
    return driver.findElements(CELL_WITH_MIDDLE_NAME);
  }

  public List<WebElement> getListOfGroupsFromTable() {
    return driver.findElements(GROUP_IN_TABLE);
  }

  public List<WebElement> getListOfAddedGroups() {
    return driver.findElements(ADDED_GROUPS);
  }

  public List<WebElement> getListOfAvailableGroupsToAdd() {
    return driver.findElements(GROUP_TO_ADD);
  }

  public void clickOnUserInTable(String userName) {
    driver.findElement(By.xpath(String.format(USER_TABLE + ROW_BY_NAME, userName))).click();
    waitForPageLoad();
  }

  public void addGroup(String groupName) {
    waitForVisibilityOfElementLocated(By.xpath(String.format(TABLE_TO_ADD + ROW_BY_NAME, groupName))).click();
    clickAddButton();
    waitProgressBarNotVisible();
  }

  public void removeGroup(String groupName) {
    waitForVisibilityOfElementLocated(By.xpath(String.format(TABLE_ADDED + ROW_BY_NAME, groupName))).click();
    clickRemoveButton();
    waitForInvisibilityGridDownloader();
  }

  public void addAllGroups() {
    clickAddAllButton();
    waitProgressBarNotVisible();
  }

  public void removeAllGroups() {
    clickRemoveAllButton();
    waitProgressBarNotVisible();
  }

  /**
   * Method to avoid parallel test conflicts.
   * <p>
   * If the list of groups available for adding is not empty, checks if the list contains only newly created groups.
   * </p>
   *
   * @param groupNames list retrieved from the database before the parallel test created a new group.
   *                   Instance of {@link List<String>} type.
   *
   * @return value of {@link Boolean} type.
   * <p>
   * True - if list of groups available for adding is empty, or contains only newly created groups from parallel tests.
   * </p>
   * <p>
   * False - if list of groups available for adding contains values from groupNames list.
   * </p>
   */
  public boolean isAvailableGridEmpty(List<String> groupNames) {
    List<String> possibleParallelAddedGroups = getListOfAvailableGroupsToAdd()
        .stream()
        .map(WebElement::getText)
        .collect(Collectors.toList());

    if (possibleParallelAddedGroups.isEmpty()) {
      return true;
    }
    else {
      return groupNames
          .stream()
          .noneMatch(possibleParallelAddedGroups::contains);
    }
  }

  public void bindGroup(String roleName) {
    changeUserPageGridsSort(UsersPageGrids.GROUPS_TO_ADD_GRID);

    //проходим вниз все группы пока не найдем нужную
    listGroupsToAdd.get(0).click();
    Actions actions = new Actions(driver);
    int numberOfScrolls = 10;
    while (driver.findElements(By.xpath(String.format(TABLE_TO_ADD + ROW_BY_NAME, roleName)))
               .isEmpty() && numberOfScrolls != 0) {
      actions.sendKeys(Keys.PAGE_DOWN).perform();
      numberOfScrolls--;
    }

    waitProgressBarNotVisible();
    addGroup(roleName);
    waitProgressBarNotVisible();
  }
  
  public void logout() {
    waitProgressBarNotVisible();
    userMenuButton.click();
    exitButton.click();
  }

  public void changeUserPageGridsSort(UsersPageGrids value) {
    switch (value) {
      case USERS_GRID:
        driver.findElement(CELL_WITH_LAST_NAME_HEADER).click();
        break;
      case LINKED_GROUPS_GRID:
        driver.findElement(GROUP_IN_TABLE_HEADER).click();
        break;
      case GROUPS_TO_ADD_GRID:
        driver.findElement(GROUP_TO_ADD_HEADER).click();
      case ADDED_GROUPS_GRID:
        driver.findElement(ADDED_GROUPS_HEADER).click();
        break;
    }
    waitForPageLoad();
  }

  public enum UsersPageGrids {
    USERS_GRID,
    LINKED_GROUPS_GRID,
    GROUPS_TO_ADD_GRID,
    ADDED_GROUPS_GRID
  }
}