<!--
    <PxTransition animation="fade up" />
-->

<template>
    <transition @enter="enter" @leave="leave">
        <slot />
    </transition>
</template>

<script>
import gsap from 'gsap';
import { cssUnitFallback, cssUnitScale } from '../utils/cssStr.js';

export default {
    props: {
        animation: { type: [String, Object], default: '' },

        /**
         * The duration of the animation in seconds.
         */
        duration: { type: Number, default: 0.5 },

        /**
         * The easing function to be used for the animation.
         */
        easing: { type: String, default: 'power.out' },

        /**
         * Specifies the hide behavior if none is explicitly defined. Possible values are reverse
         * (default) or continue. Reverse will play the reverse of the show animation and continue
         * will show the natural continuation of the show animation.
         *
         * @values reverse, continue
         */
        autoHide: { type: String, default: 'reverse' },

        /**
         * A string that reprensents the animation to be used when hiding the element. See the
         * documentation for the 'animation' prop for details.
         */
        hideAnimation: { type: [String, Object], default: null },

        /**
         * The duration of the hide animation in seconds. If not specified then the duration of the
         * show animation will be used.
         */
        hideDuration: { type: Number, default: null },

        /**
         * The easing function to be used for the hide animation. If not specified then the easing
         * function of the show animation will be used.
         */
        hideEasing: { type: String, default: null },
    },
    // data() { return { b: 0 }; },f
    computed: {
        transitionName() {
            return `pxtx-${this.name}`;
        },
        showDur() {
            return this.duration;
        },
        showEase() {
            return this.easing;
        },
        hideDur() {
            return this.hideDuration || this.duration;
        },
        hideEase() {
            return this.hideEasing || this.easing;
        },
    },
    // watch: {},
    // mounted() {},
    methods: {
        keywordsToParameters(keywords, direction, reverse) {
            const words = (keywords || '').split(/[, ]+/).map(s => s.trim());
            const fr = { x: 0, y: 0, scale: 1 };
            const to = { x: 0, y: 0, scale: 1 };
            const isHide = direction == 'hide';
            const isShow = !isHide;

            if (words && words.length) {
                // fade - animates opacity: 0 -> 1 / 1 -> 0
                if (!words.includes('nofade')) {
                    fr['opacity'] = isShow ? 0 : 1;
                    to['opacity'] = isShow ? 1 : 0;
                }

                let scale = 1;
                let value = 0.33;

                scale = words.includes('xl') ? 2 : scale;
                scale = words.includes('lg') ? 1.5 : scale;
                scale = words.includes('sm') ? 0.5 : scale;
                scale = words.includes('xs') ? 0.25 : scale;

                words.forEach(word => {
                    value = 0.33 * scale;

                    if (word.indexOf(':') > -1) {
                        let [w, v] = word.split(':');
                        word = w;
                        value = v;
                    }

                    switch (word) {
                        case 'up':
                            value = cssUnitFallback(value, '%');
                            fr['y'] = isShow ? value : 0;
                            to['y'] = isShow ? 0 : cssUnitScale(value, -1);
                            break;

                        case 'down':
                            value = cssUnitFallback(value, '%');
                            fr['y'] = isShow ? cssUnitScale(value, -1) : 0;
                            to['y'] = isShow ? 0 : value;
                            break;

                        case 'left':
                            value = cssUnitFallback(value, '%');
                            fr['x'] = isShow ? value : 0;
                            to['x'] = isShow ? 0 : cssUnitScale(value, -1);
                            break;

                        case 'right':
                            value = cssUnitFallback(value, '%');
                            fr['x'] = isShow ? cssUnitScale(value, -1) : 0;
                            to['x'] = isShow ? 0 : value;
                            break;

                        case 'zoomin':
                            fr['scale'] = isShow ? 1 - value : 1;
                            to['scale'] = isShow ? 1 : 1 + value;
                            break;

                        case 'zoomout':
                            fr['scale'] = isShow ? 1 + value : 1;
                            to['scale'] = isShow ? 1 : 1 + value;
                            break;

                        default:
                            break;
                    }
                });
            }

            if (reverse) {
                return {
                    from: to,
                    to: fr,
                };
            }
            return {
                from: fr,
                to: to,
            };
        },
        enter(element, done) {
            const params = this.keywordsToParameters(this.animation, 'show');
            if (params) {
                gsap.fromTo(element, params.from, {
                    ...params.to,
                    duration: this.showDur,
                    ease: this.showEase,
                    onComplete: done,
                });
            }
        },
        leave(element, done) {
            let params;

            if (this.hideAnimation) {
                params = this.keywordsToParameters(this.hideAnimation, 'hide');
            } else {
                if (this.autoHide == 'reverse') {
                    params = this.keywordsToParameters(this.animation, 'show', true);
                } else {
                    params = this.keywordsToParameters(this.animation, 'hide');
                }
            }

            if (params) {
                gsap.to(element, {
                    ...params.to,
                    duration: this.hideDur,
                    ease: this.hideEase,
                    onComplete: done,
                });
            }
        },
    },
};
</script>
