import Vue from 'vue'
import { uniq } from './utils.js'

/* eslint-disable */
export default (options) => {
  const plugin = {
    selectionRows: [],
    keepAllSelected: false,
    excludeKeys: [],
    includeKeys: [],
    state: Vue.observable({
      checkedAll: false,
      indeterminate: false
    }),
    init (options) {
      this.options = Object.assign({
        grid: null,
        selectionInfo: null,
        change: null
      }, options)
      this.grid = this.options.grid
      if (this.options.selectionInfo) {
        this.keepAllSelected = !!this.options.selectionInfo.keepAllSelected
        this.excludeKeys = this.options.selectionInfo.excludeKeys || []
        this.includeKeys = this.options.selectionInfo.includeKeys || []
      }
      this.handleSelectionChange = (selection) => {
        if (this.disabledSelectionChange) {
          return
        }
        this.checkExcludeKeys(selection)
      }
      this.handleLoad = () => {
        this.syncCheckedState()
        this.checkAllCheckboxState()
        Vue.nextTick(() => {
          this.disabledSelectionChange = false
        })
      }
      this.handleReload = () => {
        this.excludeKeys = []
        this.includeKeys = []
        this.state.checkedAll = this.keepAllSelected
        this.state.indeterminate = false
        this.options.change && this.options.change({
          keepAllSelected: this.keepAllSelected,
          excludeKeys: this.excludeKeys,
          includeKeys: this.includeKeys
        })
      }
      this.handleQuery = () => {
        this.disabledSelectionChange = true
      }
      this.grid.$on('selection-change', this.handleSelectionChange)
      this.grid.$on('load', this.handleLoad)
      this.grid.$on('_reload', this.handleReload)
      this.grid.$on('_query', this.handleQuery)
    },
    handleCheckAllChange (checked) {
      this.excludeKeys = []
      this.includeKeys = []
      this.keepAllSelected = checked
      this.grid.toggleAllSelection()
      this.options.change && this.options.change({
        keepAllSelected: this.keepAllSelected,
        excludeKeys: this.excludeKeys,
        includeKeys: this.includeKeys
      })
    },
    syncCheckedState () {
      if (this.keepAllSelected) {
        const excludeKeys = this.excludeKeys.map(v => v[this.grid.rowKey])
        this.grid.tableData.forEach(row => {
          if (excludeKeys.includes(row[this.grid.rowKey])) {
            this.grid.toggleRowSelection(row, false)
          } else {
            this.grid.toggleRowSelection(row, true)
          }
        })
      } else {
        const includeKeys = this.includeKeys.map(v => v[this.grid.rowKey])
        this.grid.tableData.forEach(row => {
          if (includeKeys.includes(row[this.grid.rowKey])) {
            this.grid.toggleRowSelection(row, true)
          } else {
            this.grid.toggleRowSelection(row, false)
          }
        })
      }
    },
    checkExcludeKeys (selection) {
      if (this.keepAllSelected) {
        const currExcludeKeys = []
        const selectionMap = selection.reduce((rs, v) => {
          rs[v[this.grid.rowKey]] = v
          return rs
        }, {})
        const prevExcludeKeys = this.excludeKeys.filter(v => !selectionMap[v[this.grid.rowKey]])
        this.grid.tableData.forEach(v => {
          if (!selectionMap[v[this.grid.rowKey]]) {
            currExcludeKeys.push(v)
          }
        })
        this.excludeKeys = uniq([].concat(currExcludeKeys, prevExcludeKeys), this.grid.rowKey)
        this.state.checkedAll = this.excludeKeys.length === 0
        this.state.indeterminate = !this.state.checkedAll && this.excludeKeys.length > 0 && this.excludeKeys.length < this.grid.tableTotal
      } else {
        const dataMap = this.grid.tableData.reduce((rs, v) => {
          rs[v[this.grid.rowKey]] = v
          return rs
        }, {})
        const currIncludeKeys = this.includeKeys.filter(v => !dataMap[v[this.grid.rowKey]])
        this.includeKeys = uniq([].concat(currIncludeKeys, selection), this.grid.rowKey)
        this.state.checkedAll = this.includeKeys.length >= this.grid.tableTotal
        this.state.indeterminate = !this.state.checkedAll && this.includeKeys.length > 0
      }
      this.options.change && this.options.change({
        keepAllSelected: this.keepAllSelected,
        excludeKeys: this.excludeKeys,
        includeKeys: this.includeKeys
      })
      this.checkAllCheckboxState()
    },
    checkAllCheckboxState () {
      if (this.keepAllSelected) {
        this.state.checkedAll = this.excludeKeys.length === 0
        this.state.indeterminate = !this.state.checkedAll && this.excludeKeys.length > 0 && this.excludeKeys.length < this.grid.tableTotal
      } else {
        this.state.checkedAll = this.includeKeys.length >= this.grid.tableTotal
        this.state.indeterminate = !this.state.checkedAll && this.includeKeys.length > 0
      }
    },
    render (h) {
      return h('div', {
        class: 'ui-grid-plugin-select-all'
      }, [
        h('ui-checkbox', {
          props: {
            value: this.state.checkedAll,
            indeterminate: this.state.indeterminate
          },
          on: {
            input: (checked) => {
              this.state.checkedAll = checked
              this.state.indeterminate = false
              this.handleCheckAllChange(checked)
            }
          }
        })
      ])
    },
    destroy () {
      this.grid.$off('selection-change', this.handleSelectionChange)
      this.grid.$off('load', this.handleLoad)
      this.grid.$off('_reload', this.handleReload)
      this.grid.$off('_query', this.handleQuery)
    }
  }
  plugin.init(options)
  return plugin
}
/* eslint-enable */
