<template>
    <div
        v-loading="dataLoading"
        class="tree-side"
        element-loading-background="rgba(10 ,38 ,61, 0.9)"
    >
        <!-- tab选项 -->
        <el-tabs v-model="activeTab" :type="tabType" @tab-click="handleClick">
            <template v-if="tabList.length">
                <el-tab-pane
                    v-for="(item, index) in tabList"
                    :key="index"
                    :label="item"
                    :name="item + ''"
                >
                </el-tab-pane>
            </template>
            <!-- 筛选框 -->
            <div class="tree-header">
                <el-input v-model="filterText" clearable placeholder="请输入">
                    <template #prefix>
                        <el-icon>
                            <Search />
                        </el-icon>
                    </template>
                </el-input>
                <div class="tree-button-group">
                    <i
                        v-if="expand"
                        :class="[
                            'expand-icon',
                            'fvue-icon',
                            `fvue-icon-${expandAll ? 'shouqi' : 'zhankai'}`
                        ]"
                        :title="expandAll ? '收起' : '展开'"
                        @click="expandHandle(!expandAll)"
                    />
                    <i
                        v-if="refresh"
                        :class="['el-icon-refresh', refreshLading ? 'el-icon-refresh-loading' : '']"
                        title="刷新"
                        @click="refreshData"
                    />
                </div>
            </div>
            <!-- 树形数据 -->
            <el-scrollbar>
                <el-tree
                    ref="treeRef"
                    :check-strictly="checkStrictlyValue"
                    :data="treeData"
                    :default-expand-all="defaultExpandAll"
                    :expand-on-click-node="false"
                    :filter-node-method="filterNode"
                    :highlight-current="true"
                    :node-key="nodeKey"
                    :props="defaultProps"
                    :show-checkbox="showCheckboxValue"
                    class="filter-tree tree-content"
                    v-bind="attrs"
                    @check-change="checkChange"
                    @current-change="currentChange"
                    @node-expand="nodeExpand"
                >
                    <template #default="{ node, data }">
                        <div class="tree-item">
                            <template v-if="!hideIcon">
                                <el-icon v-if="!attrs.customIcon">
                                    <Folder v-if="data.children" />
                                    <Tickets v-else />
                                </el-icon>
                                <template v-else>
                                    <slot :data="data" name="treeIcon"></slot>
                                </template>
                            </template>
                            <span
                                :class="['custom-node-text', isOperate ? 'operate-node-text' : '']"
                                :title="
                                    data[defaultProps.label] +
                                    (data[defaultProps.number]
                                        ? '（' + data[defaultProps.number] + '）'
                                        : '')
                                "
                                v-html="
                                    brightenKeyword(
                                        data[defaultProps.label],
                                        data[defaultProps.number]
                                    )
                                "
                            ></span>
                            <el-dropdown
                                v-if="isOperate"
                                class="tree-drop"
                                trigger="click"
                                @command="handleCommand"
                            >
                                <el-icon :style="{ color: 'var(--theme-text-inverse)' }">
                                    <More />
                                </el-icon>
                                <template v-slot:dropdown>
                                    <el-dropdown-menu>
                                        <template v-if="data.id">
                                            <el-dropdown-item
                                                v-for="(item, index) in dropdownMenu"
                                                :key="index"
                                                :command="{
                                                    type: item.type,
                                                    dropdownItem: data
                                                }"
                                                :disabled="!!btnDisableKey && !data[btnDisableKey]"
                                                :divided="!!item.divided"
                                                :icon="item.icon"
                                            >
                                                {{ item.type }}
                                            </el-dropdown-item>
                                        </template>
                                        <template v-else>
                                            <el-dropdown-item
                                                :command="{
                                                    type: '新增',
                                                    dropdownItem: data
                                                }"
                                                icon="EditPen"
                                            >
                                                新增
                                            </el-dropdown-item>
                                        </template>
                                    </el-dropdown-menu>
                                </template>
                            </el-dropdown>
                        </div>
                    </template>
                </el-tree>
            </el-scrollbar>
        </el-tabs>
    </div>
</template>

<script lang="ts" setup>
import { defineEmits, defineProps, onMounted, ref, useAttrs, watch } from 'vue'

interface DropdownMenuItem {
    icon: string
    type: string
    divided?: boolean
}

const props = withDefaults(
    defineProps<{
        expand?: boolean
        tabList?: any[]
        treeData?: any[]
        defaultProps?: {
            label: string
            children: string
            number?: string
        }
        activeName?: string
        isOperate?: boolean
        dropdownMenu?: DropdownMenuItem[]
        isDeselect?: boolean
        btnDisableKey?: string
        defaultExpandAll?: boolean
        dataLoading?: boolean
        tabType?: string
        nodeKey?: string
        hideIcon?: boolean
        refresh?: boolean
        showCheckboxValue?: boolean
        checkStrictlyValue?: boolean
    }>(),
    {
        expand: true,
        tabList: () => [],
        treeData: () => [],
        defaultProps: () => ({ label: 'label', children: 'children' }),
        activeName: '',
        isOperate: false,
        dropdownMenu: () => [
            { icon: 'EditPen', type: '新增' },
            { icon: 'Edit', type: '编辑' },
            { icon: 'Delete', type: '删除' }
        ],
        isDeselect: false,
        btnDisableKey: '',
        defaultExpandAll: false,
        dataLoading: false,
        tabType: '',
        nodeKey: 'id',
        hideIcon: false,
        refresh: false,
        showCheckboxValue: false,
        checkStrictlyValue: false
    }
)

const emit = defineEmits([
    'filterChange',
    'tabChange',
    'update:activeName',
    'currentChange',
    'checkChange',
    'operateEvent',
    'refresh'
])

const attrs = useAttrs()

const treeRef = ref(null)
const activeTab = ref('')

const refreshLading = ref(false)
const currentNode = ref({})
const expandAll = ref(false)

const handleClick = () => {
    filterText.value = ''
    emit('tabChange', activeTab.value)
    emit('update:activeName', activeTab.value)
}

// 初始化activeTab
const initActiveTab = () => {
    activeTab.value = props.activeName || (props.tabList.length > 0 ? props.tabList[0] : '')
}

// 监听tabList变化
watch(
    () => props.tabList,
    () => {
        if (!activeTab.value && props.tabList.length > 0) {
            initActiveTab()
        }
    },
    { immediate: true }
)

// 监听activeName变化
watch(
    () => props.activeName,
    (newVal) => {
        if (newVal) {
            activeTab.value = newVal
        }
    },
    { immediate: true }
)

onMounted(() => {
    expandAll.value = props.defaultExpandAll
    initActiveTab()
})

const filterText = ref('')

watch(filterText, (val) => {
    console.log('treeRefs', treeRef.value)
    treeRef.value && treeRef.value.filter(val)
    emit('filterChange', val)
})

function filterNode(value, data) {
    if (!value) return true
    return data[props.defaultProps.label].indexOf(value) !== -1
}

const currentChange = (value, data) => {
    try {
        if (!treeRef.value || !value) return

        // Initialize currentNode if empty
        if (!currentNode.value || !currentNode.value[props.defaultProps.label]) {
            currentNode.value = value
            emit('currentChange', value, data, activeTab.value)
            return
        }

        // Compare nodes by nodeKey if available, otherwise by label
        const compareKey = props.nodeKey || props.defaultProps.label
        if (currentNode.value[compareKey] === value[compareKey]) {
            if (props.isDeselect) return
            treeRef.value.setCurrentKey(null)
            currentNode.value = {}
            emit('currentChange', null, data, activeTab.value)
        } else {
            currentNode.value = value
            emit('currentChange', value, data, activeTab.value)
        }
    } catch (error) {
        console.error('Error in currentChange:', error)
    }
}

const checkChange = (data, checked, indeterminate) => {
    const checkedNodes = (treeRef.value && treeRef.value.getCheckedNodes()) || []
    emit('checkChange', checkedNodes, activeTab.value, !checked && data)
}

const handleCommand = (command) => {
    const { type = '', dropdownItem = {} } = command
    emit('operateEvent', type, dropdownItem)
}

const nodeExpand = (data, node) => {
    console.log('nodeExpand', data, node)
}

const expandHandle = (type, level = -1) => {
    expandAll.value = type
    const currentTree = treeRef.value
    if (currentTree) {
        expandNodes(currentTree.store.root, level, 0)
    }
}

const expandNodes = (node, level, currentLevel) => {
    if (level === -1) {
        node.expanded = expandAll.value
    } else {
        node.expanded = currentLevel <= level
    }
    for (let i = 0; i < node.childNodes.length; i++) {
        expandNodes(node.childNodes[i], level, currentLevel + 1)
    }
}

const refreshData = () => {
    refreshLading.value = true
    const done = () => {
        refreshLading.value = false
    }
    emit('refresh', done)
}

const brightenKeyword = (val, number) => {
    const allVal = val + (number ? ' (' + number + ')' : '')
    const escapedKeyword = filterText.value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').trim()
    if (!escapedKeyword) return allVal
    const regex = new RegExp(escapedKeyword, 'gi')
    return allVal.replace(regex, (match) => `<span style="color: #f56c6c">${match}</span>`)
}

const setCheckedNodes = (nodes) => {
    treeRef.value && treeRef.value.setCheckedNodes(nodes)
}

const setCurrentKey = (key) => {
    treeRef.value && treeRef.value.setCurrentKey(key)
}

const getCheckedNodes = () => {
    return treeRef.value && treeRef.value.getCheckedNodes()
}

defineExpose({
    setCheckedNodes,
    setCurrentKey,
    getCheckedNodes,
    expandHandle
})
</script>

<style lang="scss" scoped>
.tree-side {
    padding: 10px 16px;
    box-sizing: border-box;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    height: 100%;

    :deep {
        .el-scrollbar__wrap {
            overflow-y: auto;
        }

        .el-scrollbar__bar.is-horizontal {
            display: none;
        }
    }

    :deep(.el-tabs) {
        display: flex;
        flex-direction: column;

        .el-tabs__content {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .el-tabs__item {
            font-size: 13.5px;
            padding: 0 10px;

            &:nth-child(2) {
                padding: 0 10px 0 0;
            }
        }

        .el-tab-pane {
            display: flex;
            flex-direction: column;
            row-gap: 20px;
            display: none;

            .el-scrollbar {
                // height: 0;
                flex: 1;

                .el-tree {
                    background-color: transparent !important;

                    &.tree-content {
                        border: none;
                    }
                }
            }
        }
    }

    .tree-header {
        display: flex;
        column-gap: 12px;
        align-items: center;

        .el-input {
            flex: 1;
        }

        .tree-button-group {
            display: flex;
            align-items: center;
            height: 100%;
            column-gap: 10px;

            .el-icon-refresh {
                font-weight: bold;
                font-size: 18px;
                margin-top: 2px;

                &.el-icon-refresh-loading {
                    animation: rotate 1.5s linear infinite;
                    -webkit-animation: rotate 1.5s linear infinite;

                    @keyframes rotate {
                        0% {
                            transform: rotate(0);
                        }
                        25% {
                            transform: rotate(90deg);
                        }
                        50% {
                            transform: rotate(180deg);
                        }
                        75% {
                            transform: rotate(270deg);
                        }
                        100% {
                            transform: rotate(360deg);
                        }
                    }
                }
            }

            .expand-icon {
                transform: rotate(45deg);
                font-size: 13px;

                &.fvue-icon-zhankai {
                    transform: rotate(45deg) scale(1.25);
                }
            }

            i {
                cursor: pointer;
                font-size: 16px;
                color: $color-text-placeholder;

                &:hover {
                    color: $system-hover-active-text;
                }
            }
        }
    }
}

.tree-item {
    width: calc(100% - 30px);
    display: flex;
    align-items: center;
    justify-content: start;
}

:deep(.el-tree-node__content) {
    height: 34px;

    &:hover {
        background-color: var(--theme-box-color-5);
    }
}

:deep(.custom-node-text) {
    font-size: 14px;
    margin-left: 5px;
    display: inline-block;
    width: calc(100%);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;

    span {
        font-size: 14px;
    }
}

:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
    background: var(--theme-box-color-3);

    .el-icon-tickets,
    .custom-node-text {
        color: $system-hover-active-text;
    }
}

:deep(.el-tree-node:focus > .el-tree-node__content) {
    background-color: transparent;
}

:deep(.el-input__inner) {
    font-size: 14px;
}

.el-icon-folder,
.el-icon-tickets {
    width: 14px;
}

.el-icon-more {
    font-size: 14px;
    transform: rotate(90deg);
    height: 25px;
    color: $color-text-placeholder;
}

:deep(.el-tree-node__content .tree-item .el-dropdown) {
    left: 0;
}

:deep(.el-dropdown-menu__item) {
    height: 32px;
    display: flex;
    justify-content: center;
    align-items: center;

    div {
        font-size: 14px;
    }
}

:deep(.el-dropdown-menu__item--divided) {
    display: block;
    min-height: 35px;
    line-height: 32px;
    text-align: center;
}

.el-node-icon,
:deep(.el-icon-search) {
    font-size: 15px;
}

:deep(.el-node-icon) {
    color: $color-text-placeholder;
}
</style>
