<template>
  <thead v-bind="$attrs" v-on="$listeners">
    <slot></slot>
    <a-dropdown
      v-model="menuOpen"
      :class="[$style.menu, menuOpen ? $style.open : '', notAllChecked ? $style.selected : '']"
      :overlay-class-name="columns.length >= 15 ? $style.dropDown : ''"
      :trigger="['click']"
    >
      <a-icon type="setting" theme="filled" title="选择列" @click.stop />
      <a-menu slot="overlay">
        <a-tree
          v-model="checkedKeys"
          checkable
          :tree-data="columns"
          :replace-fields="{ key: 'dataIndex' }"
          draggable
          @check="onCheck"
          @drop="onDrop"
        />
        <a-menu-divider />
        <a-button :class="$style.btnAction" type="link" @click="showAll">
          全选
        </a-button>
        <a-button :class="$style.btnAction" type="link" @click="reset">
          重置
        </a-button>
        <a-button :class="$style.btnAction" type="link" @click="refresh">
          刷新
        </a-button>
      </a-menu>
    </a-dropdown>
  </thead>
</template>

<script>
import { message } from 'ant-design-vue'
import cloneDeep from 'lodash.clonedeep'
import components from './_import-components/sd-table-header-import'
export default {
  name: 'SdTableHeader',
  components,
  props: {
    columns: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      menuOpen: false,
      checkedKeys: [],
      notAllChecked: false,
    }
  },
  created() {
    this.setCheckedKeys()
  },
  methods: {
    columnShowChange(key, value) {
      this.$emit('columnShowChange', key, value)
    },
    reset() {
      this.$emit('reset')
      this.menuOpen = false
      this.setCheckedKeys()
    },
    showAll() {
      this.$emit('columnShowChange', '*', true) //* 标识所有
      this.setCheckedKeys()
    },
    refresh() {
      this.$emit('refresh')
      this.menuOpen = false
    },
    onCheck(checkedKeys, info) {
      // 利用tree的halfCheckedKeys属性标识所有显示的列
      if (checkedKeys.length === 0) {
        // todo应该用置灰来控制是否可选，但是树结构判断比较麻烦先这样，发现空了就不管
        message.warn('不能清除所有选项')
        this.setCheckedKeys()
        return
      }
      this.$emit('columnShowChange', [...info.halfCheckedKeys, ...checkedKeys], true)
      this.setCheckedKeys()
    },
    setCheckedKeys() {
      this.checkedKeys = []
      this.notAllChecked = false
      const f = (columns) => {
        columns.forEach((item) => {
          if (!item.show) {
            this.notAllChecked = true
          }
          if (item.show && !item.children) {
            // 只设置叶子节点的选中，父节点会根据叶子节点自动选中或半选
            this.checkedKeys.push(item.dataIndex)
          }
          if (item.children) {
            f(item.children)
          }
        })
      }
      f(this.columns)
    },
    onDrop(info) {
      const dropKey = info.node.eventKey
      const dragKey = info.dragNode.eventKey
      const dropPos = info.node.pos.split('-')
      const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
      const loop = (data, key, callback) => {
        data.forEach((item, index, arr) => {
          if (item.dataIndex === key) {
            return callback(item, index, arr)
          }
          if (item.children) {
            return loop(item.children, key, callback)
          }
        })
      }
      const data = cloneDeep(this.columns)
      // 抄的样例的，实现只有同级可移动，暂不知第二个elseif是啥意思
      if (!info.dropToGap) {
        return
      } else if (
        (info.node.children || []).length > 0 && // Has children
        info.node.expanded && // Is expanded
        dropPosition === 1 // On the bottom gap
      ) {
        return
      } else {
        let dragObj
        let moveAble = false
        loop(data, dragKey, (item, index, arr) => {
          if (!arr.find((i) => i.dataIndex === dropKey)) {
            // dragKey和dropKey是不是在一层
            return
          }
          moveAble = true
          arr.splice(index, 1)
          dragObj = item
        })
        if (!moveAble) {
          return
        }
        let ar
        let i
        loop(data, dropKey, (item, index, arr) => {
          ar = arr
          i = index
        })
        if (dropPosition === -1) {
          ar.splice(i, 0, dragObj)
        } else {
          ar.splice(i + 1, 0, dragObj)
        }
      }

      const f = (columns) => {
        columns.forEach((item) => {
          for (const x in item) {
            if (x !== 'children' && x !== 'dataIndex') {
              delete item[x]
            }
          }
          if (item.children) {
            f(item.children)
          }
        })
      }
      f(data)
      this.$emit('columnOrderChange', data)
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
$icon-width: 28px;

:global(.ant-table-thead) {
  // position: relative;
  th:last-of-type {
    // padding-right: 28px !important;
  }
}
.menu {
  position: absolute;
  top: 0;
  right: 0;
  // bottom: 0;
  width: $icon-width;
  height: $line-height-base * $font-size-base + 2 * $table-padding-vertical;
  font-size: $font-size-sm;
  color: $input-placeholder-color;
  text-align: center;
  cursor: pointer;
  transition: all 0.3s;

  svg {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -$font-size-sm / 2 + 1px;
    margin-left: -$font-size-sm / 2;
  }
  &:hover,
  &.open {
    color: $text-color-secondary;
    background: $border-color-split;
  }
  &.selected {
    color: $primary-color;
  }
  &:active {
    color: $text-color;
  }
}
.btn-action {
  max-width: 33%;
}
.drop-down {
  max-height: 480px;
  overflow-y: auto;
  box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
}
</style>
