import { cloneDeep } from 'lodash-es'

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 serverType = Cypress.env('serverType')
const libraryToOpenIncludes = Cypress.env(`libraryToOpenIncludes_${serverType}`)

context('editor tests: ', function () {
  this.beforeAll(() => {
    cy.visit(`${hostUrl}/SASLogon/logout`)
    cy.loginAndUpdateValidKey(true)
  })

  this.beforeEach(() => {
    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()
      }
    })

    visitPage('home')
  })

  it('1 | Add one viewbox', (done) => {
    const viewbox_table = 'mpe_audit'
    const columns = ['LOAD_REF', 'LIBREF', 'DSN', 'KEY_HASH', 'TGTVAR_NM']

    openTableFromTree(libraryToOpenIncludes, 'mpe_x_test')

    cy.get('.viewbox-open').click()
    openTableFromViewboxTree(libraryToOpenIncludes, [viewbox_table])

    cy.get('.open-viewbox').then((viewboxNodes: any) => {
      for (let viewboxNode of viewboxNodes) {
        if (!viewboxNode.innerText.toLowerCase().includes(viewbox_table)) {
          return
        }

        checkColumns(columns, () => {
          done()
        })
      }
    })
  })

  it('2 | Add two viewboxes', (done) => {
    const viewboxes = [
      {
        viewbox_table: 'mpe_audit',
        columns: ['LOAD_REF', 'LIBREF', 'DSN', 'KEY_HASH', 'TGTVAR_NM']
      },
      {
        viewbox_table: 'mpe_alerts',
        columns: [
          'TX_FROM',
          'ALERT_EVENT',
          'ALERT_LIB',
          'ALERT_DS',
          'ALERT_USER'
        ]
      }
    ]

    openTableFromTree(libraryToOpenIncludes, 'mpe_x_test')
    cy.get('.viewbox-open').click()
    openTableFromViewboxTree(
      libraryToOpenIncludes,
      viewboxes.map((viewbox) => viewbox.viewbox_table)
    )
    cy.get('.open-viewbox').then((viewboxNodes: any) => {
      let found = 0

      for (let viewboxNode of viewboxNodes) {
        for (let viewbox of viewboxes) {
          if (
            viewboxNode.innerText.toLowerCase().includes(viewbox.viewbox_table)
          )
            found++
        }
      }

      if (found < viewboxes.length) return

      cy.get('.viewboxes-container .viewbox', { withinSubject: null }).then(
        (viewboxNodes: any) => {
          for (let viewboxNode of viewboxNodes) {
            cy.get(viewboxNode).within(() => {
              cy.get('.table-title').then((tableTitle) => {
                const title = tableTitle[0].innerText
                const viewbox = viewboxes.find((vb) =>
                  title.toLowerCase().includes(vb.viewbox_table)
                )

                if (viewbox) {
                  cy.get('.ht_master.handsontable .htCore thead tr').then(
                    (viewboxColNodes: any) => {
                      let allColsHtml = viewboxColNodes[0].innerHTML

                      for (let col of viewbox?.columns) {
                        if (!allColsHtml.includes(col)) return
                      }

                      done()
                    }
                  )
                }
              })
            })
          }
        }
      )
    })
  })

  it('3 | Add viewbox, add columns', (done) => {
    const viewbox_table = 'mpe_audit'
    const columns = ['LOAD_REF', 'LIBREF', 'DSN', 'KEY_HASH', 'TGTVAR_NM']
    const additionalColumns = ['IS_PK']

    openTableFromTree(libraryToOpenIncludes, 'mpe_x_test')

    cy.get('.viewbox-open').click()
    openTableFromViewboxTree(libraryToOpenIncludes, [viewbox_table])

    cy.get('.open-viewbox').then((viewboxNodes: any) => {
      for (let viewboxNode of viewboxNodes) {
        if (!viewboxNode.innerText.toLowerCase().includes(viewbox_table)) {
          return
        }

        openViewboxConfig(viewbox_table)

        removeAllColumns()

        addColumns(additionalColumns)

        checkColumns([...columns, ...additionalColumns], () => {
          done()
        })
      }
    })
  })

  it('4 | Add viewbox, add columns and reorder', (done) => {
    const viewbox_table = 'mpe_audit'
    const columns = ['LOAD_REF', 'LIBREF', 'DSN', 'KEY_HASH', 'TGTVAR_NM']
    const additionalColumns = ['IS_PK', 'MOVE_TYPE']

    openTableFromTree(libraryToOpenIncludes, 'mpe_x_test')

    cy.get('.viewbox-open').click()
    openTableFromViewboxTree(libraryToOpenIncludes, [viewbox_table])

    cy.get('.open-viewbox').then((viewboxNodes: any) => {
      for (let viewboxNode of viewboxNodes) {
        if (!viewboxNode.innerText.toLowerCase().includes(viewbox_table)) {
          return
        }

        openViewboxConfig(viewbox_table)

        removeAllColumns()

        addColumns(additionalColumns, () => {
          cy.wait(1000)
          //reorder
          cy.get('.col-box.column-MOVE_TYPE')
            .realMouseDown({ button: 'left', position: 'center' })
            .realMouseMove(0, 10, { position: 'center' })
          cy.wait(200) // In our case, we wait 200ms cause we have animations which we are sure that take this amount of time
          cy.get('.col-box.column-IS_PK')
            .realMouseMove(0, 0, { position: 'center' })
            .realMouseUp()
          //reorder end

          cy.wait(500)

          checkColumns([...columns, ...additionalColumns.reverse()], () => {
            done()
          })
        })
      }
    })
  })

  it('5 | Add viewbox, add columns, reorder, remove column, add again', (done) => {
    const viewbox_table = 'mpe_audit'
    const columns = ['LOAD_REF', 'LIBREF', 'DSN', 'KEY_HASH', 'TGTVAR_NM']
    const additionalColumns = ['IS_PK', 'MOVE_TYPE']

    openTableFromTree(libraryToOpenIncludes, 'mpe_x_test')

    cy.get('.viewbox-open').click()
    openTableFromViewboxTree(libraryToOpenIncludes, [viewbox_table])

    cy.get('.open-viewbox').then((viewboxNodes: any) => {
      for (let viewboxNode of viewboxNodes) {
        if (!viewboxNode.innerText.toLowerCase().includes(viewbox_table)) {
          return
        }

        viewboxNode.click()

        removeAllColumns()

        addColumns(additionalColumns, () => {
          cy.wait(1000)
          //reorder
          cy.get('.col-box.column-MOVE_TYPE')
            .realMouseDown({ button: 'left', position: 'center' })
            .realMouseMove(0, 10, { position: 'center' })
          cy.wait(200) // In our case, we wait 200ms cause we have animations which we are sure that take this amount of time
          cy.get('.col-box.column-IS_PK')
            .realMouseMove(0, 0, { position: 'center' })
            .realMouseUp()
          //reorder end

          cy.wait(500)

          checkColumns([...columns, ...additionalColumns.reverse()], () => {
            const colToRemove = 'MOVE_TYPE'

            removeColumn(colToRemove)
            checkColumns(
              [
                ...columns,
                ...additionalColumns.filter((col) => col !== colToRemove)
              ],
              () => {
                addColumns([colToRemove], () => {
                  checkColumns(
                    [...columns, ...additionalColumns.reverse()],
                    () => {
                      done()
                    }
                  )
                })
              }
            )
          })
        })
      }
    })
  })

  it('6 | Add viewboxes, reload and check url restored configuration', (done) => {
    const viewboxes = [
      {
        viewbox_table: 'mpe_audit',
        columns: ['LOAD_REF', 'LIBREF', 'DSN', 'KEY_HASH', 'TGTVAR_NM'],
        additionalColumns: ['IS_PK', 'MOVE_TYPE']
      },
      {
        viewbox_table: 'mpe_alerts',
        columns: [
          'TX_FROM',
          'ALERT_EVENT',
          'ALERT_LIB',
          'ALERT_DS',
          'ALERT_USER'
        ],
        additionalColumns: ['TX_TO']
      }
    ]

    openTableFromTree(libraryToOpenIncludes, 'mpe_x_test')

    cy.get('.viewbox-open').click()
    openTableFromViewboxTree(libraryToOpenIncludes, [
      viewboxes[0].viewbox_table,
      viewboxes[1].viewbox_table
    ])

    openViewboxConfig(viewboxes[0].viewbox_table)

    cy.wait(500)

    removeAllColumns()

    addColumns(viewboxes[0].additionalColumns, () => {
      cy.wait(1000)

      if (viewboxes[0].viewbox_table === 'mpe_audit') {
        cy.get('.col-box.column-MOVE_TYPE')
          .realMouseDown({ button: 'left', position: 'center' })
          .realMouseMove(0, 10, { position: 'center' })
        cy.wait(200) // In our case, we wait 200ms cause we have animations which we are sure that take this amount of time
        cy.get('.col-box.column-IS_PK')
          .realMouseMove(0, 0, { position: 'center' })
          .realMouseUp()
      }

      cy.wait(1000)

      openViewboxConfig(viewboxes[1].viewbox_table)

      addColumns(viewboxes[1].additionalColumns, () => {
        cy.wait(1000).reload()

        let result = 0

        checkColumns(
          [
            ...viewboxes[0].columns,
            ...cloneDeep(viewboxes[0].additionalColumns.reverse())
          ],
          () => {
            result++

            if (result === 2) done()
          }
        )
        checkColumns(
          [...viewboxes[1].columns, ...viewboxes[1].additionalColumns],
          () => {
            result++

            if (result === 2) done()
          }
        )
      })
    })
  })

  // We will enable this test when we figure out how to mock filtering
  // it('7 | Add viewboxes and filter', () => {
  //   const viewboxes = ['mpe_x_test', 'mpe_validations']

  //   openTableFromTree(libraryToOpenIncludes, 'mpe_x_test')

  //   cy.get('.viewbox-open').click()
  //   openTableFromViewboxTree(libraryToOpenIncludes, viewboxes)

  //   cy.wait(1000)

  //     closeViewboxModal()

  //     cy.get('.viewboxes-container .viewbox', { withinSubject: null }).then(
  //       (viewboxNodes: any) => {
  //         for (let viewboxNode of viewboxNodes) {
  //           cy.get(viewboxNode).within(() => {
  //             cy.get('.table-title').then((title: any) => {
  //               cy.get('.hot-spinner')
  //                 .should('not.exist')
  //                 .then(() => {
  //                   cy.get('clr-icon[shape="filter"]').then((filterButton) => {
  //                     filterButton[0].click()
  //                   })

  //                   if (title[0].innerText.includes('MPE_X_TEST')) {
  //                     setFilterWithValue(
  //                       'SOME_CHAR',
  //                       'this is dummy data',
  //                       'value',
  //                       () => {
  //                         cy.get('app-query', { withinSubject: null })
  //                           .should('not.exist')
  //                           .get('.ht_master.handsontable tbody tr')
  //                           .then((rowNodes) => {
  //                             const tr = rowNodes[0]

  //                             expect(rowNodes).to.have.length(1)
  //                             expect(tr.innerText).to.equal('0')
  //                           })
  //                       }
  //                     )
  //                   } else if (title[0].innerText.includes('MPE_VALIDATIONS')) {
  //                     setFilterWithValue('BASE_COL', 'ALERT_LIB', 'value', () => {
  //                       cy.get('app-query', { withinSubject: null })
  //                         .should('not.exist')
  //                         .get('.ht_master.handsontable tbody tr')
  //                         .then((rowNodes) => {
  //                           const tr = rowNodes[0]

  //                           expect(rowNodes).to.have.length(1)
  //                           expect(tr.innerText).to.contain('ALERT_LIB')
  //                         })
  //                     })
  //                   }
  //                 })
  //             })
  //           })
  //         }
  //       }
  //     )
  // })
})

const removeAllColumns = () => {
  cy.get('.configuration-wrapper clr-icon[shape="trash"]').then(
    (removeNodes) => {
      for (let removeNode of removeNodes) {
        removeNode.click()
      }
    }
  )
}

const checkColumns = (columns: string[], callback: () => void) => {
  cy.get('.viewboxes-container .viewbox', { withinSubject: null }).then(
    (viewboxNodes: any) => {
      for (let viewboxNode of viewboxNodes) {
        cy.get(viewboxNode).within(() => {
          cy.get('.ht_master.handsontable thead tr th').then(
            (viewboxColNodes: any) => {
              console.log('viewboxColNode', viewboxColNodes)
              console.log('columns', columns)
              for (let i = 0; i < viewboxColNodes.length; i++) {
                const col = columns[i] || ''
                const colNode = viewboxColNodes[i]

                if (
                  !colNode.innerHTML.toLowerCase().includes(col.toLowerCase())
                )
                  return
              }

              callback()
            }
          )
        })
      }
    }
  )
}

const closeViewboxModal = () => {
  cy.get('app-viewboxes .close', { withinSubject: null }).click()
}

const removeColumn = (column: string) => {
  cy.get(`.col-box.column-${column} clr-icon`, { withinSubject: null }).click()
}

const addColumns = (columns: string[], callback?: () => void) => {
  for (let i = 0; i < columns.length; i++) {
    const column = columns[i]

    cy.get('.cols-search input', { withinSubject: null }).type(column)
    cy.get('.cols-search .autocomplete-wrapper', { withinSubject: null })
      .first()
      .trigger('keydown', { key: 'ArrowDown' })
    cy.get('.cols-search .autocomplete-wrapper', { withinSubject: null })
      .first()
      .trigger('keydown', { key: 'Enter' })
      .then(() => {
        if (i === columns.length - 1 && callback) callback()
      })
  }
}

const openViewboxConfig = (viewbox_tablename: string) => {
  cy.get('.open-viewbox').then((viewboxes: any) => {
    for (let openViewbox of viewboxes) {
      if (openViewbox.innerText.toLowerCase().includes(viewbox_tablename))
        openViewbox.click()
    }
  })
}

const openTableFromTree = (libNameIncludes: string, tablename: string) => {
  cy.get('.app-loading', { timeout: longerCommandTimeout })
    .should('not.exist')
    .then(() => {
      cy.get('.nav-tree clr-tree > clr-tree-node', {
        timeout: longerCommandTimeout
      }).then((treeNodes: any) => {
        let viyaLib

        for (let node of treeNodes) {
          if (new RegExp(libNameIncludes).test(node.innerText.toLowerCase())) {
            viyaLib = node
            break
          }
        }

        cy.get(viyaLib).within(() => {
          cy.get('.clr-tree-node-content-container p').click()

          cy.get('.clr-treenode-link').then((innerNodes: any) => {
            for (let innerNode of innerNodes) {
              if (innerNode.innerText.toLowerCase().includes(tablename)) {
                innerNode.click()
                break
              }
            }
          })
        })
      })
    })
}

const setFilterWithValue = (
  variableValue: string,
  valueString: string,
  valueField: 'value' | 'time' | 'date' | 'datetime' | 'in' | 'between',
  callback?: any
) => {
  cy.wait(600)

  cy.focused().type(variableValue)
  cy.wait(100)
  // cy.focused().trigger('input')
  cy.get('.variable-col .autocomplete-wrapper', { withinSubject: null })
    .first()
    .trigger('keydown', { key: 'ArrowDown' })
  cy.get('.variable-col .autocomplete-wrapper', {
    withinSubject: null
  }).trigger('keydown', { key: 'Enter' })
  cy.focused().tab()
  cy.wait(100)

  if (valueField === 'in') {
    cy.focused().select(valueField.toUpperCase()).trigger('change')
  } else if (valueField === 'between') {
    cy.focused().select(valueField.toUpperCase()).trigger('change')
  } else {
    cy.focused().tab()
    cy.wait(100)
  }

  switch (valueField) {
    case 'value': {
      cy.focused().type(valueString)

      break
    }
    case 'time': {
      cy.focused().type(valueString)

      break
    }
    case 'date': {
      cy.focused().type(valueString)
      cy.focused().tab()

      break
    }
    case 'datetime': {
      const date = valueString.split(' ')[0]
      const time = valueString.split(' ')[1]

      cy.focused().type(date)
      cy.focused().tab()
      cy.focused().tab()
      cy.focused().type(time)

      break
    }
    case 'in': {
      cy.get('.checkbox-vals').then(() => {
        cy.focused().tab()
        cy.focused().click()
        cy.get('.no-values')
          .should('not.exist')
          .then(() => {
            cy.get('clr-checkbox-wrapper input').then((inputs: any) => {
              inputs[0].click()
              cy.get('.in-values-modal .modal-footer button').click()

              cy.get('.modal-footer .btn-success-outline').click()

              if (callback) callback()
            })
          })
      })

      break
    }
    case 'between': {
      cy.focused().tab()

      const start = valueString.split('-')[0]
      const end = valueString.split('-')[1]

      cy.focused().type(start)
      cy.focused().tab()
      cy.focused().type(end)
    }
    default: {
      break
    }
  }

  cy.wait(100)
  cy.focused().tab()
  cy.wait(100)
  cy.focused().tab()
  cy.wait(100)
  cy.focused().tab()
  cy.wait(100)
  cy.focused().tab()
  cy.wait(100)
  cy.focused().click()

  if (callback) callback()
}

const openTableFromViewboxTree = (
  libNameIncludes: string,
  tablenames: string[]
) => {
  cy.get('.add-new clr-tree > clr-tree-node', {
    timeout: longerCommandTimeout
  }).then((treeNodes: any) => {
    let viyaLib

    for (let node of treeNodes) {
      if (node.innerText.toLowerCase().includes(libNameIncludes)) {
        viyaLib = node
        break
      }
    }

    cy.get(viyaLib).within(() => {
      cy.get('p')
        .click()
        .then(() => {
          cy.get('.clr-treenode-link').then(async (innerNodes: any) => {
            for (let innerNode of innerNodes) {
              for (let tablename of tablenames) {
                await pause(300)
                if (innerNode.innerText.toLowerCase().includes(tablename)) {
                  innerNode.click()
                }
              }
            }
          })
        })
    })
  })
}

const pause = (ms: number) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(null)
    }, ms)
  })
}

const visitPage = (url: string) => {
  cy.visit(`${hostUrl}${appLocation}/#/${url}`)
}
