import 'cypress-localstorage-commands'
import 'cypress-file-upload'
import { version as systemVersion } from '../../../system-base/package.json'
import { version as wmsVersion } from '../../package.json'

// logs in as tester user and disables release note popup
Cypress.Commands.add('login', (email, password) => {
  cy.session([email, password], () => {
    cy.visit('/auth/signin')
    cy.get('input.mdc-text-field__input[type="email"]').click().type(email, { force: true })
    cy.get('input.mdc-text-field__input[type="password"]').click().type(password, { force: true })
    cy.get('form#form')
      .submit()
      .then(() => {
        // release note localStorage popup sometimes uses version number from system-base package.json
        // sometimes from operato-wms package.json
        // version numbers aren’t always the same
        window.localStorage.setItem(`release-note.${wmsVersion}`, 'true')
        window.localStorage.setItem(`release-note.${systemVersion}`, 'true')
      })
    cy.url().should('include', '/auth/checkin?redirect_to=%2F')
  })
})

// give 15 seconds for grist to populate
Cypress.Commands.add('waitGristLoad', () => {
  cy.get('data-grid-footer').within(() => {
    cy.contains('span', 'total 0 records.', { timeout: 30000 }).should('not.exist')
  })
})

Cypress.Commands.add('waitOneRecord', () => {
  cy.get('data-grid-footer').within(() => {
    cy.get('span')
      .invoke('text')
      .should('match', /total 1 records/)
  })
})

Cypress.Commands.add('toastContains', string => {
  cy.get('ox-snack-bar').within(() => {
    cy.get('span').should('contain.text', string).and('be.visible')
  })
})

Cypress.Commands.add('searchGrist', () => {
  cy.get('form[class="search-form"]').find('mwc-icon[search]').click()
})

Cypress.Commands.add('addTransportDriver', data => {
  cy.get('things-app').within(() => {
    cy.get(
      'mwc-icon[style="font-size: var(--grid-record-fontsize);vertical-align: middle; color: var(--grid-record-dirty-color)"]'
    )
      .parent()
      .parent()
      .next()
      .next()
      .next()
      .as('finalRow')

    cy.get('@finalRow').dblclick().find('input[type=text]').type(data.name, { force: true }).click({ force: true })
    cy.get('@finalRow')
      .next()
      .dblclick()
      .find('input[type=text]')
      .type(data.description, { force: true })
      .click({ force: true })
    cy.get('@finalRow')
      .next()
      .next()
      .dblclick()
      .find('input[type=text]')
      .type(data['driver code'], { force: true })
      .click({ force: true })
  })
})

Cypress.Commands.add('addTransportVehicle', vehicleData => {
  cy.get('things-app').within(() => {
    cy.get(
      'mwc-icon[style="font-size: var(--grid-record-fontsize);vertical-align: middle; color: var(--grid-record-dirty-color)"]'
    )
      .parent()
      .parent()
      .next()
      .next()
      .next()
      .as('finalRow')

    cy.get('@finalRow')
      .dblclick()
      .find('input[type=text]')
      .type(vehicleData.regNumber, { force: true })
      .click({ force: true })
    cy.get('@finalRow')
      .next()
      .dblclick()
      .find('input[type=text]')
      .type(vehicleData.description, { force: true })
      .click({ force: true })
    cy.get('@finalRow')
      .next()
      .next()
      .dblclick()
      .find('input[type=text]')
      .type(vehicleData.size, { force: true })
      .click({ force: true })
    cy.get('@finalRow')
      .next()
      .next()
      .next()
      .dblclick()
      .find('input[type=text]')
      .type(vehicleData.status, { force: true })
      .click({ force: true })
  })
})

Cypress.Commands.add('clickSaveButton', () => {
  cy.get('button#button.mdc-button.mdc-button--raised[aria-label="save"]').click()
})

Cypress.Commands.add('clickDeleteButton', () => {
  cy.get('button#button.mdc-button.mdc-button--raised[aria-label="delete"]').click()
})

Cypress.Commands.add('clickPopupButton', action => {
  cy.get('button.swal2-confirm.swal2-styled').contains(action).click()
})

Cypress.Commands.add('checkGristRecords', dataNames => {
  cy.get('things-app').within(() => {
    for (const dataName of dataNames) {
      cy.get('span')
        .contains(dataName)
        .should('exist')
        .parent()
        .prev()
        .find('input[type="checkbox"]')
        .check({ force: true })
    }
  })
})

Cypress.Commands.add('checkWarehouseRecords', dataNames => {
  cy.get('things-app').within(() => {
    for (const dataName of dataNames) {
      cy.get('span')
        .contains(dataName)
        .should('exist')
        .parent()
        .prev()
        .prev()
        .find('input[type="checkbox"]')
        .check({ force: true })
    }
  })
})

// finds data name in list then targets that specific row for checking
// against provided data
Cypress.Commands.add('recordExists', data => {
  cy.get('data-grid-body').within(() => {
    cy.contains('span', data.name).parent().prev().nextUntil('data-grid-field[gutter]').as('targetRow')
    for (const [key, value] of Object.entries(data)) {
      cy.get('@targetRow').shadow().should('contain.text', value)
    }
  })
})

Cypress.Commands.add('vehicleExists', data => {
  cy.get('data-grid-body').within(() => {
    cy.contains('span', data.regNumber).parent().prev().nextUntil('data-grid-field[gutter]').as('targetRow')
    for (const [key, value] of Object.entries(data)) {
      cy.get('@targetRow').shadow().should('contain.text', value)
    }
  })
})

Cypress.Commands.add('dataNotExists', dataName => {
  cy.get('data-grid-body').within(() => {
    for (const [key, value] of Object.entries(dataName)) {
      cy.get('data-grid-field').shadow().should('not.contain.text', value)
    }
  })
})

Cypress.Commands.add('warehouseNotExists', data => {
  cy.contains('span', data.name).should('not.exist')
})

Cypress.Commands.add('warehouseNotAdded', data => {
  cy.contains('span', data.name).parent().prev().nextUntil('data-grid-field[gutter]').as('targetRow')
  cy.get('@targetRow').should('not.contain.text', 'Tester')
})

Cypress.Commands.add('palletExists', fixture => {
  cy.get('data-grid-field').shadow().should('contain.text', fixture['ref no.'])
})

Cypress.Commands.add('palletNotExists', fixture => {
  cy.get('data-grid-field').shadow().should('not.contain.text', fixture['ref no.'])
})

Cypress.Commands.add('palletPopup', data => {
  cy.get('object-selector').within(() => {
    cy.contains('span', 'total 0 records.', { timeout: 10000 }).should('not.exist')
    cy.get('input[name="name"]').type(`${data}{enter}`, { force: true })
    cy.contains('span', 'total 1 records.', { timeout: 10000 }).should('exist')
    cy.get('span').contains(data).parent().prev().find('input[type="radio"]').check()
    cy.get('mwc-button').contains('confirm').click()
  })
})

// fill in pallet page grist fields based on keys given in the data parameter
Cypress.Commands.add('addPallet', data => {
  cy.get(
    'mwc-icon[style="font-size: var(--grid-record-fontsize);vertical-align: middle; color: var(--grid-record-dirty-color)"]'
  )
    .parent()
    .parent()
    .nextAll()
    .as('finalRow')

  const targetIndexes = {}
  for (const [key, value] of Object.entries(data)) {
    cy.get('data-grid-header').within(() => {
      cy.contains('div', key)
        .invoke('index')
        .then(i => (targetIndexes[i] = value))
    })
  }

  cy.get('@finalRow').each(($elem, index, $elems) => {
    // + 1 since nextAll() does not include the initial get() element
    switch (index + 1) {
      case 3:
        if (!(3 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(targetIndexes[3], { force: true }).type('{enter}')
        break
      case 4:
        if (!(4 in targetIndexes)) break
        cy.wrap($elem).dblclick().click()
        cy.palletPopup(targetIndexes[4])
        break
      case 5:
        if (!(5 in targetIndexes)) break
        cy.wrap($elem).dblclick().click()
        cy.palletPopup(targetIndexes[5])
        break
      case 6:
        if (!(6 in targetIndexes)) break
        cy.wrap($elem).dblclick().click().find('select').select(targetIndexes[6], { force: true }).type('{enter}')
        break
    }
  })
})

Cypress.Commands.add('addWarehouse', data => {
  cy.get('gutter-dirty-element[value="+"]').last().parent().nextAll().as('finalRow')

  const targetIndexes = {}
  for (const [key, value] of Object.entries(data)) {
    cy.get('data-grid-header').within(() => {
      cy.contains('div', key)
        .invoke('index')
        .then(i => (targetIndexes[i] = value))
    })
  }

  cy.get('@finalRow').each(($elem, index, $elems) => {
    // + 1 since nextAll() does not include the initial get() element
    switch (index + 1) {
      case 4:
        if (!(4 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(`${targetIndexes[4]}{enter}`, { force: true })
        break
      case 5:
        if (!(5 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(`${targetIndexes[5]}{enter}`, { force: true })
        break
      case 6:
        if (!(6 in targetIndexes)) break
        cy.wrap($elem).dblclick().click().find('select').select(`${targetIndexes[6]}{enter}`, { force: true })
        break
    }
  })
})

Cypress.Commands.add('editImport', data => {
  const targetIndexes = {}
  for (const [key, value] of Object.entries(data)) {
    cy.get('data-grid-header').within(() => {
      cy.contains('div', key)
        .invoke('index')
        .then(i => (targetIndexes[i] = value))
    })
  }

  cy.get('@finalRow').each(($elem, index, $elems) => {
    // + 1 since nextAll() does not include the initial get() element
    switch (index + 1) {
      case 4:
        if (!(4 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(targetIndexes[4], { force: true }).type('{enter}')
        break
      case 5:
        if (!(4 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(targetIndexes[5], { force: true }).type('{enter}')
        break
      case 6:
        if (!(6 in targetIndexes)) break
        cy.wrap($elem).dblclick().click().find('select').select(targetIndexes[6], { force: true }).type('{enter}')
        break
    }
  })
})

Cypress.Commands.add('editField', (oldVal, newVal) => {
  cy.get('span')
    .contains(oldVal)
    .parent()
    .dblclick()
    .find('input[type="text"]')
    .clear({ force: true })
    .type(newVal, { force: true })
})

Cypress.Commands.add('importGrist', filepath => {
  cy.get('mwc-icon').contains('open_in_browser').click()
  cy.get('input[type="file"]').invoke('removeClass', 'file_input_hidden').attachFile(filepath)
})

Cypress.Commands.add('importAllPopup', () => {
  cy.get('import-pop-up').within(() => {
    cy.get('data-grid-header').find('input[type="checkbox"]').check()
    cy.get('mwc-button').contains('import').click()
  })
  cy.clickPopupButton('import')
})

Cypress.Commands.add('exportGrist', (path, fileTypes, fileName) => {
  const downloadsFolder = Cypress.config('downloadsFolder')
  cy.get('mwc-icon').contains('save_alt').click()
  for (const fileType of fileTypes) {
    cy.get('export-overlay-template').find('span').contains(fileType).click()
    cy.readFile(path.join(downloadsFolder, `${fileName}.${fileType}`)).should('exist')
  }
})

Cypress.Commands.add('addLocation', data => {
  cy.get('gutter-dirty-element[value="+"]').last().parent().nextAll().as('finalRow')

  const targetIndexes = {}
  for (const [key, value] of Object.entries(data)) {
    cy.get('data-grid-header').within(() => {
      cy.contains('div', key)
        .invoke('index')
        .then(i => (targetIndexes[i] = value))
    })
  }

  cy.get('@finalRow').each(($elem, index, $elems) => {
    // + 1 since nextAll() does not include the initial get() element
    switch (index + 1) {
      case 3:
        if (!(3 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(targetIndexes[3], { force: true }).type('{enter}')
        break
      case 4:
        if (!(4 in targetIndexes)) break
        cy.wrap($elem).dblclick().click().find('select').select(targetIndexes[4], { force: true }).type('{enter}')
        break
      case 5:
        if (!(5 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(targetIndexes[5], { force: true }).type('{enter}')
        break
      case 6:
        if (!(6 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(targetIndexes[6], { force: true }).type('{enter}')
        break
      case 7:
        if (!(7 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(targetIndexes[7], { force: true }).type('{enter}')
        break
      case 8:
        if (!(8 in targetIndexes)) break
        cy.wrap($elem).dblclick().find('input[type=text]').type(targetIndexes[8], { force: true }).type('{enter}')
        break
      case 9:
        if (!(9 in targetIndexes)) break
        cy.wrap($elem).dblclick().click().find('select').select(targetIndexes[9], { force: true }).type('{enter}')
        break
    }
  })
})

Cypress.Commands.add('checkLocationRecords', dataNames => {
  cy.get('things-app').within(() => {
    for (const dataName of dataNames) {
      cy.get('span')
        .contains(dataName)
        .should('exist')
        .parent()
        .prev()
        .prev()
        .find('input[type="checkbox"]')
        .check({ force: true })
    }
  })
})

// // use api to login instead of session
// Cypress.Commands.add('login', () => {
//   cy.request({
//     method: 'POST',
//     url: '/auth/signin',
//     body: {
//       email: 'wliang@hatiolab.com',
//       password: '1234'
//     }
//   }).then(res => {
//     cy.log(res.body)
//   })
