import _extends from 'babel-runtime/helpers/extends';
import { createPopper as _createPopper } from '@popperjs/core/lib/popper-lite';
import flip from '@popperjs/core/lib/modifiers/flip';
import arrow from '@popperjs/core/lib/modifiers/arrow';
import preventOverflow from '@popperjs/core/lib/modifiers/preventOverflow';
import offset from '@popperjs/core/lib/modifiers/offset';
import Icon from '../icon';
import Popup from '../popup';
import { doubleRaf } from '../_utils/dom/raf';
import { on, off } from '../_utils/dom/event';
import TransferDom from '../directives/transfer-dom';
import './index.less';

var Popover = {
    name: 'SnPopover',
    directives: { TransferDom: TransferDom },
    props: {
        value: Boolean,
        message: String,
        placement: {
            type: String,
            'default': 'bottom',
            validator: function validator(value) {
                return ['bottom', 'top'].indexOf(value) > -1;
            }
        },
        offset: {
            type: Array,
            'default': function _default() {
                return [0, 8];
            }
        },
        overflowPadding: {
            type: Number,
            'default': 15
        },
        closeable: {
            type: Boolean,
            'default': true
        },
        container: {
            type: String,
            'default': 'body'
        },
        trigger: {
            type: String,
            'default': 'click',
            validator: function validator(value) {
                return ['click', 'hover', 'focus'].indexOf(value) > -1;
            }
        },
        closeOnClickOutside: {
            type: Boolean,
            'default': true
        },
        mouseEnterDelay: {
            type: Number,
            'default': 100
        },
        mouseLeaveDelay: {
            type: Number,
            'default': 100
        },
        disabled: Boolean,
        popperClass: String
    },

    watch: {
        value: 'updateLocation',
        placement: 'updateLocation',
        message: 'updateLocation',
        trigger: function trigger(val) {
            var _$refs = this.$refs,
                wrapperRef = _$refs.wrapperRef,
                popoverRef = _$refs.popoverRef;


            if (val === 'hover') {
                on(wrapperRef, 'mouseenter', this.onMouseEnter, true);
                on(popoverRef.$el, 'mouseenter', this.onMouseEnter, true);
                on(wrapperRef, 'mouseleave', this.onMouseLeave, true);
                on(popoverRef.$el, 'mouseleave', this.onMouseLeave, true);
            } else if (val === 'click') {
                off(wrapperRef, 'mouseenter', this.onMouseEnter);
                off(popoverRef.$el, 'mouseenter', this.onMouseEnter);
                off(wrapperRef, 'mouseleave', this.onMouseLeave);
                off(popoverRef.$el, 'mouseleave', this.onMouseLeave);

                clearTimeout(this._timer);
            }
        }
    },

    mounted: function mounted() {
        this.updateLocation();

        var wrapperRef = this.$refs.wrapperRef;


        if (this.trigger === 'hover') {
            on(wrapperRef, 'mouseenter', this.onMouseEnter, true);
            on(wrapperRef, 'mouseleave', this.onMouseLeave, true);
        }

        if (this.trigger === 'focus') {
            on(wrapperRef, 'focusin', this.doShow, true);
            on(wrapperRef, 'focusout', this.doHide, true);
        }
    },
    beforeDestroy: function beforeDestroy() {
        if (this.popper) {
            this.popper.destroy();
            this.popper = null;
            off(document, 'click', this.onClickOutside);

            var _$refs2 = this.$refs,
                wrapperRef = _$refs2.wrapperRef,
                popoverRef = _$refs2.popoverRef;

            off(wrapperRef, 'mouseenter', this.onMouseEnter);
            off(popoverRef.$el, 'mouseenter', this.onMouseEnter);
            off(wrapperRef, 'mouseleave', this.onMouseLeave);
            off(popoverRef.$el, 'mouseleave', this.onMouseLeave);
            off(wrapperRef, 'focusin', this.onShow);
            off(wrapperRef, 'focusout', this.onHide);

            clearTimeout(this._timer);
        }
    },


    methods: {
        createPopper: function createPopper() {
            var _$refs3 = this.$refs,
                wrapperRef = _$refs3.wrapperRef,
                popoverRef = _$refs3.popoverRef,
                arrowRef = _$refs3.arrowRef;


            return _createPopper(wrapperRef, popoverRef.$el, {
                placement: this.placement,
                shift: true,
                modifiers: [{
                    name: 'computeStyles',
                    options: {
                        gpuAcceleration: false,
                        adaptive: false
                    }
                }, _extends({}, offset, {
                    options: {
                        offset: this.offset
                    }
                }), _extends({}, preventOverflow, {
                    options: {
                        boundariesElement: document,
                        padding: this.overflowPadding
                    }
                }), _extends({}, arrow, {
                    options: {
                        element: arrowRef
                    }
                }), _extends({}, flip, {
                    options: {
                        fallbackPlacements: []
                    }
                })]
            });
        },
        updateLocation: function updateLocation() {
            var _this = this;

            this.$nextTick(function () {
                if (!_this.value) {
                    return;
                }

                if (!_this.popper) {
                    _this.popper = _this.createPopper();

                    doubleRaf(function () {
                        var _popper$state = _this.popper.state,
                            placement = _popper$state.placement,
                            styles = _popper$state.styles;

                        var _ref = styles || {},
                            arrow = _ref.arrow;

                        _this.$refs.popoverRef.$el.style['transform-origin'] = arrow.left + ' ' + (placement.indexOf('top') !== -1 ? '100%' : '0');

                        var popoverRef = _this.$refs.popoverRef;


                        if (_this.trigger === 'hover') {
                            on(popoverRef.$el, 'mouseenter', _this.onMouseEnter, true);
                            on(popoverRef.$el, 'mouseleave', _this.onMouseLeave, true);
                        }

                        // 设置延时处理外部点击在弹起气泡时触发
                        setTimeout(function () {
                            on(document, 'click', _this.onClickOutside);
                        });
                    });
                } else {
                    _this.popper.setOptions({
                        placement: _this.placement
                    });

                    _this.$nextTick(function () {
                        var _popper$state2 = _this.popper.state,
                            placement = _popper$state2.placement,
                            styles = _popper$state2.styles;

                        var _ref2 = styles || {},
                            arrow = _ref2.arrow;

                        _this.$refs.popoverRef.$el.style['transform-origin'] = arrow.left + ' ' + (placement.indexOf('top') !== -1 ? '100%' : '0');
                    });
                }
            });
        },
        onClick: function onClick() {
            this.$emit('click');
        },
        onToggle: function onToggle(value) {
            if (this.disabled) return;

            this.$emit('input', !value);
        },
        onClickWrapper: function onClickWrapper() {
            var trigger = this.trigger;


            if (trigger === 'click') {
                this.onToggle(this.value);
            }
        },
        onContentClick: function onContentClick(e) {
            e.stopPropagation();
        },
        onCloseClick: function onCloseClick() {
            if (this.closeable) {
                this.$emit('inside-close');
                this.$emit('input', false);
            }
        },
        onClickOutside: function onClickOutside(e) {
            if (this.closeOnClickOutside && this.$el && !this.$el.contains(e.target)) {
                this.$emit('input', false);
            }
        },
        onPopupInput: function onPopupInput(val) {
            this.$emit('input', val);
        },
        onOpen: function onOpen() {
            this.$emit('open');
        },
        onOpened: function onOpened() {
            this.$emit('opened');
        },
        onClose: function onClose() {
            this.$emit('close');
        },
        onClosed: function onClosed() {
            this.$emit('closed');
        },
        onMouseEnter: function onMouseEnter() {
            var _this2 = this;

            if (this.disabled) return;

            clearTimeout(this._timer);
            this._timer = setTimeout(function () {
                _this2.$emit('input', true);
            }, this.mouseEnterDelay);
        },
        onMouseLeave: function onMouseLeave() {
            var _this3 = this;

            if (this.disabled) return;

            clearTimeout(this._timer);
            this._timer = setTimeout(function () {
                _this3.$emit('input', false);
            }, this.mouseLeaveDelay);
        },
        doShow: function doShow() {
            if (this.disabled) return;

            this.$emit('input', true);
        },
        doHide: function doHide() {
            if (this.disabled) return;

            this.$emit('input', false);
        }
    },

    render: function render() {
        var h = arguments[0];
        var value = this.value,
            message = this.message,
            container = this.container,
            closeable = this.closeable,
            popperClass = this.popperClass,
            $slots = this.$slots;


        return h(
            'span',
            {
                ref: 'wrapperRef',
                'class': 'sn-popover-wrapper',
                on: {
                    'click': this.onClickWrapper
                }
            },
            [$slots['default'], h(
                'div',
                {
                    directives: [{
                        name: 'transfer-dom',
                        value: container
                    }]
                },
                [h(
                    Popup,
                    {
                        ref: 'popoverRef',
                        attrs: { role: 'tooltip',

                            value: value,
                            overlay: false,
                            lockScroll: false,
                            position: null,
                            transition: 'sn-popover-zoom',
                            adjustKeyboard: false
                        },
                        'class': ['sn-popover', popperClass], on: {
                            'input': this.onPopupInput,
                            'open': this.onOpen,
                            'opened': this.onOpened,
                            'close': this.onClose,
                            'closed': this.onClosed
                        }
                    },
                    [h(
                        'div',
                        {
                            'class': 'sn-popover-content',
                            on: {
                                'click': this.onContentClick
                            }
                        },
                        [h(
                            'div',
                            { 'class': 'sn-popover-content-message' },
                            [$slots['message'] || message]
                        ), closeable ? h(Icon, {
                            attrs: {
                                type: 'close'
                            },
                            'class': 'sn-popover-content-close',
                            on: {
                                'click': this.onCloseClick
                            }
                        }) : null]
                    ), h(Icon, {
                        ref: 'arrowRef',
                        attrs: { type: 'popover'
                        },
                        'class': 'sn-popover-arrow'
                    })]
                )]
            )]
        );
    }
};

Popover.install = function (Vue) {
    Vue.component(Popover.name, Popover);
};

export default Popover;