<template>
  <th
    :colspan="item.colSpan"
    :rowspan="item.rowSpan"
    :style="thStyle"
    :title="thTitle"
    :class="thClass"
  >
    <x-custom-render
      v-if="item.customHeader"
      header
      :column="item"
      :c-index="index"
      :custom-render="item.customHeader"
    ></x-custom-render>
    <template v-else>
      <div v-if="item.type === 'selection'" class="table-header-cell-content icon-column">
        <x-checkbox
          :indeterminate="!!table.isIndeterminate"
          :value="!!table.isSelectAll"
          @on-change="onCheckChange"
        ></x-checkbox>
      </div>
      <div v-else-if="item.type === 'expand'" class="table-header-cell-content">{{ item.label || '' }}</div>
      <div v-else class="table-header-cell-content flex-cell" :class="contentClass" @click="onSortChange($event)">
        <x-custom-render
          v-if="item.prependHeader"
          header
          :column="item"
          :c-index="index"
          :custom-render="item.prependHeader"
        ></x-custom-render>

        <span v-if="item.headerText" class="table-header-text">
          <x-custom-render
            header
            :column="item"
            :c-index="index"
            :custom-render="item.headerText"
          ></x-custom-render>
        </span>
        <span v-else class="table-header-text">{{ item.label }}</span>

        <span v-if="item.sortable" class="column-order-area">
          <i class="ascending-order" data-method="asc"></i>
          <i class="descending-order" data-method="desc"></i>
        </span>

        <x-custom-render
          v-if="item.appendHeader"
          header
          :column="item"
          :c-index="index"
          :custom-render="item.appendHeader"
        ></x-custom-render>
      </div>
    </template>
    <span
      v-if="item.resizable && !item.children"
      class="resize-handle"
      @mousedown.stop="handleMouseDown($event)"
    ></span>
  </th>
</template>

<script>
import { xCheckbox } from '../../../vue-checkbox/src'
import ItemMixin from './mixin/ItemMixin'
import XCustomRender from './CustomRender'
import { ASCENDING_ORDER, DESCENDING_ORDER } from './util/util'

export default {
  name: 'TableTh',
  components: { xCheckbox, XCustomRender },
  mixins: [ItemMixin],
  props: {
    item: {
      type: Object,
      default: () => {}
    },
    fixed: {
      type: String,
      default: '',
      validator: value => ['left', 'right', ''].includes(value)
    },
    index: { // eslint-disable-line
      type: Number
    }
  },
  data() {
    return {
      header: true,
      event: 'columnWidthChange',
      uniqueKey: this.item.id,
      sortMethod: ''
    }
  },
  computed: {
    table() {
      return this.$parent.table
    },
    isFixedLeft() {
      return this.fixed === 'left'
    },

    contentClass() {
      return [
        this.item.sortable && 'flex-cell',
        this.table.currentSortProp === this.item.prop && this.sortMethod
      ]
    },

    // 是否是左侧固定的最后一列
    isLastLeftColumn() {
      const leafColumns = this.table.leftLeafColumns
      const { id, children } = this.item

      if (!children || !children.length) {
        return leafColumns[leafColumns.length - 1].id === id
      }

      return this.getChildren(this.item, true).id === leafColumns[leafColumns.length - 1].id
    },

    // 是否是右侧固定的第一列
    isFirstRightColumn() {
      const leafColumns = this.table.rightLeafColumns
      const { id, children } = this.item
      if (!children) {
        return leafColumns[0].id === id
      }
      return this.getChildren(this.item).id === leafColumns[0].id
    },

    // th class样式
    thClass() {
      const { fixed, item, table, dragging } = this
      const align = item.headerAlign || item.align
      return [
        'table-header-cell',
        'align-' + align,
        dragging && 'hover-bg',
        item.resizable && 'resizable-bg',
        fixed === 'left' && 'fix-left' || '',
        fixed === 'right' && 'fix-right' || '',
        item.sortable && 'sortable-column',
        item.sortable && item.prop === table.currentSortProp && this.sortMethod,
        fixed === 'left' && this.isLastLeftColumn && 'last-fix-left',
        fixed === 'right' && this.isFirstRightColumn && 'first-fix-right'
      ]
    },
    // 计算sticky位置
    thStyle() {
      const { headerHeight: height, layout } = this.table
      const { colSpan = 1, rowSpan = 1 } = this.item
      if (!this.fixed) {
        return {
          height: rowSpan * height + 'px'
        }
      }
      const width = this.getSumWidth + 'px'
      return this.fixed === 'left' ? {
        position: 'sticky',
        width: colSpan * this.item.currentWidth + 'px',
        height: rowSpan * height + 'px',
        left: layout.isIE ? 0 : width
      } : {
        position: 'sticky',
        width: colSpan * this.item.currentWidth + 'px',
        height: rowSpan * height + 'px',
        right: layout.isIE ? 0 : width
      }
    },
    // 左右固定列叶子节点
    leafColumns() {
      return this.table[this.isFixedLeft ? 'leftLeafColumns' : 'rightLeafColumns']
    },

    // 计算位置
    getSumWidth() {
      if (!this.fixed) return ''

      const method = this.isFixedLeft ? 'getLeftSumWidth' : 'getRightSumWidth'
      const index = this.getColIndex(this.item, this.fixed)
      return this[method](index)
    },
    dragging() {
      return this.table.dragColumnId === this.item.id
    },

    thTitle() {
      const { customHeader, label } = this.item
      return customHeader ? '' : label
    }
  },
  // 默认排序
  mounted() {
    if (!this.table.defaultSort || !this.item.prop) return

    const { prop, order } = this.table.defaultSort
    if (this.item.prop === prop) {
      this.sortMethod = order
    }
  },
  methods: {
    getColIndex(col, position = 'left') {
      const index = this.leafColumns.findIndex(v => v.id === col.id)
      if (index !== -1) {
        return index
      }
      if (col.children) {
        const childCol = position === 'left' ? col.children[0] : col.children[col.children.length - 1]
        return this.getColIndex(childCol, position)
      }
    },
    getLeftSumWidth(index) {
      let sum = 0
      for (let start = 0; start <= index - 1; start++) {
        const cur = this.leafColumns[start]
        sum += this.leafColumns[start].currentWidth * (cur.colSpan || 1)
      }
      return sum
    },
    getRightSumWidth(index) {
      let sum = 0
      for (let start = index + 1; start <= this.leafColumns.length - 1; start++) {
        const cur = this.leafColumns[start]
        sum += this.leafColumns[start].currentWidth * (cur.colSpan || 1)
      }
      return sum + (this.table.restrict ? this.table.layout.gutterWidth : 0)
    },
    onCheckChange(val) {
      this.table.store.commit('allSelectChange', val)
    },
    onSortChange(e) {
      const { sortable, prop } = this.item
      if (!sortable) return

      const method = e.target && e.target.getAttribute('data-method') || ''
      if (method) {
        this.sortMethod = method
      } else if (!this.sortMethod ||
        this.sortMethod === DESCENDING_ORDER ||
        this.table.currentSortProp !== prop) {
        this.sortMethod = ASCENDING_ORDER
      } else if (this.sortMethod === ASCENDING_ORDER) {
        this.sortMethod = DESCENDING_ORDER
      }

      this.table.currentSortProp = prop
      if (sortable === 'custom') {
        this.table.$emit('on-sort-change', this.item, prop, this.sortMethod)
        return
      }
      this.table.sortData(prop, this.sortMethod)
    },
    getChildren(col, isLast) {
      if (!col.children || !col.children.length) return col
      const key = isLast ? col.children.length - 1 : 0
      return this.getChildren(col.children[key], isLast)
    },
    handleMouseDown(event) {
      const column = this.item
      if (column.children && column.children.length > 0) return

      const table = this.table
      table.resizeProxyVisible = true
      const tableEl = table.$el
      const tableLeft = tableEl.getBoundingClientRect().left
      const columnEl = this.$el
      const columnRect = columnEl.getBoundingClientRect()
      const minLeft = columnRect.left - tableLeft + column.minWidth

      table.dragColumnId = column.id

      const dragModel = {
        startMouseLeft: event.clientX,
        startLeft: event.clientX - tableLeft,
        startColumnLeft: columnRect.left - tableLeft
      }

      table.currentDragModel = dragModel
      const resizeProxy = table.$refs.resizeProxy
      resizeProxy.style.left = dragModel.startLeft + 'px'

      document.onselectstart = () => false
      document.ondragstart = () => false

      const handleMouseMove = (event) => {
        const deltaLeft = event.clientX - table.currentDragModel.startMouseLeft
        const proxyLeft = table.currentDragModel.startLeft + deltaLeft
        resizeProxy.style.left = Math.max(minLeft, proxyLeft) + 'px'
      }

      const handleMouseUp = () => {
        if (this.dragging) {
          const { startColumnLeft } = table.currentDragModel
          const finalLeft = parseInt(resizeProxy.style.left, 10)
          const columnWidth = finalLeft - startColumnLeft

          column.currentWidth = column.width = columnWidth
          table.updateColumns(column)
          table.resizeProxyVisible = false
          table.dragColumnId = null
        }

        document.removeEventListener('mousemove', handleMouseMove)
        document.removeEventListener('mouseup', handleMouseUp)
        document.onselectstart = null
        document.ondragstart = null
      }

      document.addEventListener('mousemove', handleMouseMove)
      document.addEventListener('mouseup', handleMouseUp)
    }
  }
}
</script>
