// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
import 'cypress-file-upload';

import { arrayBufferToBase64 } from './../util/helper-functions'
import * as moment from 'moment'

const username = Cypress.env('username');
const password = Cypress.env('password');
const hostUrl = Cypress.env('hosturl');
const appLocation = Cypress.env('appLocation');
const longerCommandTimeout = Cypress.env('longerCommandTimeout')
const site_id_SASJS = Cypress.env('site_id_SASJS')

Cypress.Commands.add('isLoggedIn', (callback: (exist: boolean) => void) => {
  cy.get('body').then($body => {
    if ($body.find(".nav-tree").length > 0) {
      if (callback) callback(true)
    } else {
      if (callback) callback(false)
    }
  })
})

Cypress.Commands.add('loginAndUpdateValidKey', (forceLicenceKey: boolean = false) => {
  cy.visit(hostUrl + appLocation);

  cy.wait(2000)

  cy.get('body').then($body =>{
    const usernameInput = $body.find("input.username")[0]

    if (usernameInput && !Cypress.dom.isHidden(usernameInput)) {
      cy.get('input.username').type(username);
      cy.get('input.password').type(password);

      cy.get('.login-group button').click()
    }

    cy.get('.app-loading', {timeout: longerCommandTimeout}).should('not.exist').then(() => {
      cy.wait(2000)

      if ($body.find(".nav-tree").length > 0) {
        /**
       * If licence key is already working, then skip rest of the function
       */
        return logout(() => {
          return
        })
      } else{
        const keyData = {
          valid_until: moment().add(20, 'day').format('YYYY-MM-DD'),
          number_of_users: 10,
          hot_license_key: '',
          site_id: '',
          demo: false
        }

        return generateKeys(keyData.valid_until, keyData.number_of_users, keyData.hot_license_key, keyData.demo, (keysGen: any) => {
          return acceptTermsIfPresented((result: boolean) => {
            if (result) {
              cy.wait(20000)
            }

            if (!forceLicenceKey) {
              return logout(() => {
                return
              })
            } else {
              return updateLicenseKeyQuick(keysGen, () => {
                cy.wait(25000)
                return acceptTermsIfPresented((result: boolean) => {
                  if (result) {
                    cy.wait(20000)
                  }
                  return logout(() => {
                    return
                  })
                })
              })
            }
          })
        })
      }
    })
  });
});

const logout = (callback?: any) => {
  cy.get('.header-actions .dropdown-toggle').click().then(() => {
    cy.get('.header-actions .dropdown-menu > .separator').next().click().then(() => {
      if (callback) callback()
    })
  })
}

const updateLicenseKeyQuick = (keys: any, callback: any) => {
  isLicensingPage((result: boolean) => {
    if (!result) {
      visitPage('licensing/update')
      cy.wait(2000)
    }
    inputLicenseKeyPage(keys.licenseKey, keys.activationKey)

    callback()
  })
}

const acceptTermsIfPresented = (callback?: any) => {
  cy.url().then((url: string) => {
    if (url.includes('licensing/register')) {
      cy.get('.card-block').scrollTo('bottom').then(() => {
        cy.get('#checkbox1').click().then(() => {
          if (callback) callback(true)
        })
      })
    } else {
      if (callback) callback(false)
    }
  })
}

const isLicensingPage = (callback: any) => {
  cy.url().then((url: string) => {
    callback(url.includes('licensing') && !url.includes('licensing/register'))
  })
}

const inputLicenseKeyPage = (licenseKey: string, activationKey: string) => {
  cy.get('button').contains('Paste licence').click()
  cy.get('.license-key-form textarea', {timeout: longerCommandTimeout}).invoke('val', licenseKey).trigger('input').should('not.be.undefined')
  cy.get('.activation-key-form textarea', {timeout: longerCommandTimeout}).invoke('val', activationKey).trigger('input').should('not.be.undefined')
  cy.get('button.apply-keys').click()
}

const visitPage = (url: string) => {
    cy.visit(`${hostUrl}${appLocation}/#/${url}`);
}
const generateKeys = async (valid_until: string, users_allowed: number, hot_license_key: string, demo: boolean, resultCallback?: any) => {
  let keyPair = await window.crypto.subtle.generateKey({
    name: "RSA-OAEP",
    modulusLength: 2024,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: "SHA-256"
    },
    true,
    ["encrypt", "decrypt"]
  )

  let licenseData = {
    valid_until: valid_until,
    users_allowed: users_allowed,
    hot_license_key: hot_license_key,
    site_id: site_id_SASJS,
    demo: demo
  }

  console.log('License data', licenseData)

  let encoded = new TextEncoder().encode(JSON.stringify(licenseData))

  console.log(encoded)

  let cipher = await window.crypto.subtle.encrypt(
    {
      name: "RSA-OAEP"
    },
    keyPair.publicKey,
    encoded
  ).then((value) => {
    return value
  }, (err) => {
    console.log('Encrpyt error', err)
  })

  if (!cipher) {
    alert('Encryptin keys failed')
    throw new Error('Encryptin keys failed')
  }

  let privateKeyBytes = await window.crypto.subtle.exportKey('pkcs8', keyPair.privateKey)

  let activationKey = await arrayBufferToBase64(privateKeyBytes)
  let licenseKey = await arrayBufferToBase64(cipher)

  if (resultCallback) resultCallback({
    activationKey,
    licenseKey
  })
}