/* eslint-disable no-extend-native */
export default {
  install(Vue) {
    // Array ext.
    Array.prototype.first = function(predicate) {
      if (predicate == null || typeof predicate !== 'function') {
        return this.length ? this[0] : null
      }
      for (let i = 0; i < this.length; i++) {
        const item = this[i]
        if (predicate(item)) return item
      }
    }
    Array.prototype.last = function(predicate) {
      if (predicate == null || typeof predicate !== 'function') {
        return this.length ? this[this.length - 1] : null
      }
      for (let i = this.length - 1; i >= 0; i--) {
        const item = this[i]
        if (predicate(item)) return item
      }
    }
    Array.prototype.groupBy = function(propGetter, groupName = 'label', listName = 'options') {
      const results = []
      this.forEach(item => {
        const groupValue = propGetter(item)
        let exists = results.find(i => i[groupName] === groupValue)
        if (!exists) {
          exists = {}
          exists[groupName] = groupValue
          exists[listName] = []
          results.push(exists)
        }
        exists[listName].push(item)
      })

      return results
    }
    Array.prototype.remove = function(item) {
      // remove first match item in array
      const idx = this.findIndex(i => i === item)
      if (idx === -1) return
      this.splice(idx, 1)
    }
    Array.prototype.sum = function(propGetter = null) {
      let result = 0
      this.forEach(item => {
        let el = propGetter ? propGetter(item) : item
        if (isNaN(el)) el = 0
        result += el * 1
      })
      return result
    }
    Array.prototype.clear = function() {
      this.splice(0, this.length)
    }

    // String
    String.prototype.castObject = function() {
      // cast if it is json
      try {
        return JSON.parse(this)
      } catch (e) {
        console.log('extension `castObject` failed, will return raw value.', e)
        return this
      }
    }
    String.prototype.tailingFix = function(fix) {
      return this.endsWith(fix) ? this : this + fix
    }
    String.prototype.trimFix = function(fix) {
      if (!fix) return this.trim()
      return this.replace(new RegExp('^' + fix), '')
        .replace(new RegExp(fix + '$'), '')
    }

    // Global func.
    Vue.prototype.msgSuccess = function(msg) {
      this.$message({ showClose: true, message: msg, type: 'success' })
    }

    Vue.prototype.msgError = function(msg) {
      this.$message({ showClose: true, message: msg, type: 'error' })
    }

    Vue.prototype.msgInfo = function(msg) {
      this.$message.info(msg)
    }

    Vue.prototype.deepClone = function(obj) {
      if (!obj) return obj
      return JSON.parse(JSON.stringify(obj))
    }

    Vue.prototype.sleep = function(delay) {
      return new Promise(resolve => {
        setTimeout(resolve, delay)
      })
    }
    // 动态表转objects
    Vue.prototype.reverseDynamicTableToObjects = function({ columns, rows }) {
      return rows.map(row => {
        const obj = {}
        // eslint-disable-next-line no-return-assign
        columns.forEach((col, idx) => obj[col] = row[idx])
        return obj
      })
    }
    Vue.prototype.dynamicTableExchangeRowColumn = function({ columns, rows }) {
      let newColumns = []
      const newRows = []
      for (let rowIdx = 0; rowIdx < columns.length; rowIdx++) {
        const rowName = columns[rowIdx]
        const newRow = [rowName]
        for (let colIdx = 0; colIdx < rows.length; colIdx++) {
          const row = rows[colIdx]
          const val = rowIdx < row.length ? row[rowIdx] : ''
          newRow.push(val)
        }
        if (rowIdx === 0) {
          newColumns = newRow
        } else {
          newRows.push(newRow)
        }
      }
      return {
        columns: newColumns,
        rows: newRows
      }
    }
    Vue.prototype.convertStandardTree = function(
      root,
      labelKey = 'label',
      valueKey = 'value',
      childrenKey = 'children',
      toLabel = 'label',
      toValue = 'value',
      toChildren = 'children') {
      const convertor = (node) => {
        const result = {
          [toLabel]: node[labelKey],
          [toValue]: node[valueKey],
          [toChildren]: node[childrenKey]?.map(convertor)
        }
        if (!result.children?.length) delete result.children
        return result
      }
      const arrRoot = Array.isArray(root) ? root : [root]
      return arrRoot.map(convertor)
    }
    Vue.prototype.findTreeNode = function(tree, predicate) {
      if (typeof predicate !== 'function') throw new TypeError('predicate must be a function')
      const _findNode = (node) => {
        if (predicate(node)) return node
        if (node.children?.length) {
          for (const child of node.children) {
            const subFind = _findNode(child)
            if (subFind) return subFind
          }
        }
      }
      const nodes = [].concat(tree)
      for (const child of nodes) {
        const subFind = _findNode(child)
        if (subFind) return subFind
      }
    }
  }
}
