
const ButtonConfig = {
  add: {
    icon: 'el-icon-circle-plus-outline',
    label: '新增'
  }
}

// {
//   keepalive?: false,
//   singlePage?: false,
//   pagination?: Object,
//   condition?: Object,
//   list: Function,
//   transform?: Function
//   buttons?: [
//     { type: String, icon: String, label: String, on: Function }
//   ],
//   filters?: [
//     { key: String, type: 'select', placeholder: String, ...SelectSchema },
//     { key: String, type: 'search', placeholder: String }
//   ],
//   cols: [
//     { prop: String, label: String, render?: Function | Array }
//   ]
// }
export default {
  provide () {
    return {
      table: this
    }
  },
  props: {
    schema: {
      type: Object,
      required: true
    },
    proxy: {
      type: Object,
      default: null
    }
  },
  data () {
    return {
      customOptions: null,
      buttons: null,
      filters: null
    }
  },
  computed: {
    hasHeader () {
      return this.$scopedSlots.header || this.buttons?.length || this.filters?.length
    },
    tableData () {
      const { transformData } = this.schema
      return transformData ? transformData(this.options.list) : this.options.list
    },
    options: {
      get () {
        return this.proxy || this.customOptions
      },
      set (val) {
        if (this.proxy) {
          this.$emit('update:proxy', val)
        } else {
          this.customOptions = val
          this.onPagination()
        }
      }
    },
    isManualPagination () {
      return this.schema.singlePage
    },
    paginationConfig () {
      return this.schema.pagination
    }
  },
  watch: {
    proxy () {
      this.queueStatus()
    },
    schema: {
      handler () {
        this.customOptions = this.createOptions(this.schema.condition)

        this.buttons = this.schema.buttons?.map(({ type, ...item }) => {
          return {
            ...ButtonConfig[type],
            ...item
          }
        })

        const filterMap = {}
        this.filters = this.schema.filters?.map(filter => {
          filterMap[filter.key] = filter
          return {
            ...filter,
            loading: false,
            loaded: !!filter.remote
          }
        })
        this.filterMap = filterMap

        this.queueStatus()
      },
      immediate: true
    }
  },
  activated () {
    if (this.schema.keepalive) {
      this.onPagination()
    }
  },
  methods: {
    queueStatus () {
      if (!this.$flushing) {
        this.$flushing = true
        this.$nextTick(this.flushStatus)
      }
    },
    flushStatus () {
      this.$flushing = false
      this.onPagination()
    },
    createOptions (condition) {
      return {
        loading: false,
        error: false,
        params: { pageSize: this.pageSize, pageNum: 1, ...condition },
        totalCount: 0,
        list: []
      }
    },
    filterInvokes (data) {
      return this.schema.invokes.filter(({ render }) => !render || render(data))
    },
    onPagination () {
      const options = this.options
      if (!options.loading) {
        options.loading = true
        const { list, transform } = this.schema
        list(options.params).then(
          ({ data, totalCount }) => {
            options.loading = false
            options.error = false
            options.totalCount = totalCount || data.length
            if (this.isManualPagination) {
              const { pageNum, pageSize } = options.params
              data = data.slice((pageNum - 1) * pageSize, pageNum * pageSize)
            }
            if (data.length === 0) {
              const { pageNum, pageSize } = options.params
              if (pageNum > 1) {
                return void this.pageTo(totalCount ? Math.ceil(totalCount / pageSize) : 1)
              }
            }
            options.list = transform ? data.map(transform) : data
          },
          () => {
            options.loading = false
            options.error = true
            options.totalCount = 0
            options.list = []
          }
        )
      }
    },
    onClickButton ({ on }) {
      if (on) {
        on(this.options.params, this)
      }
    },
    onChange () {
      this.pageTo(1)
    },
    getInst () {
      return this.$refs.table
    },
    getData () {
      return this.options.list
    },
    setData (data) {
      this.options.list = data
    },
    info () {
      const options = this.options
      return {
        totalCount: options.totalCount,
        ...options.params
      }
    },
    getCondition () {
      return this.options.params
    },
    mergeCondition (condition) {
      const params = { ...this.options.params, pageNum: 1, ...condition }
      if (this.options.loading) {
        this.options = this.createOptions(params)
      } else {
        this.options.params = params
      }
      this.onPagination()
    },
    resetCondition (condition) {
      const params = this.options.params
      condition && Object.keys(condition).forEach(key => {
        const paramValue = params[key]
        if (paramValue != null && paramValue !== '') {
          const value = condition[key]
          const filter = this.filterMap[key]
          switch (filter?.key) {
            case 'select':
              if (paramValue !== value) {
                params[key] = filter.placeholder ? void 0 : value
              }
              break
            case 'search':
              if (new RegExp(paramValue).test(value)) {
                params[key] = ''
              }
              break
            default:
              params[key] = value
              break
          }
        }
      })
      this.onChange()
    },
    pageTo (pageNum) {
      if (pageNum >= 1) {
        return void this.mergeCondition({ pageNum })
      }
      this.mergeCondition({ pageNum: this.options.params.pageNum })
    },
    decrease (count) {
      const options = this.options
      if (options.list.length <= count) {
        return void this.pageTo(options.params.pageNum - 1)
      }
      this.pageTo()
    }
  }
}
