<script lang="ts" setup>
import { defaultProps, handleTree } from '@/utils/tree'
import * as DeviceCategoryApi from '@/api/pms/productclassify'
import { CaretLeft, CaretRight, Search } from '@element-plus/icons-vue'
import { ElTree } from 'element-plus'

defineOptions({ name: 'DeviceCategoryTree' })

interface DeviceCategoryNode extends Tree {
  parentId?: number
  code?: string
  status?: number
}

const props = defineProps({
  modelValue: {
    type: Number as PropType<number | undefined>,
    default: undefined
  },
  title: {
    type: String,
    default: '设备分类'
  },
  rootId: {
    type: Number,
    default: 0
  },
  rootName: {
    type: String,
    default: '顶级设备分类'
  },
  initSelect: {
    type: Boolean,
    default: false
  },
  showTitle: {
    type: Boolean,
    default: true
  }
})

const emits = defineEmits<{
  (event: 'update:modelValue', value?: number): void
  (event: 'node-click', value: DeviceCategoryNode): void
}>()

const isCollapsed = ref(false)
const deviceCategoryName = ref('')
const deviceCategoryList = ref<DeviceCategoryNode[]>([])
const treeRef = ref<InstanceType<typeof ElTree>>()
const expandedKeys = ref<number[]>([])

const sortTreeBySort = (treeNodes: DeviceCategoryNode[]) => {
  if (!Array.isArray(treeNodes)) return treeNodes

  return [...treeNodes]
    .sort((a, b) => (a.sort ?? 999999) - (b.sort ?? 999999))
    .map((node) => ({
      ...node,
      children: node.children ? sortTreeBySort(node.children as DeviceCategoryNode[]) : undefined
    }))
}

const setCurrentNode = (id?: number) => {
  if (id === undefined || id === null || !treeRef.value) return

  treeRef.value.setCurrentKey(id)
  if (!expandedKeys.value.includes(id)) {
    expandedKeys.value.push(id)
  }
}

const loadTree = async () => {
  try {
    const res = await DeviceCategoryApi.IotProductClassifyApi.getSimpleProductClassifyList()
    const rootNode: DeviceCategoryNode = {
      id: props.rootId,
      name: props.rootName,
      children: sortTreeBySort(handleTree(res) as DeviceCategoryNode[])
    }

    deviceCategoryList.value = [rootNode]
    expandedKeys.value = [props.rootId]

    await nextTick()

    const targetId = props.modelValue ?? (props.initSelect ? props.rootId : undefined)
    if (targetId !== undefined) {
      setCurrentNode(targetId)
      if (props.initSelect && props.modelValue === undefined) {
        emits('update:modelValue', targetId)
      }
    }
  } catch (error) {
    console.error(error)
  }
}

const handleNodeClick = (data: DeviceCategoryNode) => {
  emits('update:modelValue', data.id)
  emits('node-click', data)
}

const filterNode = (val: string, data: DeviceCategoryNode) => !val || data.name.includes(val)

watch(deviceCategoryName, (val) => treeRef.value?.filter(val))
watch(
  () => props.modelValue,
  (val) => setCurrentNode(val),
  { immediate: true }
)

onMounted(loadTree)
</script>

<template>
  <div
    class="device-category-aside relative bg-white dark:bg-[#1d1e1f] shadow rounded-lg transition-all duration-300 ease-in-out overflow-visible"
    :class="[isCollapsed ? 'is-collapsed' : 'p-4']"
  >
    <div v-show="!isCollapsed" class="h-full flex flex-col gap-4 overflow-hidden w-full">
      <h1 v-if="showTitle" class="text-lg font-medium truncate shrink-0">{{ title }}</h1>

      <div class="shrink-0">
        <el-input
          v-model="deviceCategoryName"
          placeholder="请输入设备分类名称"
          clearable
          size="default"
          :prefix-icon="Search"
        />
      </div>

      <div class="flex-1 relative overflow-hidden">
        <el-auto-resizer class="absolute">
          <template #default="{ height }">
            <el-scrollbar :style="{ height: `${height}px` }">
              <el-tree
                ref="treeRef"
                :data="deviceCategoryList"
                :props="defaultProps"
                :expand-on-click-node="false"
                :filter-node-method="filterNode"
                :default-expanded-keys="expandedKeys"
                node-key="id"
                highlight-current
                @node-click="handleNodeClick"
              />
            </el-scrollbar>
          </template>
        </el-auto-resizer>
      </div>
    </div>

    <div class="collapse-handle" @click="isCollapsed = !isCollapsed">
      <el-icon size="12">
        <CaretLeft v-if="!isCollapsed" />
        <CaretRight v-else />
      </el-icon>
    </div>
  </div>
</template>

<style scoped>
.device-category-aside {
  width: 14vw;
  height: calc(
    100vh - 20px - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height)
  );
  min-width: 200px;
  box-sizing: border-box;
  flex-shrink: 0;
}

.device-category-aside.is-collapsed {
  width: 0 !important;
  min-width: 0 !important;
  padding: 0 !important;
  margin-right: -16px;
  overflow: visible !important;
  pointer-events: none;
  box-shadow: none;
}

.collapse-handle {
  position: absolute;
  top: 50%;
  right: -14px;
  z-index: 200;
  display: flex;
  width: 14px;
  height: 60px;
  color: var(--el-text-color-secondary);
  pointer-events: auto;
  cursor: pointer;
  background-color: var(--el-bg-color);
  border: 1px solid var(--el-border-color-light);
  border-left: none;
  border-radius: 0 12px 12px 0;
  transform: translateY(-50%);
  box-shadow: 2px 0 6px rgb(0 0 0 / 5%);
  align-items: center;
  justify-content: center;
}

.is-collapsed .collapse-handle {
  right: -8px;
  border-left: 1px solid var(--el-border-color-light);
}

.collapse-handle:hover {
  color: var(--el-color-primary);
  background-color: var(--el-fill-color-light);
}

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>
