import { Logs } from '@utility-lib/log';
import { HttpRequest } from 'cypress/artifacts';

export const userPageSelectors = {
  usersTable: 'table[role="table"] tbody',
  userRow: '[data-testid="user-row-{0}"]',
  managerTrigger: '[data-testid="manager-combobox"]',
  dropDownSelection: '[data-testid="option-{0}"]',
  approverTrigger: '[data-testid="users-approver-combobox"]',
  statusToggle: '[data-testid="users-status-toggle"]',
  statusLabelText: '[data-testid="users-status-toggle"] label.ta-toggle span',
  registeredColumn: '.cdk-column-registered',
  modalSendCtaModal: 'ta-modal [text="Send"]',
  accessColumn: '.cdk-column-userAccess',
  accessModal: 'ta-modal .user-permissions__main',
  permissionItem: '.user-permissions__main > :nth-child({0}) .permission-item__toggle',
  closeModal: '[data-testid="modal-header-close-button"]',
  permissionIcon: 'ta-permissions > :nth-child({0})',
  permissionIconActive: 'permissions__icon--active',
  titleColumnToggle: '.cdk-column-title',
  looseFocus: '.ta-co-users-main-header__wrapper',
  costCenterColumn: '.cdk-column-billTo',
  addOptionCombo: '.ta-combobox__custom-option',
  departmentColumn: '.cdk-column-department',
  subsidiaryColumn: '.cdk-column-subsidiary',
  regionColumn: '.cdk-column-region',
  employeeidColumn: '.cdk-column-employeeId',
  policyLevelColumn: '.cdk-column-policyLevel',
  companyOfficeColumn: '.cdk-column-companyOffice-officeName',
  openStatusFilter: '[label="Status"] .ta-co-users-filter',
  filterCheckboxesList: '.ta-co-filters-header__filter-content',
  checkedCheckbox: 'mat-checkbox.mat-checkbox-checked:first'
};

export enum apiWait {
  USERS_PATCH = '@apiUsersPatch',
  USERS_POST_PERMISSIONS = '@apiUsersPostPermissions',
  USER_ACCESS_CONTROL = '@apiUserAccessControl'
}

export interface ColumnTestParams {
  columnSelector: string;
  userA: string;
  userB: string;
  textToType: string;
}

const formatStr = (text: string, replacement: string): string => text.replace('{0}', replacement);

export class UsersPage {
  static gotoUsersPage(): void {
    cy.allure().logStep('going to users page');

    cy.visit('/app/company/users');
  }

  static getRowByEmail(userEmail: string): Cypress.Chainable<any> {
    cy.allure().logStep('find the row of user: ' + userEmail);

    return cy.get(formatStr(userPageSelectors.userRow, userEmail));
  }

  static openSelectManagerForUser(email: string): void {
    const userRow = UsersPage.getRowByEmail(email);

    cy.allure().logStep('clicking on the Select Manager' + userRow);

    userRow.find(userPageSelectors.managerTrigger).click();

    UsersPage.waitForUsers();
  }

  static selectUserInDropDown(userNameAndEmail: string): void {
    cy.allure().logStep('clicking on the Select user ' + userNameAndEmail);

    cy.get(formatStr(userPageSelectors.dropDownSelection, userNameAndEmail)).click();
  }

  static waitForUsers(): void {
    cy.allure().logStep('wait for users');

    cy.wait('@apiAdminUsers');

    cy.wait(1000);
  }

  static verifyEmailInManagerCell(userEmail: string, managerEmail: string): void {
    cy.allure().logStep(`verifying user ${userEmail} contains manager: ${managerEmail}`);

    UsersPage.getRowByEmail(userEmail).find(userPageSelectors.managerTrigger).should('contain.text', managerEmail);
  }

  static openSelectApproverForUser(email: string): void {
    const userRow = UsersPage.getRowByEmail(email);

    cy.allure().logStep('clicking on the Select Approver');

    userRow.find(userPageSelectors.approverTrigger).click();

    UsersPage.waitForUsers();
  }

  static verifyEmailInApproverCell(userEmail: string, approver: string): void {
    cy.allure().logStep(`verifying user ${userEmail} contains approver: ${approver}`);

    UsersPage.getRowByEmail(userEmail).find(userPageSelectors.approverTrigger).should('contain.text', approver);
  }

  static clickOn(selector: string): void {
    cy.allure().logStep(`clicking on selector`);

    cy.get(selector).click();
  }

  static clickOnUserSelector(userEmail: string, selector: string): void {
    cy.allure().logStep(`clicking on user: ${userEmail}`);

    UsersPage.getRowByEmail(userEmail).find(selector).click();
  }

  static verifyUserStatusToggle(userEmail: string, isEnabled: boolean): void {
    const expectedText = isEnabled ? 'Enabled' : 'Disabled';
    cy.allure().logStep(`verifying user: ${userEmail} is ${expectedText}`);

    UsersPage.getRowByEmail(userEmail).find(userPageSelectors.statusLabelText).should('contain.text', expectedText);
  }

  static clearStatusFilterIfNeeded(): void {
    cy.get(userPageSelectors.openStatusFilter)
      .invoke('hasClass', 'ta-co-users-filter__active')
      .then((isFilterActive: boolean) => {
        cy.allure().logStep(`status filter is ${isFilterActive ? 'active, unchecking' : 'not active'} `);

        if (isFilterActive) {
          UsersPage.clickOn(userPageSelectors.openStatusFilter);
          cy.get(userPageSelectors.filterCheckboxesList).find(userPageSelectors.checkedCheckbox).click();
        }
      });
  }

  static verifySelectorExist(selector: string): void {
    cy.allure().logStep(`verifying modal opened selector`);

    cy.get(selector).should('exist');
  }

  static waitFor(apiWait: string): void {
    cy.allure().logStep(`waiting for api ${apiWait}`);

    cy.wait(apiWait);
  }

  static waitForAccessModalLoad(): void {
    cy.allure().logStep(`waiting for 2 api calls`);

    cy.wait('@apiUsersPermissions');

    cy.wait('@apiIsUserAllowed');
  }

  static verifyPermissionActive(userEmail: string, permissionIndex: number, isActive: boolean): void {
    const clause = isActive ? 'have.class' : 'not.have.class';
    cy.allure().logStep(`verifying user has ${isActive ? '' : 'no'} permission`);

    UsersPage.getRowByEmail(userEmail)
      .find(userPageSelectors.accessColumn)
      .find(formatStr(userPageSelectors.permissionIcon, permissionIndex.toString()))
      .should(clause, userPageSelectors.permissionIconActive);
  }

  static typeInColumn(userEmail: string, selector: string, content: string): void {
    cy.allure().logStep(`typing in selector column`);

    UsersPage.getRowByEmail(userEmail).find(selector).type(content);
  }

  static clearInSelector(userEmail: string, selector: string): void {
    cy.allure().logStep(`typing in selector column`);

    UsersPage.getRowByEmail(userEmail).find(selector).clear();
  }

  static verifySelectorContent(userEmail: string, selector: string, content: string): void {
    cy.allure().logStep(`verifying email selector content`);

    UsersPage.getRowByEmail(userEmail).find(selector).should('contain.text', content);
  }

  static testCustomDropDownColumn({ columnSelector, userA, userB, textToType }: ColumnTestParams): void {
    UsersPage.typeInColumn(userA, columnSelector, textToType);
    UsersPage.clickOn(userPageSelectors.addOptionCombo);
    UsersPage.verifySelectorContent(userA, columnSelector, textToType);

    UsersPage.clickOnUserSelector(userB, columnSelector);
    UsersPage.clickOn(formatStr(userPageSelectors.dropDownSelection, textToType));
    UsersPage.verifySelectorContent(userB, columnSelector, textToType);
  }

  static cleanupTestDropDownColumn({ columnSelector, userA, userB, textToType: clearText }: ColumnTestParams): void {
    UsersPage.clickOnUserSelector(userA, columnSelector);
    UsersPage.selectUserInDropDown(clearText);
    UsersPage.clickOnUserSelector(userB, columnSelector);
    UsersPage.selectUserInDropDown(clearText);
  }

  static testEditableTextColumn(userEmail: string, columnSelector: string, textCheck: string): void {
    const inputSelector = columnSelector + ' input';

    UsersPage.typeInColumn(userEmail, columnSelector, textCheck);
    UsersPage.clickOn(userPageSelectors.looseFocus);
    UsersPage.verifySelectorContent(userEmail, columnSelector, textCheck);

    UsersPage.clickOnUserSelector(userEmail, columnSelector);
    UsersPage.clearInSelector(userEmail, inputSelector);
    UsersPage.clickOn(userPageSelectors.looseFocus);
  }

  static modifyAccessModalPermissions(userEmail: string, accessColumn: string, permissionItem: string): void {
    UsersPage.clickOnUserSelector(userEmail, accessColumn);
    UsersPage.waitForAccessModalLoad();

    UsersPage.verifySelectorExist(userPageSelectors.accessModal);
    UsersPage.clickOn(formatStr(permissionItem, '1'));
    UsersPage.waitFor(apiWait.USERS_POST_PERMISSIONS);

    UsersPage.clickOn(formatStr(permissionItem, '3'));
    UsersPage.waitFor(apiWait.USERS_POST_PERMISSIONS);
  }

  static verifyPermissionsItems(userEmail: string, permissionItems: { index: number; enabled: boolean }[]): void {
    permissionItems.forEach((item) => {
      UsersPage.verifyPermissionActive(userEmail, item.index, item.enabled);
    });
  }

  static addUser(token: string, user: { email: string; givenName: string; familyName: string }) {
    Logs.logToCypressAndAllure(`*** addUser ${user}`);
    return cy
      .request({
        method: HttpRequest.Post,
        url: '/api/admin/users/bulk',
        headers: {
          Authorization: token
        },
        body: user,
        retryOnStatusCodeFailure: true
      })
      .then(({ body }) => {
        return body;
      });
  }
}
