<template>
  <el-tooltip :disabled="!showDesc" :content="desc">
    <div
      :class="[
        'table-header-cell',
        'el-table-v2__header-cell-text',
        'el-table__header-cell-text',
        {
          'table-header-cell-space-between':
            (filterable && filterStyle === 'arrow') || sortable,
        },
      ]"
    >
      <template v-if="filterable && filterStyle === 'underline'">
        <span :class="['filter-button-wrapper']">
          <span
            :class="['filter-button', { 'filter-button-active': active }]"
            ref="buttonRef"
            v-click-outside="clickOutsideHandler"
            >{{ `${showDesc ? '*' : ''}${label}` }}</span
          >
        </span>
      </template>
      <template v-else>
        <span style="flex: 1">{{ `${showDesc ? '*' : ''}${label}` }}</span>
      </template>
      <div
        v-if="(filterable && filterStyle === 'arrow') || sortable"
        class="button-wrapper"
      >
        <div
          v-if="filterable && filterStyle === 'arrow'"
          ref="buttonRef"
          v-click-outside="clickOutsideHandler"
          :class="[
            'filter-arrow',
            { 'arrow-active': active, 'arrow-expand': expand },
          ]"
        >
          <el-icon>
            <CaretBottom />
          </el-icon>
        </div>
        <div v-if="sortable" class="sort-button" @click="sortChange">
          <el-icon
            :color="sortRule ? '#2d7cff' : '#000000'"
            :size="sortRule ? 16 : ''"
          >
            <SortUp v-show="sortRule === 'ascending'" />
            <SortDown v-show="sortRule === 'descending'" />
            <Sort v-show="!sortRule" />
          </el-icon>
        </div>
      </div>
      <el-popover
        ref="popoverRef"
        :virtual-ref="buttonRef"
        virtual-triggering
        trigger="click"
        :width="224"
        class="table-header-cell-popover"
        placement="bottom"
        @show="
          () => {
            expand = true
          }
        "
        @hide="
          () => {
            expand = false
          }
        "
      >
        <el-button-group size="small" type="default" class="select-buttons">
          <el-button @click="selectAll">全选</el-button>
          <el-button @click="selectReverse">反选</el-button>
        </el-button-group>
        <el-select
          v-model="selections"
          size="default"
          placeholder="筛选"
          multiple
          filterable
          default-first-option
          collapse-tags
          clearable
          :teleported="false"
        >
          <el-option
            v-for="(option, index) in groupedOptions"
            :key="option.value + index"
            :value="option.value"
            :label="option.label"
          />
        </el-select>
      </el-popover>
    </div>
  </el-tooltip>
</template>

<script setup lang="ts">
import { PropType } from 'vue'
import _ from 'lodash'
import { CaretBottom, Sort, SortUp, SortDown } from '@element-plus/icons-vue'
import { ClickOutside as vClickOutside } from 'element-plus'

const props = defineProps({
  label: {
    type: String,
    default: '',
  },
  desc: {
    type: String,
    default: ''
  },
  showDesc: {
    type: Boolean,
  },
  filterStyle: {
    type: String as PropType<'arrow' | 'underline'>,
    default: 'arrow',
  },
  filterOptions: {
    type: Array as PropType<{ value: string, label: string }[]>,
  },
  filterValues: {
    type: Array<string>,
  },
  sortable: {
    type: Boolean,
  },
  sortRule: {
    type: String,
    default: '',
  },
})

const emit = defineEmits(['update:filterValues', 'update:sortRule'])

const selections = ref<string[]>([])
const groupedOptions = computed(() => {
  if (props.filterOptions) {
    const selected = selections.value.map(value => {
      const sameOption = props.filterOptions?.find(option => option.value === value)
      if (sameOption) {
        return sameOption
      } else {
        return {
          value,
          label: value
        }
      }
    })
    const unselected = props.filterOptions.filter(option => !selections.value.includes(option.value))
    return [
      ..._.orderBy(selected, o => o.value),
      ..._.orderBy(unselected, o => o.value)
    ]
  } else {
    return []
  }
})
const expand = ref(false)
const active = computed(() => !!props.filterValues?.length)
const filterable = computed(() => !!props.filterOptions)
watchEffect(() => {
  if (props.filterValues) {
    selections.value = props.filterValues
  }
})
watchEffect(() => {
  emit('update:filterValues', selections.value)
})
const selectAll = () => {
  selections.value.push(...props.filterOptions!.reduce((pre: string[], { value }) => {
    if (!selections.value.includes(value)) {
      pre.push(value)
    }
    return pre
  }, []))
}
const selectReverse = () => {
  selections.value = props.filterOptions!.reduce((pre: string[], { value }) => {
    if (!selections.value.includes(value)) {
      pre.push(value)
    }
    return pre
  }, [])
}

const buttonRef = ref()
const popoverRef = ref()
const clickOutsideHandler = () => {
  unref(popoverRef).popperRef?.delayHide?.()
}

const sortChange = () => {
  const sortRule =
    props.sortRule === ''
      ? 'ascending'
      : props.sortRule === 'ascending'
        ? 'descending'
        : ''
  emit('update:sortRule', sortRule)
}
</script>

<style lang="scss" scoped>
.table-header-cell {
  flex: 1;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  line-height: 14px;

  &.table-header-cell-space-between {
    justify-content: space-between;
  }

  .filter-button-wrapper {
    flex: 1;
    cursor: pointer;

    .filter-button {
      position: relative;

      &::after {
        content: '';
        display: block;
        width: calc(100% + 4px);
        position: absolute;
        bottom: -4px;
        left: -2px;
        border-bottom: 1px solid #101116;
      }

      &:hover {
        color: #2d7cff;
      }

      &-active,
      &:hover {
        &::after {
          border-bottom: 2px solid #2d7cff;
        }
      }
    }
  }

  .button-wrapper {
    width: 14px;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items: center;
    position: relative;

    &::after {
      content: '';
      display: block;
      width: 100%;
      height: 100%;
      position: absolute;
      z-index: 0;
      background-color: #000000;
      opacity: 0.1;
    }

    > div {
      z-index: 1;
      flex: 1;
      display: flex;
      justify-content: center;
      align-items: center;
      cursor: pointer;
    }

    .filter-arrow {
      transition: 0.3s transform;

      &.arrow-expand {
        transform: rotate(-180deg);
      }

      &.arrow-active {
        color: #2d7cff;
        font-weight: bold;
      }
    }
  }
}

.el-select-dropdown__item.hover {
  background: #d2d6df;
}

.select-buttons {
  margin-bottom: 10px;

  .el-button {
    margin-right: 10px;
  }
}

.el-table-v2__main .button-wrapper {
  position: relative;
  z-index: 0;
}
</style>
