import { Ref } from 'vue'
import _ from 'lodash'
import { CommonData, CommonTableColumn, MaybeRef } from '~/common'

export interface Options {
  defaultFilterValueMap?: { [x: string]: string[] } // 默认筛选条件
  extraFilterValueMap?: MaybeRef<{ [x: string]: string[] }> // 表头之外的额外筛选条件
  defaultSortRuleMap?: { [x: string]: string } // 默认排序条件
  extraSortRuleMap?: MaybeRef<{ [x: string]: string }> // 表头之外的额外排序条件
  defaultSortFunction?: (a: CommonData, b: CommonData) => number // 默认排序函数
  sortMode?: 'single' | 'multiple'
}

export function useTableFilterAndSort(
  tableColumns: Ref<CommonTableColumn[]>,
  tableData: Ref<CommonData[]>,
  options: Options = {}
) {
  if (!options.sortMode) {
    options.sortMode = 'single'
  }

  watch([tableColumns, tableData], ([columns, records]) => {
    const tempSets = {}
    columns.forEach(column => {
      if (column.needFilters) {
        tempSets[column.columnName] = new Set()
      }
    })
    records.forEach(item => {
      Object.keys(tempSets).forEach(key => {
        '' !== (item[key] ?? '') && tempSets[key].add(String(item[key]))
      })
    })
    Object.keys(tempSets).forEach(key => {
      filterOptionMap[key] = _.orderBy(
        [...tempSets[key]].map(value => ({
          label: value,
          value,
        })),
        o => o.value
      )
    })
  })

  const {
    defaultFilterValueMap = {},
    extraFilterValueMap = {},
    defaultSortRuleMap = {},
    extraSortRuleMap = {},
    defaultSortFunction,
  } = options

  const filterOptionMap = reactive<{
    [x: string]: { label: string; value: string }[]
  }>({})
  const filterValueMap = reactive(defaultFilterValueMap)
  const mergedFilterValueMap = computed(() => ({
    ...unref(extraFilterValueMap),
    ...filterValueMap,
  }))

  const sortRuleMap = reactive(defaultSortRuleMap)
  const mergedSortRuleMap = computed(() => ({
    ...unref(extraSortRuleMap),
    ...sortRuleMap,
  }))

  const dealedTableData = computed(() => {
    const filtered = tableData.value.filter(item => {
      let flag = true
      Object.entries(unref(mergedFilterValueMap)).forEach(([key, arr]) => {
        if (arr.length && !arr.includes(String(item[key]))) {
          flag = false
        }
      })
      return flag
    })
    const sortRules = Object.entries(unref(mergedSortRuleMap)).reduce(
      (pre: [string[], ('asc' | 'desc')[]], [key, value]) => {
        if (value) {
          pre[0].push(key)
          pre[1].push(value === 'ascending' ? 'asc' : 'desc')
        }
        return pre
      },
      [[], []]
    )
    if (sortRules[1].length) {
      return _.orderBy(filtered, sortRules[0], sortRules[1])
    }
    if (defaultSortFunction) {
      return filtered.sort(defaultSortFunction)
    }
    return filtered
  })

  const sortChangeHandler = (currentKey: string) => {
    if (options.sortMode === 'single') {
      Object.keys(sortRuleMap).forEach(key => {
        if (currentKey !== key) {
          delete sortRuleMap[key]
        }
      })
    }
  }

  return {
    filterOptionMap,
    filterValueMap,
    sortRuleMap,
    sortChangeHandler,
    dealedTableData,
  }
}
