<script lang="tsx">
import { defineComponent, ref, onMounted, watch, PropType } from 'vue'
import { useState } from '../../../hooks/hook-state'
import { divineHandler, divineDelay } from '../../../utils/common'
import BScroll from '@better-scroll/core'
import MouseWheel from '@better-scroll/mouse-wheel'
import ObserveDOM from '@better-scroll/observe-dom'
import ScrollBar from '@better-scroll/scroll-bar'
import * as env from '../../../types/instance.resolver'
BScroll.use(MouseWheel)
BScroll.use(ObserveDOM)
BScroll.use(ScrollBar)

export default defineComponent({
    name: 'SkyBookmark',
    emits: ['selecter', 'close', 'close-whole', 'close-other', 'close-current', 'refresh'],
    props: {
        defaultActive: { type: String },
        dataSource: { type: Array as PropType<Array<env.BookmarkOption>>, default: () => [] }
    },
    setup(props, { emit, slots }) {
        const element = ref<HTMLElement>()
        const wrapper = ref<HTMLElement>()
        const instance = ref<BScroll>()
        const { state, setState } = useState({ elementWidth: 0, wrapperWidth: 0 })

        onMounted(async () => {
            await divineDelay(0)
            await createScrollber()
            return await setStateDistance()
        })

        /**监听数据变化重新计算滚动容器宽度**/
        watch(() => props.dataSource, watchRefresh, { deep: true })
        async function watchRefresh() {
            await divineDelay(0)
            return await setStateDistance()
        }

        /**页面地址变化、滚动到对应节点**/
        watch(() => props.defaultActive, watchScroll, { deep: true })
        async function watchScroll() {
            await divineDelay()
            const index = props.dataSource.findIndex(item => item.path === props.defaultActive)
            const children = Array.from(wrapper.value?.children ?? [])
            const node = children[index] as HTMLElement
            return await divineHandler(Boolean(instance.value) && Boolean(node), {
                handler: () => {
                    /**保存选中项始终在中间**/
                    const distance = state.elementWidth / 2 - node.clientWidth
                    instance.value!.scrollToElement(node, 300, -distance, false)
                }
            })
        }

        /**初始化滚动容器**/
        async function createScrollber() {
            if (!element.value) {
                return new Error('element 初始化节点不存在')
            }
            const bscroll = new BScroll(element.value, {
                probeType: 3,
                click: true,
                scrollX: true,
                scrollY: false,
                bounce: false,
                mouseWheel: true,
                observeDOM: true,
                scrollbar: false
            })
            return (instance.value = bscroll)
        }

        /**获取滚动容器、节点容器宽度**/
        async function setStateDistance() {
            return await setState({
                elementWidth: element.value?.clientWidth || 0,
                wrapperWidth: wrapper.value?.clientWidth || 0
            })
        }

        /**向左侧滚动**/
        async function divineStart() {
            if (!instance.value) {
                return new Error('instance 滚动实例不存在')
            }
            const distance = instance.value?.x ?? 0
            return await divineHandler(distance < 0, {
                handler: () => {
                    instance.value!.scrollTo(Math.min(distance + 300, 0), 0, 300)
                }
            })
        }

        /**向右侧侧滚动**/
        async function divineEnding() {
            if (!instance.value) {
                return new Error('instance 滚动实例不存在')
            }
            const w1 = element.value?.clientWidth ?? 0
            const w2 = wrapper.value?.clientWidth ?? 0
            const distance = instance.value?.x ?? 0
            const offset = w2 - w1 + distance
            return await divineHandler(w2 > w1 && offset > 0, {
                handler: () => {
                    instance.value!.scrollTo(Math.max(distance - 300, w2 - w1 - 2 * (w2 - w1)), 0, 300)
                }
            })
        }

        return () => (
            <div class="skyline-bookmark">
                {state.wrapperWidth > state.elementWidth && (
                    <div class="skyline-ps-6">
                        <el-button text class="skyline-standard" onClick={divineStart}>
                            <el-icon size={16}>
                                <local-skyline-left />
                            </el-icon>
                        </el-button>
                    </div>
                )}
                <div style={{ flex: 1, overflow: 'hidden', padding: '4px 6px' }}>
                    <div ref={element} class="skyline-bookmark__scrollbar">
                        <div ref={wrapper} class="skyline-bookmark__container">
                            {props.dataSource.map(item => (
                                <div class="skyline-bookmark__column" key={item.path}>
                                    {slots.default ? (
                                        slots.default(item, props.defaultActive)
                                    ) : (
                                        <sky-bookmark-item
                                            node={item}
                                            default-active={props.defaultActive}
                                            onSelecter={(data: env.BookmarkOption) => emit('selecter', data)}
                                            onClose={(data: env.BookmarkOption) => emit('close', data)}
                                        ></sky-bookmark-item>
                                    )}
                                </div>
                            ))}
                        </div>
                    </div>
                </div>
                <div class="skyline-pe-6">
                    {state.wrapperWidth > state.elementWidth && (
                        <el-button text class="skyline-standard" onClick={divineEnding}>
                            <el-icon size={16}>
                                <local-skyline-right />
                            </el-icon>
                        </el-button>
                    )}
                    <el-dropdown trigger="click">
                        {{
                            default: () => (
                                <el-button text class="skyline-standard">
                                    <el-icon size={16}>
                                        <local-skyline-menu />
                                    </el-icon>
                                </el-button>
                            ),
                            dropdown: () => (
                                <el-dropdown-menu>
                                    <el-dropdown-item icon={<local-skyline-reload />} onClick={(evt: MouseEvent) => emit('refresh')}>
                                        重新加载
                                    </el-dropdown-item>
                                    <el-dropdown-item icon={<local-skyline-close />} onClick={(evt: MouseEvent) => emit('close-current')}>
                                        关闭当前
                                    </el-dropdown-item>
                                    <el-dropdown-item icon={<local-skyline-swap />} onClick={(evt: MouseEvent) => emit('close-other')}>
                                        关闭其他
                                    </el-dropdown-item>
                                    <el-dropdown-item icon={<local-skyline-line />} onClick={(evt: MouseEvent) => emit('close-whole')}>
                                        关闭全部
                                    </el-dropdown-item>
                                </el-dropdown-menu>
                            )
                        }}
                    </el-dropdown>
                </div>
            </div>
        )
    }
})
</script>

<style lang="scss" scoped>
.skyline-bookmark {
    min-height: 34px;
    user-select: none;
    display: flex;
    align-items: center;
    &__scrollbar {
        width: 100%;
        position: relative;
        white-space: nowrap;
        overflow: hidden;
    }
    &__container {
        display: inline-block;
    }
    &__column {
        display: inline-flex;
        padding-right: 10px;
        &:last-child {
            padding-right: 0px;
        }
        :deep(.el-sky-button),
        .el-sky-button {
            height: 26px;
            padding-block-start: 0;
            padding-block-end: 0;
            padding-inline-start: 10px;
            padding-inline-end: 10px;
            border-style: none;
            border-radius: 2px;
        }
    }
    .skyline-ps-6 {
        padding-inline-start: 6px;
    }
    .skyline-pe-6 {
        padding-inline-end: 6px;
    }
}

.skyline-standard {
    padding: 0;
    width: 26px;
    height: 26px;
    border-radius: 2px;
}
</style>
