<!--
    Describe this component...
-->
<template>
    <div :class="bem({ active: active })">
        <slot />
    </div>
</template>

<script>
import gsap from 'gsap';

export default {
    name: 'px-slides-transition',
    // components: { Component },
    // mixins: [ Mixin ],

    props: {
        active: { type: Boolean, default: true },

        // selector used to find children of the element that should slide during the transition
        dragSelector: { type: String, default: '[data-drag]' },

        // selector used to find drag elements in the dom that should animate in a reverse direction in vertical transitions
        dragReverseSelector: { type: String, default: '[data-drag-reverse]' },

        // if true, slide the parent element if no slideSelect children are found (false will result just fading)
        dragElementFallback: { type: Boolean, default: true },

        // 1 moves the content to the left/up, -1 moves to the right/down
        direction: { type: Number, default: 1 },

        // vertical or horizontal
        orientation: { type: String, default: 'horizontal' },

        disableAnimations: { type: Boolean, default: false },

        // TODO rtlAdjust: {type: Boolean, default: false }

        // if null, use --px-slide-transition-duration variable
        duration: { type: Number, default: null },

        ease: { type: String, default: 'power3.out' },

        // if null, use --px-slide-transition-slide-amount variable
        slideAmount: { default: '40vw' },
    },

    data() {
        return { initialized: false };
    },
    computed: {
        calcDuration() {
            if (this.disableAnimations || !this.initialized) {
                return 0;
            }

            if (this.duration !== null) {
                return this.duration;
            }

            const duration = getComputedStyle(this.$el).getPropertyValue(
                '--px-slide-transition-duration',
            );

            return parseFloat(duration);
        },

        calcSlideAmount() {
            if (this.slideAmount !== null) {
                return this.slideAmount;
            }

            const slideAmount = getComputedStyle(this.$el).getPropertyValue(
                '--px-slide-transition-slide-amount',
            );

            return slideAmount;
        },
        tweenShared() {
            return {
                duration: this.calcDuration,
                ease: this.ease,
            };
        },
    },
    watch: {
        active(isActive, wasActive) {
            this.updateActive(isActive, wasActive);
        },
    },
    mounted() {
        this.updateActive(this.active, false);
        setTimeout(() => {
            this.initialized = true;
        }, 0);
    },
    methods: {
        updateActive(isActive, wasActive) {
            if (isActive && !wasActive) {
                this.enter(this.$el);
            }

            if (!isActive && wasActive) {
                this.leave(this.$el);
            }
        },
        directionAmount(direction, addEquals = false) {
            let dir;
            if (addEquals) {
                dir = direction < 0 ? '-=' : '+=';
            } else {
                dir = direction < 0 ? '-' : '';
            }

            return dir + this.calcSlideAmount;
        },
        slideElements(element) {
            if (!element) {
                return [];
            }
            return element.querySelectorAll(this.dragSelector);
        },

        slideElementsReverse(element) {
            if (!element || !this.orientation == 'vertical') {
                return [];
            }
            return element.querySelectorAll(this.dragReverseSelector);
        },

        enter(element) {
            const slideElements = this.slideElements(element);

            if (slideElements?.length) {
                const from = {};
                const to = {
                    ...this.tweenShared,
                };

                if (this.orientation === 'vertical') {
                    from.y = this.directionAmount(this.direction * -1);
                    to.y = 0;
                } else {
                    from.x = this.directionAmount(this.direction * -1);
                    to.x = 0;
                }

                gsap.fromTo(slideElements, from, to);
            }

            if (this.orientation === 'vertical') {
                const slideElementsReverse = this.slideElementsReverse(element);
                if (slideElementsReverse?.length) {
                    gsap.fromTo(
                        slideElementsReverse,
                        { y: this.directionAmount(this.direction) },
                        { y: 0, ...this.tweenShared },
                    );
                }
            }

            // fade
            gsap.to(element, {
                opacity: 1,
                duration: this.calcDuration,
                ease: this.ease,
                onStart: () => {
                    this.$emit('before-enter');
                },
                onComplete: () => {
                    this.$emit('after-enter');
                },
                onUpdateParams: [this],
                onUpdate: function (self) {
                    self.$emit('progress', {
                        active: self.active,
                        progress: this.progress(),
                        direction: 'enter',
                    });
                    self.$emit('enter-progress', {
                        active: self.active,
                        progress: this.progress(),
                    });
                },
            });
        },
        leave(element) {
            const slideElements = this.slideElements(element);

            const to = {
                ...this.tweenShared,
            };

            if (this.orientation === 'vertical') {
                to.y = this.directionAmount(this.direction, true);
            } else {
                to.x = this.directionAmount(this.direction, true);
            }

            if (slideElements?.length) {
                gsap.to(slideElements, to);
            }

            if (this.orientation === 'vertical') {
                const slideElementsReverse = this.slideElementsReverse(element);

                if (slideElementsReverse?.length) {
                    const slideElementsReverse = this.slideElementsReverse(element);

                    const toReverse = {
                        ...this.tweenShared,
                        y: this.directionAmount(this.direction * -1, true),
                    };

                    gsap.to(slideElementsReverse, toReverse);
                }
            }

            gsap.to(element, {
                opacity: 0,
                duration: this.calcDuration,
                ease: this.ease,
                onStart: () => {
                    this.$emit('before-leave');
                },
                onComplete: () => {
                    this.$emit('after-leave');
                },
                onUpdateParams: [this],
                onUpdate: function (self) {
                    self.$emit('progress', {
                        active: self.active,
                        progress: this.progress(),
                        direction: 'leave',
                    });
                    self.$emit('leave-progress', {
                        active: self.active,
                        progress: this.progress(),
                    });
                },
            });
        },
    },
};
</script>

<style lang="scss">
@use '../styles/px.scss' as *;

@at-root {
    :root {
        --px-slide-transition-duration: 1s;
        --px-slide-transition-slide-amount: 40vw;
    }
}

.px-slides-transition {
    opacity: 0;
    width: 100%;
    height: 100%;
}
</style>
