<script setup lang="ts">
import { state_checked, state_indeterminate, state_unchecked } from '.'
import XTreeItem from './item.vue'

const props = withDefaults(
  defineProps<{
    options: anyObj[]
    prop?: {
      label: string
      select: string
    }
  }>(),
  {
    options: () => [],
  },
)

defineOptions({
  name: 'XTree',
})

const key = props.prop?.select || 'select'
const expands = ref([])

function onSelect(pData: anyObj, data?: anyObj, status?: number, update = 1) {
  if (data) {
    if (status !== undefined) {
      data[key] = status
    } else {
      data[key] = data[key] === state_unchecked ? state_checked : state_unchecked
    }
    if (pData.children.some((i: anyObj) => i[key] === state_unchecked)) {
      pData[key] = state_unchecked
    } else {
      pData[key] = state_checked
    }
    check(props.options)
  } else {
    if (status !== undefined) {
      pData[key] = status
    } else {
      pData[key] = pData[key] === state_unchecked ? state_checked : state_unchecked
    }
    pData.children.forEach((item: anyObj) => {
      item[key] = pData[key]
      if (item.children?.length) {
        onSelect(
          item,
          data,
          item[key],
          pData[key] === state_unchecked ? state_checked : state_unchecked,
        )
      }
    })
    if (update) check(props.options) // 仅在最后一次刷新
  }

  // 子节点更新，同步所有父节点状态
  function check(data: anyObj) {
    data?.forEach((i: anyObj) => {
      if (!i.children?.length) return
      check(i.children)
      let childrenSelectedCount = state_unchecked
      for (const sub of i.children) {
        if ((sub[key] || state_unchecked) === state_unchecked) continue
        childrenSelectedCount++
      }
      if (childrenSelectedCount === i.children.length) {
        i[key] = state_checked
      } else if (childrenSelectedCount === state_unchecked) {
        i[key] = state_unchecked
      } else {
        i[key] = state_indeterminate
      }
    })
  }
}

const state = computed(() => {
  let checkedCount = 0
  for (const item of props.options) {
    const itemState = item[key] || state_unchecked
    if (itemState === state_indeterminate) {
      // 半选中
      return itemState
    } else if (itemState === state_checked) {
      checkedCount++
    }
  }
  if (checkedCount === 0) {
    return state_unchecked
  }
  return checkedCount === props.options.length ? state_checked : state_indeterminate
})

const allSelect = computed(() => state.value === state_checked)
function toggleAllSelection() {
  const changeSelect = allSelect.value ? state_unchecked : state_checked
  props.options.forEach(i => onSelect(i, undefined, changeSelect))
}

// 获取所有选中的ID
function getSelectId() {
  const ids: string[] = []
  function _getSelectId(data: anyObj) {
    data.forEach((i: anyObj) => {
      if (i.children?.length) {
        _getSelectId(i.children)
      }
      if (i[key] === 1) {
        ids.push(i.id) // 父节点 子节点 都要保存
      }
    })
  }
  _getSelectId(props.options)
  return ids
}

function _select(values: any[], dataList: any[]) {
  for (const item of dataList) {
    onSelect(item, undefined, values.includes(item.id) ? state_checked : state_unchecked)
    if (item.children?.length) {
      _select(values, item.children)
    }
  }
}

function select(values: any[]) {
  _select(values, props.options)
}

defineExpose({
  state,
  toggleAllSelection,
  getSelectId,
  select,
})
</script>

<template>
  <div class="x-tree">
    <el-collapse v-model="expands">
      <XTreeItem
        v-for="item in options"
        :key="item.label"
        :data="item"
        :prop="prop"
        :expands="expands"
        @select="onSelect"
      />
    </el-collapse>
  </div>
</template>

<style lang="scss" scoped>
.x-tree {
  :deep(.el-collapse) {
    padding: 0 $space-4;
    border: none;
    .el-collapse-item {
      .el-collapse-item__header {
        height: 6.67vh;
        font-size: $font-size-5;
        line-height: 1.5em;
        font-weight: 400;
        color: $font-tag-color;
        border: none;
        position: relative;
        justify-content: space-between;
        .arrow-icon {
          transition: all 0.3s ease-in-out;
        }
        .title {
          text-align: left;
          flex: 1;
          margin-left: $space-3;
        }
        .el-icon {
          display: none;
        }

        &::after {
          position: absolute;
          bottom: 0;
          content: '';
          display: block;
          width: 100%;
          height: 0.08vh;
          background: repeating-linear-gradient(
            to right,
            rgba(0, 0, 0, 0.15),
            rgba(0, 0, 0, 0.15) 8px,
            transparent 8px,
            transparent 16px /* 线条间隔 */
          );
        }
      }
      .el-collapse-item__wrap {
        border: none;
      }
      .el-collapse-item__content {
        padding-bottom: 0;
      }

      .child-list {
        .child-list-item {
          height: 6.67vh;
          font-size: $font-size-5;
          line-height: 1.5em;
          display: flex;
          align-items: center;
          justify-content: space-between;
          padding-left: 72px;
          position: relative;
          &::after {
            position: absolute;
            bottom: 0;
            content: '';
            display: block;
            width: 100%;
            height: 0.08vh;
            background: repeating-linear-gradient(
              to right,
              rgba(0, 0, 0, 0.15),
              rgba(0, 0, 0, 0.15) 8px,
              transparent 8px,
              transparent 16px /* 线条间隔 */
            );
          }
        }
      }
    }

    .select-icon {
      cursor: pointer;
    }
  }
}
</style>
