import { range } from '../utils/numberUtil';
import { preventDefault } from '../_utils/dom/event';
import { TouchMixin } from '../mixins/touch';
import { MouseMixin } from '../mixins/mouse';
import { ClickOutsideMixin } from '../mixins/click-outside';

import './index.less';

var THRESHOLD = 0.15;

var SwipeAction = {
    name: 'SnSwipeAction',

    mixins: [TouchMixin, MouseMixin, ClickOutsideMixin({
        event: 'touchstart',
        method: 'onClick'
    }), ClickOutsideMixin({
        event: 'click',
        method: 'onClick'
    })],

    props: {
        onClose: Function,
        disabled: Boolean,
        leftWidth: Number,
        rightWidth: Number,
        stopPropagation: Boolean,
        name: {
            type: [Number, String],
            'default': ''
        }
    },

    data: function data() {
        return {
            opened: false,
            offset: 0,
            dragging: false,
            mouseSign: false
        };
    },


    computed: {
        computedLeftWidth: function computedLeftWidth() {
            return this.leftWidth || this.getWidthByRef('left');
        },
        computedRightWidth: function computedRightWidth() {
            return this.rightWidth || this.getWidthByRef('right');
        }
    },

    watch: {
        opened: function opened(val) {
            this.$emit('change', val);
        }
    },

    methods: {
        getWidthByRef: function getWidthByRef(ref) {
            if (this.$refs[ref]) {
                var rect = this.$refs[ref].getBoundingClientRect();
                return rect.width;
            }

            return 0;
        },
        open: function open(position) {
            var offset = position === 'left' ? this.computedLeftWidth : -this.computedRightWidth;
            this.swipeMove(offset);
            this.resetSwipeStatus();
        },
        close: function close() {
            this.offset = 0;
        },
        resetSwipeStatus: function resetSwipeStatus() {
            this.swiping = false;
            this.opened = true;
        },
        swipeMove: function swipeMove() {
            var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;

            this.offset = range(offset, -this.computedRightWidth, this.computedLeftWidth);

            if (this.offset) {
                this.swiping = true;
            } else {
                this.opened = false;
            }
        },
        swipeLeaveTransition: function swipeLeaveTransition(direction) {
            var offset = this.offset,
                computedLeftWidth = this.computedLeftWidth,
                computedRightWidth = this.computedRightWidth;

            var threshold = this.opened ? 1 - THRESHOLD : THRESHOLD;

            // right
            if (direction === 'right' && -offset > computedRightWidth * threshold && computedRightWidth > 0) {
                this.open('right');
                // left
            } else if (direction === 'left' && offset > computedLeftWidth * threshold && computedLeftWidth > 0) {
                this.open('left');
                // reset
            } else {
                this.swipeMove(0);
            }
        },
        onTouchstart: function onTouchstart(event) {
            if (this.disabled) {
                return;
            }

            this.dragging = true;
            this.startOffset = this.offset;
            this.touchStart(event);
        },
        onMouseStart: function onMouseStart(event) {
            if (this.disabled) {
                return;
            }

            this.dragging = true;
            this.startOffset = this.offset;
            this.mouseStart(event);
        },
        onTouchMove: function onTouchMove(event) {
            if (this.disabled) {
                return;
            }

            this.touchMove(event);

            if (this.direction === 'horizontal') {
                var shouldPrevent = !this.opened || this.deltaX * this.startOffset < 0;

                if (shouldPrevent) {
                    preventDefault(event, this.stopPropagation);
                }

                this.swipeMove(this.deltaX + this.startOffset);
            }
        },
        onMouseMove: function onMouseMove(event) {
            if (this.disabled || !this.dragging) {
                return;
            }

            this.mouseMove(event);

            if (this.direction === 'horizontal') {
                var shouldPrevent = !this.opened || this.deltaX * this.startOffset < 0;

                if (shouldPrevent) {
                    preventDefault(event, this.stopPropagation);
                }

                this.swipeMove(this.deltaX + this.startOffset);
                this.mouseSign = true;
            }
        },
        onTouchEnd: function onTouchEnd() {
            if (this.disabled) {
                return;
            }

            this.dragging = false;
            if (this.swiping) {
                this.swipeLeaveTransition(this.offset > 0 ? 'left' : 'right');
            }
        },
        onMouseEnd: function onMouseEnd() {
            var _this = this;

            if (this.disabled || !this.dragging) {
                return;
            }

            this.dragging = false;
            setTimeout(function () {
                _this.mouseSign = false;
            });

            if (this.swiping) {
                this.swipeLeaveTransition(this.offset > 0 ? 'left' : 'right');
            }
        },
        onClick: function onClick() {
            var position = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'outside';

            if (this.mouseSign) {
                return;
            }

            this.$emit('click', position);

            if (!this.offset) {
                return;
            }

            if (this.onClose) {
                this.onClose(position, this, { name: this.name });
            } else {
                this.swipeMove(0);
            }
        }
    },

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

        var h = arguments[0];
        var $slots = this.$slots;

        var onClick = function onClick(position, stop) {
            return function (event) {
                if (stop) {
                    event.stopPropagation();
                }
                _this2.onClick(position);
            };
        };

        var wrapperStyle = {
            transform: 'translate3d(' + this.offset + 'px, 0, 0)',
            transitionDuration: this.dragging ? '0s' : '.6s'
        };

        return h(
            'div',
            {
                'class': 'sn-swipe-action',
                on: {
                    'click': onClick(),
                    'touchstart': this.onTouchstart,
                    'mousedown': this.onMouseStart,
                    'touchmove': this.onTouchMove,
                    'mousemove': this.onMouseMove,
                    'touchend': this.onTouchEnd,
                    'mouseup': this.onMouseEnd,
                    'touchcancel': this.onTouchEnd
                }
            },
            [h(
                'div',
                {
                    'class': 'sn-swipe-action-wrapper',
                    style: wrapperStyle,
                    on: {
                        'transitionend': function transitionend() {
                            _this2.swiping = false;
                        }
                    }
                },
                [$slots['left'] && h(
                    'div',
                    {
                        ref: 'left',
                        'class': 'sn-swipe-action-left',
                        on: {
                            'click': onClick('left', true)
                        }
                    },
                    [$slots['left']]
                ), $slots['default'], $slots['right'] && h(
                    'div',
                    {
                        ref: 'right',
                        'class': 'sn-swipe-action-right',
                        on: {
                            'click': onClick('right', true)
                        }
                    },
                    [$slots['right']]
                )]
            )]
        );
    }
};

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

export default SwipeAction;