<script setup>
import { ref, useSlots, computed, inject } from 'vue'
import TableColumn from './TableColumn.vue'
import { PAGINATION_ALIGN_VALUES, COMP_NAME } from './constant'
import { isBoolean, isFunction, isObject } from '../utils/assist'

defineOptions({
  name: COMP_NAME
})

const props = defineProps({
  columns: {
    // 需要展示的列
    type: Array,
    required: true,
    validator(value) {
      value.forEach((item) => {
        const { type, key, slot, render, children } = item
        if (!type && !key && !slot && !render && !children) {
          throw new Error(`${COMP_NAME}: columns中每项需设置type|key|slot|render|children中的一项`)
        }
        if (render && !isFunction(render)) {
          throw new Error(`${COMP_NAME}: columns中的单项render属性需为Function类型`)
        }
      })
      return true
    }
  },
  data: {
    // 展示数据
    type: Array,
    required: true
  },
  config: {
    // 表格配置
    type: Object,
    default() {
      return {}
    }
  },
  pageConfig: {
    // 分页配置
    type: [Object, Boolean],
    default() {
      return {}
    },
    validator(value) {
      if (isBoolean(value)) return true
      const { align } = value
      if (align && !PAGINATION_ALIGN_VALUES.includes(align)) {
        throw new Error(
          `${COMP_NAME}: pageConfig中的align字段需为${PAGINATION_ALIGN_VALUES.join('|')}`
        )
      }
      return true
    }
  },
  total: {
    // 数据总条数
    type: Number,
    default: 0
  },
  loading: {
    // 表格是否加载中
    type: [Boolean, Object],
    default: false
  }
})

const CONFIG = inject('CONFIG_V_TABLE')
// 每页显示条目个数
const pageSize = defineModel('pageSize')
// 当前页数
const currentPage = defineModel('currentPage')

const tableRef = ref()
const pageRef = ref()

const slots = useSlots()

// config中的slot
const configSlotNames = computed(() => {
  return props.config.slot || {}
})
const tableConfig = computed(() => {
  const { slot, ...rest } = props.config
  return { ...CONFIG.config, ...rest }
})

const PAGE_DEFAULT_CONFIG = {
  layout: 'slot,total,prev,pager,next,sizes',
  align: 'right'
}
// 分页配置
const paginationConfig = computed(() => {
  const pConfig = props.pageConfig
  if (isBoolean(pConfig)) {
    if (pConfig) {
      return PAGE_DEFAULT_CONFIG
    } else {
      return false
    }
  }
  let defaultPageSize = 10
  if (CONFIG.pageConfig && CONFIG.pageConfig.pageSizes) {
    defaultPageSize = CONFIG.pageConfig.pageSizes[0]
  }
  return {
    ...PAGE_DEFAULT_CONFIG,
    defaultPageSize,
    ...CONFIG.pageConfig,
    ...pConfig
  }
})
// loading配置
const loadingConfig = computed(() => {
  const l = props.loading
  if (isBoolean(l)) {
    return {
      value: l
    }
  }
  if (isObject(CONFIG.loading)) {
    return {
      ...CONFIG.loading,
      value: false,
      ...l
    }
  } else {
    return {
      value: false,
      ...l
    }
  }
})

// expose
defineExpose({
  get refs() {
    return {
      table: tableRef.value,
      page: pageRef.value
    }
  },
  clearSelection() {
    tableRef.value.clearSelection()
  },
  getSelectionRows() {
    return tableRef.value.getSelectionRows()
  },
  toggleRowSelection(...rest) {
    tableRef.value.toggleRowSelection(...rest)
  },
  toggleAllSelection() {
    tableRef.value.toggleAllSelection()
  },
  toggleRowExpansion(...rest) {
    tableRef.value.toggleRowExpansion(...rest)
  },
  setCurrentRow(...rest) {
    tableRef.value.setCurrentRow(...rest)
  },
  clearSort() {
    tableRef.value.clearSort()
  },
  clearFilter(...rest) {
    tableRef.value.clearFilter(...rest)
  },
  doLayout() {
    tableRef.value.doLayout()
  },
  sort(...rest) {
    tableRef.value.sort(...rest)
  },
  scrollTo(...rest) {
    tableRef.value.scrollTo(...rest)
  },
  setScrollTop(...rest) {
    tableRef.value.setScrollTop(...rest)
  },
  setScrollLeft(...rest) {
    tableRef.value.setScrollLeft(...rest)
  }
})
</script>

<template>
  <div class="v-table-wrapper">
    <div class="el-table-wrapper">
      <div v-if="slots['table-prepend']" class="table-prepend-wrapper">
        <slot name="table-prepend"></slot>
      </div>
      <el-table
        ref="tableRef"
        :data="data"
        v-bind="tableConfig"
        v-loading="loadingConfig.value"
        :element-loading-spinner="loadingConfig.spinner"
        :element-loading-text="loadingConfig.text"
        :element-loading-svg-view-box="loadingConfig.svgViewBox"
        :element-loading-background="loadingConfig.background"
        :border="false"
      >
        <TableColumn
          v-for="(item, index) in columns"
          :key="`column-${index}`"
          :item="item"
          :slots="slots"
        >
          <template v-for="key in Object.keys(slots)" :key="key" v-slot:[key]="scope">
            <slot :name="key" v-bind="scope"></slot>
          </template>
        </TableColumn>
        <!-- 无数据的slot -->
        <template v-if="slots[configSlotNames.empty]" #empty>
          <slot :name="configSlotNames.empty"></slot>
        </template>
        <!-- 表格最后一行的slot -->
        <template v-if="slots[configSlotNames.append]" #append>
          <slot :name="configSlotNames.append"></slot>
        </template>
      </el-table>
      <div v-if="slots['table-append']" class="table-append-wrapper">
        <slot name="table-append"></slot>
      </div>
    </div>
    <div
      v-if="paginationConfig"
      class="el-pagination-wrapper"
      :class="[`align-${paginationConfig.align}`]"
    >
      <slot name="page-prepend"></slot>
      <el-pagination
        v-if="props.total > 10"
        ref="pageRef"
        v-bind="paginationConfig"
        :total="props.total"
        v-model:page-size="pageSize"
        v-model:current-page="currentPage"
      >
        <template v-if="paginationConfig.slot && slots[paginationConfig.slot]" #default>
          <slot :name="paginationConfig.slot"></slot>
        </template>
      </el-pagination>
      <slot name="page-append"></slot>
    </div>
  </div>
</template>

<style>
.v-table-wrapper {
  background-color: var(--v-light-bg);
}
.v-table-wrapper .table-prepend-wrapper {
  margin-bottom: var(--v-space-base);
}
.v-table-wrapper .table-append-wrapper {
  margin-top: var(--v-space-base);
}
.v-table-wrapper .el-pagination-wrapper.align-left {
  justify-content: flex-start;
}
.v-table-wrapper .el-pagination-wrapper.align-center {
  justify-content: center;
}
.v-table-wrapper .el-pagination-wrapper.align-right {
  justify-content: flex-end;
}
.v-table-wrapper .el-pagination-wrapper {
  display: flex;
  align-items: center;
  margin-top: var(--v-space-base);
}
</style>
