// Utils
import { isDef } from '../utils/commonUtil';
import { scrollLeftTo, scrollTopTo } from './utils';
import { isHidden } from '../_utils/dom/style';
import { on, off } from '../_utils/dom/event';
import { getElementTop, getVisibleHeight, getVisibleTop } from '../_utils/dom/scroll';

// Mixins
import { ParentMixin } from '../mixins/relation';

// Components
import Title from './title';
import Sticky from '../sticky';
import Content from './content';
import './index.less';

export default {
    name: 'SnTabs',

    mixins: [ParentMixin('snTabs')],

    model: {
        prop: 'active'
    },

    props: {
        color: String,
        sticky: Boolean,
        animated: Boolean,
        swipeable: Boolean,
        scrollspy: Boolean,
        background: String,
        lineWidth: {
            type: [Number, String],
            'default': '.52rem'
        },
        lineHeight: [Number, String],
        titleActiveColor: String,
        titleInactiveColor: String,
        type: {
            type: String,
            'default': 'line'
        },
        active: {
            type: [Number, String],
            'default': 0
        },
        border: {
            type: Boolean,
            'default': true
        },
        ellipsis: {
            type: Boolean,
            'default': true
        },
        duration: {
            type: [Number, String],
            'default': 0.3
        },
        offsetTop: {
            type: [Number, String],
            'default': 0
        },
        lazyRender: {
            type: Boolean,
            'default': true
        },
        swipeThreshold: {
            type: [Number, String],
            'default': 4
        }
    },

    data: function data() {
        return {
            position: '',
            currentIndex: null,
            lineStyle: {
                backgroundColor: this.color
            }
        };
    },


    computed: {
        // whether the nav is scrollable
        scrollable: function scrollable() {
            return this.children.length > this.swipeThreshold || !this.ellipsis;
        },
        navStyle: function navStyle() {
            return {
                borderColor: this.color,
                background: this.background
            };
        },
        currentName: function currentName() {
            var activeTab = this.children[this.currentIndex];

            if (activeTab) {
                return activeTab.computedName;
            }
            return '';
        },
        scrollOffset: function scrollOffset() {
            if (this.sticky) {
                return +this.offsetTop + this.tabHeight;
            }
            return 0;
        }
    },

    watch: {
        color: 'setLine',

        active: function active(name) {
            if (name !== this.currentName) {
                this.setCurrentIndexByName(name);
            }
        },
        children: function children() {
            var _this = this;

            this.setCurrentIndexByName(this.currentName || this.active);
            this.setLine();

            this.$nextTick(function () {
                _this.scrollIntoView(true);
            });
        },
        currentIndex: function currentIndex() {
            this.scrollIntoView();
            this.setLine();

            // scroll to correct position
            // if (this.stickyFixed && !this.scrollspy) {
            //     setRootScrollTop(Math.ceil(getElementTop(this.$el) - this.offsetTop));
            // }
        },
        scrollspy: function scrollspy(val) {
            if (val) {
                on(window, 'scroll', this.onScroll, true);
            } else {
                off(window, 'scroll', this.onScroll);
            }
        }
    },

    mounted: function mounted() {
        this.onShow();
        on(window, 'resize', this.resize, true);
    },
    activated: function activated() {
        this.onShow();
        this.setLine();
        on(window, 'resize', this.resize, true);
    },
    deactivated: function deactivated() {
        off(window, 'resize', this.resize);
    },
    beforeDestroy: function beforeDestroy() {
        off(window, 'resize', this.resize);
    },


    methods: {
        // 窗口resize事件
        resize: function resize() {
            this.setLine();
        },
        onShow: function onShow() {
            var _this2 = this;

            this.$nextTick(function () {
                _this2.inited = true;
                _this2.tabHeight = getVisibleHeight(_this2.$refs.wrap);
                _this2.scrollIntoView(true);
            });
        },


        // 更新导航栏样式
        setLine: function setLine() {
            var _this3 = this;

            var shouldAnimate = this.inited;

            this.$nextTick(function () {
                var titles = _this3.$refs.titles;


                if (!titles || !titles[_this3.currentIndex] || _this3.type !== 'line' || isHidden(_this3.$el)) {
                    return;
                }

                var title = titles[_this3.currentIndex].$el;
                var lineWidth = _this3.lineWidth,
                    lineHeight = _this3.lineHeight;

                var width = isDef(lineWidth) ? lineWidth : title.offsetWidth / 2 + 'px';
                var left = title.offsetLeft + title.offsetWidth / 2;

                var lineStyle = {
                    width: width,
                    backgroundColor: _this3.color,
                    transform: 'translateX(' + left + 'px) translateX(-50%)'
                };

                if (shouldAnimate) {
                    lineStyle.transitionDuration = _this3.duration + 's';
                }

                if (isDef(lineHeight)) {
                    var height = lineHeight;
                    lineStyle.height = height;
                    lineStyle.borderRadius = height;
                }

                _this3.lineStyle = lineStyle;
            });
        },


        // 根据name设置当前索引
        setCurrentIndexByName: function setCurrentIndexByName(name) {
            var matched = this.children.filter(function (tab) {
                return tab.computedName === name;
            });
            var defaultIndex = (this.children[0] || {}).index || 0;
            this.setCurrentIndex(matched.length ? matched[0].index : defaultIndex);
        },
        setCurrentIndex: function setCurrentIndex(currentIndex) {
            currentIndex = this.findAvailableTab(currentIndex);

            if (isDef(currentIndex) && currentIndex !== this.currentIndex) {
                var shouldEmitChange = this.currentIndex !== null;
                this.currentIndex = currentIndex;
                this.$emit('input', this.currentName);

                if (shouldEmitChange) {
                    this.$emit('change', this.currentName, this.children[currentIndex].title);
                }
            }
        },
        findAvailableTab: function findAvailableTab(index) {
            var diff = index < this.currentIndex ? -1 : 1;

            while (index >= 0 && index < this.children.length) {
                if (!this.children[index].disabled) {
                    return index;
                }

                index += diff;
            }
        },


        // 点击title栏触发事件
        onClick: function onClick(index) {
            var _children$index = this.children[index],
                title = _children$index.title,
                disabled = _children$index.disabled,
                computedName = _children$index.computedName;

            if (disabled) {
                this.$emit('disabled', computedName, title);
            } else {
                if (this.$listeners['before-change']) {
                    this.$emit('before-change', computedName, title);
                } else {
                    this.setCurrentIndex(index);
                    this.scrollToCurrentContent();
                    this.$emit('click', computedName, title);
                }
            }
        },


        // 锁定选中页签在可视区域内
        scrollIntoView: function scrollIntoView(immediate) {
            var titles = this.$refs.titles;


            if (!this.scrollable || !titles || !titles[this.currentIndex]) {
                return;
            }

            var nav = this.$refs.nav;

            var title = titles[this.currentIndex].$el;
            var to = title.offsetLeft - (nav.offsetWidth - title.offsetWidth) / 2;

            scrollLeftTo(nav, to, immediate ? 0 : +this.duration);
        },
        onSticktScroll: function onSticktScroll(params) {
            this.stickyFixed = params.isFixed;
            this.$emit('scroll', params);
        },
        scrollToCurrentContent: function scrollToCurrentContent() {
            var _this4 = this;

            if (this.scrollspy) {
                this.clickedScroll = true;
                var instance = this.children[this.currentIndex];
                var el = instance && instance.$el;
                if (el) {
                    var to = Math.ceil(getElementTop(el)) - this.scrollOffset;
                    scrollTopTo(to, +this.duration, function () {
                        _this4.clickedScroll = false;
                    });
                }
            }
        },
        onScroll: function onScroll() {
            if (this.scrollspy && !this.clickedScroll) {
                var index = this.getCurrentIndexOnScroll();
                this.setCurrentIndex(index);
            }
        },
        getCurrentIndexOnScroll: function getCurrentIndexOnScroll() {
            var children = this.children;


            for (var index = 0; index < children.length; index++) {
                var top = getVisibleTop(children[index].$el);

                if (top > this.scrollOffset) {
                    return index === 0 ? 0 : index - 1;
                }
            }

            return children.length - 1;
        }
    },

    render: function render() {
        var _this5 = this;

        var h = arguments[0];
        var type = this.type,
            ellipsis = this.ellipsis,
            animated = this.animated,
            scrollable = this.scrollable;


        var Nav = this.children.map(function (item, index) {
            return h(Title, {
                ref: 'titles',
                refInFor: true,
                attrs: { type: type,
                    dot: item.dot,
                    info: item.info,
                    title: item.title,
                    color: _this5.color,

                    isActive: index === _this5.currentIndex,
                    ellipsis: ellipsis,
                    disabled: item.disabled,
                    scrollable: scrollable,
                    activeColor: _this5.titleActiveColor,
                    inactiveColor: _this5.titleInactiveColor,
                    swipeThreshold: _this5.swipeThreshold
                },
                style: item.titleStyle, scopedSlots: {
                    'default': function _default() {
                        return item.$slots['title'];
                    }
                },
                on: {
                    'click': function click() {
                        _this5.onClick(index);
                    }
                }
            });
        });

        var Wrap = h(
            'div',
            {
                ref: 'wrap',
                'class': {
                    'sn-tabs-wrap': true,
                    'sn-tabs-scrollable': scrollable
                }
            },
            [h(
                'div',
                {
                    ref: 'nav',
                    attrs: { role: 'tablist'
                    },
                    'class': ['sn-tabs-nav', 'sn-tabs-nav-' + type],
                    style: this.navStyle
                },
                [this.$slots['nav-left'], Nav, type === 'line' && h('div', {
                    'class': 'sn-tabs-indicator-line',
                    style: this.lineStyle
                }), this.$slots['nav-right']]
            )]
        );

        return h(
            'div',
            { 'class': ['sn-tabs', 'sn-tabs-' + type] },
            [this.sticky ? h(
                Sticky,
                {
                    attrs: {
                        container: this.$el,
                        offsetTop: this.offsetTop
                    },
                    on: {
                        'scroll': this.onSticktScroll
                    }
                },
                [Wrap]
            ) : Wrap, h(
                Content,
                {
                    attrs: {
                        count: this.children.length,
                        animated: animated,
                        duration: this.duration,
                        swipeable: this.swipeable,
                        currentIndex: this.currentIndex
                    },
                    on: {
                        'change': this.setCurrentIndex
                    }
                },
                [this.$slots['default']]
            )]
        );
    }
};