
/**
 * These functions require the modules {@link module../pages/ecas/ecas-login}.
 * {@link module../pages/ecas/ecas-logout}.
 * {@link module../pages/ecas/ecas-new-password}.
 * {@link module../core/utils}.
 * {@link module../core/services/vault-service}.
 *
 * @requires ../pages/ecas/ecas-login
 * @requires ../pages/ecas/ecas-logout
 * @requires ../pages/ecas/ecas-new-password
 * @requires ../core/utils
 * @requires ../core/services/vault-service
 */
import EcasLoginPage from '../pages/ecas/ecas-login.js'
import EcasLogoutPage from '../pages/ecas/ecas-logout.js'
import EcasNewPasswordPage from '../pages/ecas/ecas-new-password.js'
import * as utils from '../core/utils.js'
import VaultService from '../core/services/vault-service.js'

/**
   * This function log in to ECAS page.
   * @async
   * @param {string} user - username
   * @param {string} url - base environment url
   * @param {boolean} skipNav -if true skips navigation to ecas login
   * @param {number} loginLoadersTimeout - default loading timeout sets to 15 sec
   */

export async function ecasLogIn( user, url=null, skipNav = false, loginLoadersTimeout=15000 ) {
  // Check if testUserData and user password is set in config
  let testUserData = browser.config.testUserData;
  if (!testUserData[user]){
    throw new Error('User not in testUserData');
  } else if (!testUserData[user]['password']){
    throw new Error('No password set for user ' + user + ' in testUserData');
  }
  browser.config.loggedInUser = user;
  let ecasLoginPage = new EcasLoginPage();
  // Skip navigation if param skipNav is set to true
  if (!skipNav){
    if (url) {
      await ecasLoginPage.open(url);
    } else {
      await ecasLoginPage.open(browser.config.baseUrl);
    }
    await browser.deductedWait(2000);
  }
  await browser.waitUntil( () => browser.execute(() => document.readyState === 'complete'), { timeout: 40 * 1000, timeoutMsg: 'Open new url: '+url+'  not complete in 40s' });
  await (await $(ecasLoginPage.mainHeaderBrandingTitle)).waitForExist({ timeout: 10000, reverse:false, timeoutMsg: "Eu-login Branding Title did not appear in 10 seconds", interval: 200 });
  let userLink = await $(ecasLoginPage.signWithAnotherUserLink);
  if (await userLink.isExisting()) {
      await userLink.click();
  }
  // Input ECAS Login page
  let userInput = await $(ecasLoginPage.userInput);
  await userInput.waitForDisplayed({timeout:5000, reverse:false, timeoutMsg:'Ecas user input did not appear', interval:100});
  await userInput.clearValue();
  await userInput.setValue(user);
  await expect(await $(ecasLoginPage.userSubmit)).toBeClickable({ wait: 3000, message: '<Ecas login> User submit button is not clickable.' });
  await (await $(ecasLoginPage.userSubmit)).click();
  await browser.pause(500);

  // Should go to password page
  await this.setVerificationMethod();
  let passwordInput = await $(ecasLoginPage.passwordInput);
  await passwordInput.waitForDisplayed({timeout:10000, reverse:false, timeoutMsg:'Ecas password input did not appear', interval:100});
  await passwordInput.setValue(testUserData[user]['password']);
  await (await $(ecasLoginPage.passwordSubmit)).click();
  try {
    await browser.waitUntil( () => browser.execute(() => document.readyState === 'complete'), { timeout: 5000, timeoutMsg: 'Start loading mwp not complete in 5s' });
  } catch (error) {
     //ignore
  }
  // await waitForEcasLoginLoaders(loginLoadersTimeout);

  // Set new password if required
  let ecasNewPasswordPage = new EcasNewPasswordPage();
  let isNewPasswordInputExisting;
  try {
    let newPasswordInput = await $(ecasNewPasswordPage.newPasswordInput);
    await newPasswordInput.waitForDisplayed({timeout:2000, reverse:false, timeoutMsg:'Ecas new user password did not appear', interval:100});
    isNewPasswordInputExisting = true;
  } catch (error) {
    isNewPasswordInputExisting = false;
  }
  if (isNewPasswordInputExisting) {
    console.log('Current user password will expire soon ecas modal to set new password displayed')
    let newPwd = await getNewUserPassword(user);
    await (await $(ecasNewPasswordPage.newPasswordInput)).click();
    await (await $(ecasNewPasswordPage.newPasswordInput)).setValue(newPwd);
    await (await $(ecasNewPasswordPage.passwordConfirmationInput)).click();
    await (await $(ecasNewPasswordPage.passwordConfirmationInput)).setValue(newPwd);
    await (await $(ecasNewPasswordPage.changePasswordSubmit)).click();
    try {
      await (await $(ecasNewPasswordPage.changePasswordSubmit)).waitForDisplayed({timeout:2000, reverse:true, timeoutMsg:'Ecas new user password submit password still displayed', interval:100});
      await waitForEcasLoginLoaders(loginLoadersTimeout);
      await updateUserPassword(user, newPwd);
    } catch (error) {
      throw new Error(error);
    }finally{
      let continueWithoutSaving = await $(ecasNewPasswordPage.continueWithoutPasswordChangeSubmit);
      if(await continueWithoutSaving.isExisting()){
        console.log('New password was not saved will continue without saving')
  
        await browser.puppScreenshot();
        await continueWithoutSaving.click();
        await continueWithoutSaving.waitForDisplayed({timeout:2000, reverse:true, timeoutMsg:'Ecas new user password continue without password change still displayed', interval:100});
      }
    }
  }
}

/**
   * This function log out from ECAS page.
   * @async
   */
export async function ecasLogOut() {
  let ecasLogoutPage = new EcasLogoutPage();
  await expect(await $(ecasLogoutPage.logoutTitle)).toBeExisting({wait:15000, message:'ECAS Logout page title is not existing on page.'});
  await expect(await $(ecasLogoutPage.logoutTitle)).toBeDisplayed({wait:15000, message:'ECAS Logout page title is not visible on page.'});
  // Redirect to ECAS page
  await expect(await browser.getUrl()).toContain('/logout', { timeout: 5000, timeoutMsg: 'Could not navigate to page ECAS logout in 5000ms.' });
  // Logout from ECAS page
  let ecasLogoutBtn = await $(ecasLogoutPage.logMeOut);
  await ecasLogoutBtn.scrollIntoView();
  await ecasLogoutBtn.waitForDisplayed({timeout:10000, timeoutMsg:'ECAS Logout button is not visible on page.', interval:100});
  await ecasLogoutBtn.click();
  await browser.deductedWait(1000);
  await browser.deleteAllCookies();
}

/**
 * Opens the Ecas LogOut page and performs the log out action
 * @async
 * @param {string} logoutUrl
 */
 export async function ecasLogOutUsingLogoutLink(userEnvironment) {
  let logOutLinkProd = 'https://ecas.ec.europa.eu/cas/logout';
  let logOutLinkAcceptance = 'https://ecas.acceptance.ec.europa.eu/cas/logout';
  let environmentLogoutLink;
  if(userEnvironment === 'PROD') {
    environmentLogoutLink = logOutLinkProd;
  } else if (userEnvironment === 'ACC') {
    environmentLogoutLink = logOutLinkAcceptance;
  } else {
    throw new Error('For the user environment ' + userEnvironment + ' logout link is not defined.');
  }
  await browser.url(environmentLogoutLink);
  let ecasLogoutPage = new EcasLogoutPage();
  await expect(await $(ecasLogoutPage.logoutTitle)).toBeExisting({wait:15000, message:'ECAS Logout page title is not existing on page.'});
  await expect(await $(ecasLogoutPage.logoutTitle)).toBeDisplayed({wait:15000, message:'ECAS Logout page title is not visible on page.'});
  let ecasLogoutBtn = await $(ecasLogoutPage.logMeOut);
  if (await ecasLogoutBtn.isExisting()) {
    await ecasLogoutBtn.scrollIntoView();
    await ecasLogoutBtn.waitForDisplayed({ timeout: 10000, timeoutMsg: 'ECAS Logout button is not visible on page.', interval: 100 });
    await ecasLogoutBtn.click();
    await browser.deductedWait(1000);
    await expect(ecasLogoutBtn).not.toBeDisplayed({ wait: 5000, message: 'Logout button is still displayed' });
  } else {
    let loggedOutMessage = await $(ecasLogoutPage.logoutWarningText('You have logged out of EU Login.'));
    await expect(loggedOutMessage).toBeDisplayed({ wait: 5000, message: 'Logged out information message is not existing' });
  }
  await browser.deleteAllCookies();
}

/**
   * This function update user password.
   * @async
   * @param {string} user - username
   * @param {string} password - user password
   */
export async function updateUserPassword(user, password) {
  let vault = new VaultService(browser.config);
  browser.config.testUserData[user]['password'] = password;
  let userPath = browser.config.vaultConfig.testusersPath + browser.config.userenv.toLowerCase()
  await vault.createUpdateSecret(userPath, user, browser.config.testUserData[user]);
}

/**
   * This function get new user password
   * @async
   * @param {string} user - username
   * @returns {string} - returns new password
   */
async function getNewUserPassword(user) {
    let oldPwd = browser.config.testUserData[user]['password'];
    let newPwd;
    if (oldPwd.includes('_')) {
        let oldPwdArr = oldPwd.split('_');
        let oldPwdIncrement = oldPwdArr[oldPwdArr.length - 1];
        if (!isNaN(oldPwdIncrement)) {
            let newPwdIncrement = parseInt(oldPwdIncrement, 10) + 1;
            oldPwdArr[oldPwdArr.length - 1] = newPwdIncrement.toString();
            newPwd = oldPwdArr.join('_');
        }
    }
    if (!newPwd) {
        newPwd = utils.getRandomdString(8);
    }
    return newPwd;
}

/**
   * This function checks 5 times that Loginloader is not displayed.
   * @async
   * @param {number} timeout - Loading timeout
   * @param {boolean} extraWait -if true wait 1 sec
   */
export async function waitForEcasLoginLoaders(timeout, extraWait=true) {
    let ecasLoginPage = new EcasLoginPage();
    let start = new Date().getTime();
    if (extraWait) {
        await browser.pause(1000);
    }
    try {
        // Loginloader does multiple redirects so we need to redo the check multiple times
        let retries = 5;
        while (retries > 0) {
            let passedTime = new Date().getTime() - start;
            await (await $(ecasLoginPage.redirectProgressImage)).waitForDisplayed({timeout:timeout - passedTime, reverse:true, timeoutMsg:'TimeoutError', interval:100});
            await (await $(ecasLoginPage.redirectFallbackLink)).waitForDisplayed({timeout:timeout - passedTime, reverse:true, timeoutMsg:'TimeoutError', interval:100});
            await browser.pause(200);
            retries--;
        }
    } catch (error) {
        // Only fail test for timeout, errors on loader like StaleElementReferenceError are not to fail the test
        if (error.message === 'TimeoutError') {
            let passedTime = new Date().getTime() - start;
            throw new Error('Ecas Login Loaders took too long, test timed out after ' + passedTime + 'ms');
        }
    }
}

export async function setVerificationMethod(verification = 'Password'){
  let ecasLoginPage = new EcasLoginPage();
  let verificationMethod = await ecasLoginPage.verificationMethodCO.element();
  let verificationTitle = await ecasLoginPage.verificationMethodTitleByTextCO(verification).element();
  if( await verificationMethod.isExisting() && !(await verificationTitle.isExisting())){
    await verificationMethod.click();
    let verificationOpen = await ecasLoginPage.verificationMethodOpenCO.element();
    await expect(verificationOpen).toBeExisting({wait: 2000, message: 'Verification modal not open after click'});
    let verificationOption = await ecasLoginPage.verificationOptionByTextCO(verification).element();
    await expect(verificationOption).toBeDisplayed({wait: 2000, message: 'Verification method '+verification+' not displayed'});
    await verificationOption.scrollIntoView();
    await verificationOption.click();
    await expect(verificationOpen).not.toBeExisting({wait:2000, message: 'Verification modal still open after setting option'})
    let verificationTitlePassord = await ecasLoginPage.verificationMethodPasswordCO.element();
    await expect(verificationTitlePassord).toBeDisplayed({wait:2000, message: 'verification method not set to :' + verification});
  }
}
/**
   * This function clears session and local storage
   * @async
   */
export async function clearLocalStorage() {
  await browser.execute('window.sessionStorage.clear();');
  await browser.execute('window.localStorage.clear();');
}
