<template>
  <el-table :data="tempData"
            ref="tableRef"
            @row-click="rowClick"
            :row-key="rowKey"
            :height="props.height"
            @select-all="selectAll"
            highlight-current-row
            :row-style="{height: '24px'}"
            :row-class-name="rowClassName"
            :cell-style="{padding: 0,height: '24px'}">
    <slot v-if="isSlots"/>
    <template v-for="(item) in props.columns" v-else>
      <xc-table-v3-column :item="item" :start-index="startIndex"/>
    </template>
  </el-table>
</template>

<script setup lang="tsx">
import {computed, defineProps, nextTick, onMounted, ref, useSlots, watch} from 'vue'
import XcTableV3Column from "@/components/xiao-chan/xc-table-v3/XcTableV3Column.vue";
import {useIntersectionObserver, useResizeObserver} from "@vueuse/core";
import {xcMessage} from "@/utils/xiaochan-element-plus";

const props = defineProps({
  data: {
    type: Array,
    default: []
  },
  height: {
    type: [String, Number],
  },
  columns: {
    type: Array,
    default: []
  },
  clickToSelect: {
    type: Boolean,
    default: true
  },
  rowClassName: {
    type: Function,
    default: null
  }
})

const emits = defineEmits(['rowClick'])


const tableRef = ref(null)
const itemHeight = ref(24)
const numberOfPages = ref(20)
const startIndex = ref(0)
const tbody = ref()
let tableHeader, highlightCurrentRow

const tempData = computed(() => {
  return props.data.slice(startIndex.value, startIndex.value + numberOfPages.value)
})

const rowKey = (row) => {
  return JSON.stringify(row)
}

function bodyScroll(e) {
  let scrollTop = Math.ceil(e.srcElement.scrollTop)
  startIndex.value = Math.floor(scrollTop / itemHeight.value)
  tbody.value.style.transform = `translateY(${scrollTop}px)`
}

const numberOfPagesSize = () => {
  try {
    numberOfPages.value = Math.floor((props.height - tableHeader.clientHeight) / itemHeight.value)
    if (numberOfPages.value <= 0) {
      numberOfPages.value = 1
    }
  } catch (e) {
  }
}

/**
 * 用这个方法来解决元素隐藏获取不到高度,
 * 等元素显示的时候才去获取高度
 */
let isShowTable = false
const {stop} = useIntersectionObserver(tableRef,
    ([{isIntersecting}], observerElement) => {
      isShowTable = isIntersecting
      if (isIntersecting) {
        numberOfPagesSize()
        setScrollBarHeight()
      }
    },
)

const setScrollBarHeight = () => {
  if (isShowTable) {
    let scroll = tableRef.value.scrollBarRef.wrap$.querySelector('.el-scrollbar__view')
    scroll.style.height = (props.data.length * itemHeight.value) + itemHeight.value + 'px'
  }
}

useResizeObserver(tableRef, (entries) => {
  numberOfPagesSize()
})

// 需要同时使用 highlight-current-row 不然当时没有效果因为渲染没有变化，所以要使用 highlight-current-row
const rowClassName = ({row}) => {
  if (props.rowClassName !== null) {
    return props.rowClassName(row)
  } else {
    if (row === highlightCurrentRow) {
      return 'current-row';
    }
  }

}

const rowClick = (row, column, event) => {
  if (isSelected && props.clickToSelect) {
    let temp = tableRef.value.getSelectionRows();
    if (temp.includes(row)) {
      tableRef.value.toggleRowSelection(row, false)
    } else {
      tableRef.value.toggleRowSelection(row, true)
    }
  }
  highlightCurrentRow = row
  emits('rowClick', row, column, event)
}

const selectAll = (selection) => {
  let len = props.data.length;
  if (tableRef.value.store.states.isAllSelected.value) {
    if (len > 10000) {
      xcMessage.error('数据量过大会导致页面卡死,无法全选。');
      tableRef.value.clearSelection()
      return
    }
    for (let i = 0; i < len; i++) {
      tableRef.value.toggleRowSelection(props.data[i], true);
    }
  } else {
    tableRef.value.clearSelection()
  }
}

watch(() => props.data, async (oldData, newData) => {
  try {
    tableRef.value.clearSelection();
  } catch (e) {
  }
  if (typeof newData !== 'undefined') {
    if (oldData.length === newData.length) return
  }
  setScrollBarHeight()
  await nextTick()
  tableRef.value.setScrollTop(0)
  tableHeader = tableRef.value.$el.querySelector('.el-table__header')
  tbody.value = tableRef.value.$el.querySelector('.el-table__body')
  try {
    tableRef.value.scrollBarRef.wrap$.removeEventListener('scroll', bodyScroll, false)
  } catch (e) {
  }
  tableRef.value.scrollBarRef.wrap$.addEventListener('scroll', bodyScroll, false)
  numberOfPagesSize()
}, {immediate: true})

const table = () => {
  return tableRef.value
}

let isSelected = false
let isSlots = ref(false)
onMounted(() => {
  try {
    isSlots.value = !!useSlots().default()
  } catch (e) {
  }
  for (let i = 0; i < props.columns.length; i++) {
    if (props.columns[i].type && props.columns[i].type === 'selection') {
      isSelected = true
      return
    }
  }
})

defineExpose({
  table
})
</script>
