<!--
    #VUE3 Todo
-->
<template>
    <component v-bind:is="tag" :style="{ minHeight: groupHeight + 'px' }">
        <component v-bind:is="innerTag" ref="inner" :class="[bem('inner'), innerClass]">
            <slot />
        </component>
    </component>
</template>

<script>
import PxBaseResize from '../bases/PxBaseResize.vue';

class HeightGroup {
    constructor(name) {
        this.name = name; // only needed for debugging
        this.valid = true;
        this.elements = [];
    }
    syncOnNext() {
        if (this.valid) {
            this.valid = false;
            setTimeout(() => {
                let maxHeight = this.getMaxHeight();
                this.elements.forEach(element => {
                    element.groupHeight = maxHeight;
                });
                this.valid = true;
            }, 100);
        }
    }
    addElement(element) {
        this.elements.push(element);
    }
    removeElement(element) {
        this.elements = this.elements.filter(el => el !== element);
    }
    getMaxHeight() {
        let maxHeight = 0;
        this.elements.forEach(item => {
            maxHeight = Math.max(maxHeight, item.innerHeight);
        });
        return maxHeight;
    }
}

let GroupManager = {
    groups: [],
    getGroup(groupName) {
        let group = this.groups[groupName];
        if (!group) {
            group = new HeightGroup(groupName);
            this.groups[groupName] = group;
        }
        return group;
    },

    addToGroup(element, groupName) {
        this.getGroup(groupName).addElement(element);
        this.syncGroupOnNext(groupName);
    },

    removeFromGroup(element, groupName) {
        this.getGroup(groupName).removeElement(element);
        this.syncGroupOnNext(groupName);
    },

    syncGroupOnNext(groupName) {
        this.getGroup(groupName).syncOnNext();
    },
};

export default {
    name: 'px-sync-height',
    mixins: [PxBaseResize],
    props: {
        tag: { type: String, default: 'div' },
        innerTag: { type: String, default: 'span' },
        group: { type: String, default: '' },
        innerClass: { type: String, default: '' },
    },
    data() {
        return {
            innerHeight: 0,
            groupHeight: 0,
            // note: its important not use GroupManager on the server because it has shared state
            isMounted: false,
        };
    },
    watch: {
        group(newValue, oldValue) {
            if (this.isMounted) {
                if (oldValue) {
                    GroupManager.removeFromGroup(this, oldValue);
                }
                if (newValue) {
                    GroupManager.addToGroup(this, newValue);
                }
            }
        },
    },
    methods: {
        resize() {
            if (this.group && this.isMounted) {
                this.innerHeight = this.$refs.inner.getBoundingClientRect().height;
                GroupManager.syncGroupOnNext(this.group);
            }
        },
    },
    mounted() {
        this.isMounted = true;
        if (this.group) {
            GroupManager.addToGroup(this, this.group);
        } else if (process.env.NODE_ENV === 'development') {
            console.warn(
                '[SyncHeight] Must specify a value for "group" in order to sync height between elements.',
            );
        }
    },
    beforeDestroy() {
        if (this.group && this.isMounted) {
            GroupManager.removeFromGroup(this, this.group);
        }
    },
};
</script>
