const throttle = function (func, wait, options) {
    let context
    let args
    let result
    let timeout = null
    // 上次执行时间点
    let previous = 0
    if (!options) options = {}
    // 延迟执行函数
    const later = function () {
        // 若设定了开始边界不执行选项，上次执行时间始终为0
        previous = options.leading === false ? 0 : Date.now()
        timeout = null
        result = func.apply(context, args)
        if (!timeout) context = args = null
    }
    return function () {
        const now = Date.now()
        // 首次执行时，如果设定了开始边界不执行选项，将上次执行时间设定为当前时间。
        if (!previous && options.leading === false) previous = now
        // 延迟执行时间间隔
        const remaining = wait - (now - previous)
        context = this
        args = arguments
        // 延迟时间间隔remaining小于等于0，表示上次执行至此所间隔时间已经超过一个时间窗口
        // remaining大于时间窗口wait，表示客户端系统时间被调整过
        if (remaining <= 0 || remaining > wait) {
            clearTimeout(timeout)
            timeout = null
            previous = now
            result = func.apply(context, args)
            if (!timeout) context = args = null
            // 如果延迟执行不存在，且没有设定结尾边界不执行选项
        } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining)
        }
        return result
    }
}

Component({
    options: {
        addGlobalClass: true,
        pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
    },
    properties: {
        list: {
            type: Array,
            value: [],
            observer: function (newVal) {
                if (newVal.length === 0) return
                const data = this.data
                const alphabet = data.list.map(item => item.alpha)
                this.setData({
                    alphabet,
                    current: alphabet[0]
                }, () => {
                    this.computedSize()
                })
            }

        },
        vibrated: {
            type: Boolean,
            value: true
        }

    },
    data: {
        windowHeight: 612,
        current: 'A',
        intoView: '',
        touching: false,
        alphabet: [],
        _tops: [],
        _anchorItemH: 0,
        _anchorItemW: 0,
        _anchorTop: 0,
        _listUpperBound: 0
    },
    lifetimes: {
        created() {

        },
        attached() {
            this.__scrollTo = throttle(this._scrollTo, 100, {})
            this.__onScroll = throttle(this._onScroll, 100, {})
            const { windowHeight } = wx.getSystemInfoSync()
            this.setData({ windowHeight })
        }
    },
    methods: {
        handleSelectAlpha(current) {
            this.setData({ current, intoView: current })
        },
        choose(e) {
            const item = e.target.dataset.item
            this.triggerEvent('choose', { item })
        },
        scrollTo(e) {
            this.__scrollTo(e)
        },

        _scrollTo(e) {
            const data = this.data
            const clientY = e.changedTouches[0].clientY
            const index = Math.floor((clientY - data._anchorTop) / data._anchorItemH)
            const current = data.alphabet[index]

            this.setData({ current, intoView: current, touching: true })
            // 振动效果
            if (data.vibrated) wx.vibrateShort()
        },

        computedSize() {
            const data = this.data
            // 计算列表每个区块的高度等信息
            const query = this.createSelectorQuery()
            query.selectAll('.index_list_item').boundingClientRect(rects => {
                const result = rects
                data._tops = result.map(item => item.top)
            }).exec()
            // 计算右侧字母栏小区块的高度等信息
            query.select('.anchor-list').boundingClientRect(rect => {
                data._anchorItemH = rect.height / data.alphabet.length
                data._anchorItemW = rect.width
                data._anchorTop = rect.top
            }).exec()
            // 计算滚动区域的上边界
            query.select('.page-select-index').boundingClientRect(rect => {
                data._listUpperBound = rect.top
            })
        },

        // throttle 的延迟
        removeTouching() {
            setTimeout(() => {
                this.setData({ touching: false })
            }, 150)
        },

        onScroll(e) {
            this.__onScroll(e)
        },

        _onScroll(e) {
            const data = this.data
            const { _tops, alphabet } = data
            const scrollTop = e.detail.scrollTop
            let current = ''
            if (scrollTop < _tops[0]) {
                current = alphabet[0]
            } else {
                for (let i = 0, len = _tops.length; i < len - 1; i++) {
                    if (scrollTop >= _tops[i] && scrollTop < _tops[i + 1]) {
                        current = alphabet[i]
                    }
                }
            }

            if (!current) current = alphabet[alphabet.length - 1]
            this.setData({ current })
        }
    }
})
