<template>
    <el-tabs
        ref="elTabRef"
        v-model="activeName"
        class="infoTabs"
        :tab-position="configTab.tabPosition || 'top'"
        :type="configTab.type"
        :addable="configTab.addable"
        :editable="configTab.editable"
        :before-leave="beforeLeave"
        @tab-click="handleClick"
        @tab-remove="handlerRemove"
        @tab-add="addTab"
    >
        <template v-for="(item, key) in configTab.data">
            <el-tab-pane
                v-if="item.show === undefined ? true : item.show()"
                :key="key"
                :name="key"
                :closable="item.closable"
                :disabled="typeof item.disabled === 'function' ? item.disabled() : item.disabled"
                :class="{'not-view': !!configTab.activeComponent}"
            >
                <template
                    #label
                >
                    <el-input
                        v-if="item.labelEdit"
                        v-model="item.label"
                        v-focus="{vm: that, key: key}"
                        size="small"
                        :placeholder="$t('name')"
                        @blur="inputBlur(item)"
                    />
                    <el-badge
                        v-else
                        :value="typeof item.count === 'function' ? item.count() : item.count"
                    >
                        <span>{{ typeof item.label === 'function' ? $t(item.label()) : $t(item.label) }}</span>
                    </el-badge>
                </template>
                <slot :value="item" />
            </el-tab-pane>
        </template>
        <router-view
            v-if="configTab.routeName"
            ref="tabView"
        />
    </el-tabs>
</template>
<script lang="ts" setup>
    import { useRoute, useRouter, RouteLocationNamedRaw } from 'vue-router'
    import { getCurrentInstance, ref, watch, onMounted, nextTick, onUpdated } from 'vue'
    import { confirm, ObjectInterface } from '../../script/index'
    import { ElMessage } from 'element-plus'
    import $ from 'jquery'
    const props = defineProps({
        configTab: {
            type: Object,
            default: () => {
                /* {
                    data: { name: {} },
                    activeComponent: '', // 或routeName
                    routeName: ''
                } */
            }
        }
    })
    const emit = defineEmits(['dblclick', 'paneSlotComponents', 'editCallback', 'addedCallback'])
    const { proxy } = getCurrentInstance() as any
    const vFocus = { // 自动获取焦点
        mounted: (el: Element, binding: ObjectInterface) => { // div.el-input
            const inputDom = el.getElementsByTagName('input')[0]
            inputDom.focus()
            let _this = binding.value.vm
            _this.editingName = binding.value.key
            let data = _this.configTab.data[_this.editingName]
            data.closable === true && (data.closable = false)
        }
    }
    const that = proxy
    const activeName = ref(props.configTab.activeComponent || props.configTab.routeName)
    const isInit = ref(true)
    const clickTimer = ref(0)
    const isEdit = ref(false)
    const elTabRef = ref()
    const editingName = ref('')
    const paneSlotComponents = ref<ObjectInterface>({})
    // 获取插槽中的组件实例
    const getSlotComponents = (paneInstance: any) => {
        if (!paneInstance || !paneInstance.$) return []

        // 获取 el-tab-pane 的 subTree
        const subTree = paneInstance.$.subTree
        if (!subTree || !subTree.children) return []

        const components: any[] = []

        // 遍历 subTree.children 查找组件实例
        const traverse = (children: any) => {
            if (!children) return

            if (Array.isArray(children)) {
                children.forEach(child => {
                    if (child.component) {
                        // Vue 3: 直接返回 component 对象本身
                        // 可以通过 component.setupState 访问 setup 返回的数据
                        // 可以通过 component.ctx 访问上下文
                        components.push(child.component)
                    }
                    // 继续遍历子节点
                    if (child.children) {
                        traverse(child.children)
                    }
                })
            }
        }

        traverse(subTree.children)
        return components
    }
    const nameCount = (keys: number[], max: number) => { // 默认 0-9
        let num = 0
        for (let i = 0; i < max; i++) {
            if (!keys.includes(i)) {
                num = i
                break
            }
        }
        return num
    }
    const validateFrom = (item: string) => {
        let valid = true
        const sourceVm = paneSlotComponents.value?.[item] as unknown as ObjectInterface
        if (sourceVm) {
            // Vue3 中没有 $children，需要通过其他方式获取子组件
            // 如果组件本身有 validate 方法，直接调用
            if (typeof sourceVm.validate === 'function') {
                valid = sourceVm.validate()
                activeName.value = item
            } else {
                // 尝试通过 $refs 或子组件来验证
                // 如果组件内部有子组件需要验证，可以通过插槽内容来访问
                const childComponents = getSlotComponents(sourceVm)
                for (let child of childComponents) {
                    if (child && typeof child.validate === 'function') {
                        valid = child.validate()
                        activeName.value = item
                        if (!valid) break
                    }
                }
            }
        }
        return valid // this.configTab.beforeLeave ? (this.configTab.beforeLeave(name, old) && valid) : valid
    }
    const validate = () => {
        for (let item in paneSlotComponents.value as any) {
            return validateFrom(item)
        }
    }
    const beforeLeave = (name: string, old: string) => {
        if (props.configTab.activeComponent) { // 非路由模式
            return validateFrom(old)
        }
        let route: RouteLocationNamedRaw = { name: name }
        if (props.configTab.query) {
            route.query = props.configTab.query
        }
        if (props.configTab.data?.[name]?.params) {
            route.params = props.configTab.data[name].params
        }
        // router.push(route).catch(err => err)
    }
    const handleClick = (tab: ObjectInterface, event: ObjectInterface) => {
        if (event.target.tagName === 'INPUT') return
        clearTimeout(clickTimer.value)
        clickTimer.value = window.setTimeout(() => {
            isInit.value = true
            props.configTab.method?.(tab.paneName)
        }, 300)
    }
    const removeTab = (targetName: string) => {
        if (isEdit.value) return
        let tabs = Object.keys(props.configTab.data)
        let activeName1 = activeName.value
        if (activeName1 === targetName) {
            for (let [index, tab] of tabs.entries()) {
                if (tab === targetName) {
                    let nextTab = tabs[index + 1] || tabs[index - 1]
                    if (nextTab) {
                        activeName1 = nextTab
                        props.configTab.method?.({
                            name: nextTab
                        })
                    }
                }
            }
        }
        delete props.configTab.data[targetName]
        activeName.value = activeName1
        props.configTab.removeMethod?.(targetName)
    }
    const handlerRemove = (targetName: string) => {
        if (props.configTab.secondaryDelete) { // 控制删除之前是否二次确认 默认不提示
            confirm($t('confirmDelete'), () => {
                removeTab(targetName)
            })
            return
        }
        removeTab(targetName)
    }
    const addTab = () => {
        let keys: number[] = []
        for (let key in props.configTab.data) {
            const last = key.substr(-1)
            if (!isNaN(Number(last))) {
                keys.push(Number(last))
            }
        }
        const max = props.configTab.addMax || 10
        if (keys.length === max) {
            ElMessage.warning($t('addTabMax'))
            return
        }
        let num = keys.length ? nameCount(keys, max) : 0
        let newTabName = props.configTab.addMethod?.(num)
        activeName.value = newTabName
        isEdit.value = false
    }
    const inputBlur = (row: ObjectInterface) => {
        if (!row.label) {
            proxy.$delete(props.configTab.data, editingName.value)
        } else {
            row.labelEdit = false
            row.closable = true
            if (isEdit.value) {
                emit('editCallback', row)
            } else {
                emit('addedCallback', row)
            }
        }
        isEdit.value = false
    }
    const getPaneSlotComponents = (init: boolean) => {
        if (!elTabRef.value || !elTabRef.value.$) return

        const paneSlotComponents1: ObjectInterface = {}

        // 从 el-tabs 的 subTree 中获取所有 el-tab-pane 实例
        const subTree = elTabRef.value.$.subTree
        if (!subTree || !subTree.children) return

        // 遍历查找所有 el-tab-pane 组件
        const findTabPanes = (children: any): any[] => {
            const panes: any[] = []
            if (!Array.isArray(children)) return panes

            children.forEach((child: any) => {
                if (child.component) {
                    // 获取组件实例
                    const instance = child.component.proxy
                    // 检查是否有 name 属性（el-tab-pane 的特征）
                    if (instance && instance.$ && instance.$.props && instance.$.props.name) {
                        panes.push(instance)
                    }
                }
                // 递归查找子节点
                if (child.children) {
                    panes.push(...findTabPanes(child.children))
                }
            })
            return panes
        }

        const tabPanes = findTabPanes(subTree.children)

        // 遍历每个 tab-pane，获取其插槽中的组件
        for (let pane of tabPanes) {
            const paneName = pane.$.props.name
            const slotComponents = getSlotComponents(pane)

            if (slotComponents.length > 0) {
                paneSlotComponents1[paneName] = slotComponents[0]
            }
        }

        paneSlotComponents.value = paneSlotComponents1

        // 初始化仅通知一次
        isInit.value && emit('paneSlotComponents', paneSlotComponents1, activeName.value)
        !init && (isInit.value = false)
    }
    // watch(() => vueRoute?.path, (to, from) => {
    //     if (props.configTab.activeComponent) return
    //     activeName.value = to
    // })
    watch(() => props.configTab.activeComponent, (newValue, oldValue) => {
        activeName.value = newValue
    })
    // watch(() => props.configTab.routeName, (newValue, oldValue) => {
    //     activeName.value = newValue
    // })
    onMounted(() => {
        // let query = JSON.parse(JSON.stringify(vueRoute.query))
        // Object.assign(query, props.configTab.query)
        // router.replace({query}).catch(err => err)
        getPaneSlotComponents(true)
        nextTick(() => {
            $('.el-tabs__header').on('dblclick', '.el-tabs__item', (e) => {
                clearTimeout(clickTimer.value) // 阻止tab-click事件
                const id = e.currentTarget.id
                const name = id.substring(4)
                let data = props.configTab.data[name]
                if (data.labelEdit !== undefined) {
                    data.labelEdit = true
                    if (data.closable) {
                        data.closable = false
                    }
                    if (isEdit.value) {
                        emit('dblclick', data)
                    }
                    isEdit.value = true
                }
            })
        })
    })
    onUpdated(() => {
        getPaneSlotComponents(false)
    })
    defineExpose({
        paneSlotComponents,
        addTab
    })
</script>
<style lang="scss" scoped>
.infoTabs {
    height: 100%;
    width: 100%;
    :deep(.el-tabs__header) {
        .el-tabs__nav-wrap {
            padding-right: 40px;
            padding-left: 20px;
        }
        /*左侧显示tabs的不需要padding*/
        .is-left {
            padding-right: 0 !important;
        }
        .el-icon-close {
            display: none;
            width: 0;
        }
        .el-badge {
            padding: 0 15px;
        }
        .is-active.el-tabs__item,
        .el-tabs__item:hover {
            .el-icon-close {
                display: inline-block;
                width: 14px;
                margin-left: -14px;
            }
        }
        .el-tabs__new-tab {
            position: absolute;
            right: 20px;
            z-index: 1;
        }
    }
}
.el-input {
    width: 120px;
}
:deep(.el-tab-pane.not-view) {
    height: 100%;
}
:deep(.el-tabs__content) {
    height: calc(100% - 55px);
    overflow: auto;
}
:deep([aria-controls$="Error"]) {
    color: red !important;
}
:deep(.el-badge__content) {
    margin-top: 6px;
}
:deep(.el-tabs__new-tab) {
    border: 1px solid var(--border-color);
    color: var(--text-color);
}
</style>
